All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] dm-crypt: Wipe private IV struct after key invalid flag is set.
@ 2019-07-04 13:10 Milan Broz
  2019-07-04 13:10 ` [PATCH 2/3] dm-crypt: Remove obsolete comment about plumb IV Milan Broz
  2019-07-04 13:10 ` [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector Milan Broz
  0 siblings, 2 replies; 19+ messages in thread
From: Milan Broz @ 2019-07-04 13:10 UTC (permalink / raw)
  To: dm-devel; +Cc: Milan Broz

If a private IV wipe function fails, the code does not set the key
invalid flag. This patch moves code after the flag is set and
prevents the device resume in an inconsistent state.

Also, it allows using of a randomized key in private wipe function
(to be used later patches).

Signed-off-by: Milan Broz <gmazyland@gmail.com>
---
 drivers/md/dm-crypt.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 1b16d34bb785..c6d41a7e89c9 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -2158,6 +2158,14 @@ static int crypt_wipe_key(struct crypt_config *cc)
 
 	clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
 	get_random_bytes(&cc->key, cc->key_size);
+
+	/* Wipe IV private keys */
+	if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) {
+		r = cc->iv_gen_ops->wipe(cc);
+		if (r)
+			return r;
+	}
+
 	kzfree(cc->key_string);
 	cc->key_string = NULL;
 	r = crypt_setkey(cc);
@@ -3050,14 +3058,8 @@ static int crypt_message(struct dm_target *ti, unsigned argc, char **argv,
 				memset(cc->key, 0, cc->key_size * sizeof(u8));
 			return ret;
 		}
-		if (argc == 2 && !strcasecmp(argv[1], "wipe")) {
-			if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) {
-				ret = cc->iv_gen_ops->wipe(cc);
-				if (ret)
-					return ret;
-			}
+		if (argc == 2 && !strcasecmp(argv[1], "wipe"))
 			return crypt_wipe_key(cc);
-		}
 	}
 
 error:
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/3] dm-crypt: Remove obsolete comment about plumb IV.
  2019-07-04 13:10 [PATCH 1/3] dm-crypt: Wipe private IV struct after key invalid flag is set Milan Broz
@ 2019-07-04 13:10 ` Milan Broz
  2019-07-04 13:10 ` [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector Milan Broz
  1 sibling, 0 replies; 19+ messages in thread
From: Milan Broz @ 2019-07-04 13:10 UTC (permalink / raw)
  To: dm-devel; +Cc: Milan Broz

The URL is no longer valid and the comment is obsolete anyway
(the plumb IV was never used).

Signed-off-by: Milan Broz <gmazyland@gmail.com>
---
 drivers/md/dm-crypt.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index c6d41a7e89c9..96ead4492787 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -290,9 +290,6 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
  *       is calculated from initial key, sector number and mixed using CRC32.
  *       Note that this encryption scheme is vulnerable to watermarking attacks
  *       and should be used for old compatible containers access only.
- *
- * plumb: unimplemented, see:
- * http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
  */
 
 static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
  2019-07-04 13:10 [PATCH 1/3] dm-crypt: Wipe private IV struct after key invalid flag is set Milan Broz
  2019-07-04 13:10 ` [PATCH 2/3] dm-crypt: Remove obsolete comment about plumb IV Milan Broz
@ 2019-07-04 13:10 ` Milan Broz
  2019-07-04 13:29     ` Milan Broz
  1 sibling, 1 reply; 19+ messages in thread
From: Milan Broz @ 2019-07-04 13:10 UTC (permalink / raw)
  To: dm-devel; +Cc: Milan Broz

This IV is used in some BitLocker devices with CBC encryption mode.

NOTE: maybe we need to use another crypto API if the bare cipher
      API is going to be deprecated.

Signed-off-by: Milan Broz <gmazyland@gmail.com>
---
 drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 81 insertions(+), 1 deletion(-)

diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 96ead4492787..a5ffa1ac6a28 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -120,6 +120,10 @@ struct iv_tcw_private {
 	u8 *whitening;
 };
 
+struct iv_eboiv_private {
+	struct crypto_cipher *tfm;
+};
+
 /*
  * Crypt: maps a linear range of a block device
  * and encrypts / decrypts at the same time.
@@ -159,6 +163,7 @@ struct crypt_config {
 		struct iv_benbi_private benbi;
 		struct iv_lmk_private lmk;
 		struct iv_tcw_private tcw;
+		struct iv_eboiv_private eboiv;
 	} iv_gen_private;
 	u64 iv_offset;
 	unsigned int iv_size;
@@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
  *       is calculated from initial key, sector number and mixed using CRC32.
  *       Note that this encryption scheme is vulnerable to watermarking attacks
  *       and should be used for old compatible containers access only.
+ *
+ * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
+ *        The IV is encrypted little-endian byte-offset (with the same key
+ *        and cipher as the volume).
  */
 
 static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
@@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
 	return 0;
 }
 
+static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
+{
+	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+
+	crypto_free_cipher(eboiv->tfm);
+	eboiv->tfm = NULL;
+}
+
+static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
+			    const char *opts)
+{
+	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+	struct crypto_cipher *tfm;
+
+	tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
+	if (IS_ERR(tfm)) {
+		ti->error = "Error allocating crypto tfm for EBOIV";
+		return PTR_ERR(tfm);
+	}
+
+	if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
+		ti->error = "Block size of EBOIV cipher does "
+			    "not match IV size of block cipher";
+		crypto_free_cipher(tfm);
+		return -EINVAL;
+	}
+
+	eboiv->tfm = tfm;
+	return 0;
+}
+
+static int crypt_iv_eboiv_init(struct crypt_config *cc)
+{
+	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+	int err;
+
+	err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
+{
+	/* Called after cc->key is set to random key in crypt_wipe() */
+	return crypt_iv_eboiv_init(cc);
+}
+
+static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
+			    struct dm_crypt_request *dmreq)
+{
+	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
+
+	memset(iv, 0, cc->iv_size);
+	*(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
+	crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
+
+	return 0;
+}
+
 static const struct crypt_iv_operations crypt_iv_plain_ops = {
 	.generator = crypt_iv_plain_gen
 };
@@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
 	.generator = crypt_iv_random_gen
 };
 
+static struct crypt_iv_operations crypt_iv_eboiv_ops = {
+	.ctr	   = crypt_iv_eboiv_ctr,
+	.dtr	   = crypt_iv_eboiv_dtr,
+	.init	   = crypt_iv_eboiv_init,
+	.wipe	   = crypt_iv_eboiv_wipe,
+	.generator = crypt_iv_eboiv_gen
+};
+
 /*
  * Integrity extensions
  */
@@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
 		cc->iv_gen_ops = &crypt_iv_benbi_ops;
 	else if (strcmp(ivmode, "null") == 0)
 		cc->iv_gen_ops = &crypt_iv_null_ops;
+	else if (strcmp(ivmode, "eboiv") == 0)
+		cc->iv_gen_ops = &crypt_iv_eboiv_ops;
 	else if (strcmp(ivmode, "lmk") == 0) {
 		cc->iv_gen_ops = &crypt_iv_lmk_ops;
 		/*
@@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
 
 static struct target_type crypt_target = {
 	.name   = "crypt",
-	.version = {1, 18, 1},
+	.version = {1, 19, 0},
 	.module = THIS_MODULE,
 	.ctr    = crypt_ctr,
 	.dtr    = crypt_dtr,
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
  2019-07-04 13:10 ` [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector Milan Broz
@ 2019-07-04 13:29     ` Milan Broz
  0 siblings, 0 replies; 19+ messages in thread
From: Milan Broz @ 2019-07-04 13:29 UTC (permalink / raw)
  To: Herbert Xu; +Cc: dm-devel, Ard Biesheuvel, linux-crypto

Hi Herbert,

I have a question about the crypto_cipher API in dm-crypt:

We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
but I am not sure what API now should be used instead.

See the patch below - all we need is to one block encryption for IV.

This algorithm makes sense only for FDE (old compatible Bitlocker devices),
I really do not want this to be shared in some crypto module...

What API should I use here? Sync skcipher? Is the crypto_cipher API
really a problem in this case?

Thanks,
Milan


On 04/07/2019 15:10, Milan Broz wrote:
> This IV is used in some BitLocker devices with CBC encryption mode.
> 
> NOTE: maybe we need to use another crypto API if the bare cipher
>       API is going to be deprecated.
> 
> Signed-off-by: Milan Broz <gmazyland@gmail.com>
> ---
>  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 81 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> index 96ead4492787..a5ffa1ac6a28 100644
> --- a/drivers/md/dm-crypt.c
> +++ b/drivers/md/dm-crypt.c
> @@ -120,6 +120,10 @@ struct iv_tcw_private {
>  	u8 *whitening;
>  };
>  
> +struct iv_eboiv_private {
> +	struct crypto_cipher *tfm;
> +};
> +
>  /*
>   * Crypt: maps a linear range of a block device
>   * and encrypts / decrypts at the same time.
> @@ -159,6 +163,7 @@ struct crypt_config {
>  		struct iv_benbi_private benbi;
>  		struct iv_lmk_private lmk;
>  		struct iv_tcw_private tcw;
> +		struct iv_eboiv_private eboiv;
>  	} iv_gen_private;
>  	u64 iv_offset;
>  	unsigned int iv_size;
> @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
>   *       is calculated from initial key, sector number and mixed using CRC32.
>   *       Note that this encryption scheme is vulnerable to watermarking attacks
>   *       and should be used for old compatible containers access only.
> + *
> + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
> + *        The IV is encrypted little-endian byte-offset (with the same key
> + *        and cipher as the volume).
>   */
>  
>  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
> @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
>  	return 0;
>  }
>  
> +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
> +{
> +	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> +
> +	crypto_free_cipher(eboiv->tfm);
> +	eboiv->tfm = NULL;
> +}
> +
> +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
> +			    const char *opts)
> +{
> +	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> +	struct crypto_cipher *tfm;
> +
> +	tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
> +	if (IS_ERR(tfm)) {
> +		ti->error = "Error allocating crypto tfm for EBOIV";
> +		return PTR_ERR(tfm);
> +	}
> +
> +	if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
> +		ti->error = "Block size of EBOIV cipher does "
> +			    "not match IV size of block cipher";
> +		crypto_free_cipher(tfm);
> +		return -EINVAL;
> +	}
> +
> +	eboiv->tfm = tfm;
> +	return 0;
> +}
> +
> +static int crypt_iv_eboiv_init(struct crypt_config *cc)
> +{
> +	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> +	int err;
> +
> +	err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
> +{
> +	/* Called after cc->key is set to random key in crypt_wipe() */
> +	return crypt_iv_eboiv_init(cc);
> +}
> +
> +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
> +			    struct dm_crypt_request *dmreq)
> +{
> +	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> +
> +	memset(iv, 0, cc->iv_size);
> +	*(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
> +	crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
> +
> +	return 0;
> +}
> +
>  static const struct crypt_iv_operations crypt_iv_plain_ops = {
>  	.generator = crypt_iv_plain_gen
>  };
> @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
>  	.generator = crypt_iv_random_gen
>  };
>  
> +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
> +	.ctr	   = crypt_iv_eboiv_ctr,
> +	.dtr	   = crypt_iv_eboiv_dtr,
> +	.init	   = crypt_iv_eboiv_init,
> +	.wipe	   = crypt_iv_eboiv_wipe,
> +	.generator = crypt_iv_eboiv_gen
> +};
> +
>  /*
>   * Integrity extensions
>   */
> @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
>  		cc->iv_gen_ops = &crypt_iv_benbi_ops;
>  	else if (strcmp(ivmode, "null") == 0)
>  		cc->iv_gen_ops = &crypt_iv_null_ops;
> +	else if (strcmp(ivmode, "eboiv") == 0)
> +		cc->iv_gen_ops = &crypt_iv_eboiv_ops;
>  	else if (strcmp(ivmode, "lmk") == 0) {
>  		cc->iv_gen_ops = &crypt_iv_lmk_ops;
>  		/*
> @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
>  
>  static struct target_type crypt_target = {
>  	.name   = "crypt",
> -	.version = {1, 18, 1},
> +	.version = {1, 19, 0},
>  	.module = THIS_MODULE,
>  	.ctr    = crypt_ctr,
>  	.dtr    = crypt_dtr,
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
@ 2019-07-04 13:29     ` Milan Broz
  0 siblings, 0 replies; 19+ messages in thread
From: Milan Broz @ 2019-07-04 13:29 UTC (permalink / raw)
  To: Herbert Xu; +Cc: dm-devel, linux-crypto, Ard Biesheuvel

Hi Herbert,

I have a question about the crypto_cipher API in dm-crypt:

We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
but I am not sure what API now should be used instead.

See the patch below - all we need is to one block encryption for IV.

This algorithm makes sense only for FDE (old compatible Bitlocker devices),
I really do not want this to be shared in some crypto module...

What API should I use here? Sync skcipher? Is the crypto_cipher API
really a problem in this case?

Thanks,
Milan


On 04/07/2019 15:10, Milan Broz wrote:
> This IV is used in some BitLocker devices with CBC encryption mode.
> 
> NOTE: maybe we need to use another crypto API if the bare cipher
>       API is going to be deprecated.
> 
> Signed-off-by: Milan Broz <gmazyland@gmail.com>
> ---
>  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 81 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> index 96ead4492787..a5ffa1ac6a28 100644
> --- a/drivers/md/dm-crypt.c
> +++ b/drivers/md/dm-crypt.c
> @@ -120,6 +120,10 @@ struct iv_tcw_private {
>  	u8 *whitening;
>  };
>  
> +struct iv_eboiv_private {
> +	struct crypto_cipher *tfm;
> +};
> +
>  /*
>   * Crypt: maps a linear range of a block device
>   * and encrypts / decrypts at the same time.
> @@ -159,6 +163,7 @@ struct crypt_config {
>  		struct iv_benbi_private benbi;
>  		struct iv_lmk_private lmk;
>  		struct iv_tcw_private tcw;
> +		struct iv_eboiv_private eboiv;
>  	} iv_gen_private;
>  	u64 iv_offset;
>  	unsigned int iv_size;
> @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
>   *       is calculated from initial key, sector number and mixed using CRC32.
>   *       Note that this encryption scheme is vulnerable to watermarking attacks
>   *       and should be used for old compatible containers access only.
> + *
> + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
> + *        The IV is encrypted little-endian byte-offset (with the same key
> + *        and cipher as the volume).
>   */
>  
>  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
> @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
>  	return 0;
>  }
>  
> +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
> +{
> +	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> +
> +	crypto_free_cipher(eboiv->tfm);
> +	eboiv->tfm = NULL;
> +}
> +
> +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
> +			    const char *opts)
> +{
> +	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> +	struct crypto_cipher *tfm;
> +
> +	tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
> +	if (IS_ERR(tfm)) {
> +		ti->error = "Error allocating crypto tfm for EBOIV";
> +		return PTR_ERR(tfm);
> +	}
> +
> +	if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
> +		ti->error = "Block size of EBOIV cipher does "
> +			    "not match IV size of block cipher";
> +		crypto_free_cipher(tfm);
> +		return -EINVAL;
> +	}
> +
> +	eboiv->tfm = tfm;
> +	return 0;
> +}
> +
> +static int crypt_iv_eboiv_init(struct crypt_config *cc)
> +{
> +	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> +	int err;
> +
> +	err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
> +{
> +	/* Called after cc->key is set to random key in crypt_wipe() */
> +	return crypt_iv_eboiv_init(cc);
> +}
> +
> +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
> +			    struct dm_crypt_request *dmreq)
> +{
> +	struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> +
> +	memset(iv, 0, cc->iv_size);
> +	*(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
> +	crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
> +
> +	return 0;
> +}
> +
>  static const struct crypt_iv_operations crypt_iv_plain_ops = {
>  	.generator = crypt_iv_plain_gen
>  };
> @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
>  	.generator = crypt_iv_random_gen
>  };
>  
> +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
> +	.ctr	   = crypt_iv_eboiv_ctr,
> +	.dtr	   = crypt_iv_eboiv_dtr,
> +	.init	   = crypt_iv_eboiv_init,
> +	.wipe	   = crypt_iv_eboiv_wipe,
> +	.generator = crypt_iv_eboiv_gen
> +};
> +
>  /*
>   * Integrity extensions
>   */
> @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
>  		cc->iv_gen_ops = &crypt_iv_benbi_ops;
>  	else if (strcmp(ivmode, "null") == 0)
>  		cc->iv_gen_ops = &crypt_iv_null_ops;
> +	else if (strcmp(ivmode, "eboiv") == 0)
> +		cc->iv_gen_ops = &crypt_iv_eboiv_ops;
>  	else if (strcmp(ivmode, "lmk") == 0) {
>  		cc->iv_gen_ops = &crypt_iv_lmk_ops;
>  		/*
> @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
>  
>  static struct target_type crypt_target = {
>  	.name   = "crypt",
> -	.version = {1, 18, 1},
> +	.version = {1, 19, 0},
>  	.module = THIS_MODULE,
>  	.ctr    = crypt_ctr,
>  	.dtr    = crypt_dtr,
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
  2019-07-04 13:29     ` Milan Broz
@ 2019-07-04 14:28       ` Ard Biesheuvel
  -1 siblings, 0 replies; 19+ messages in thread
From: Ard Biesheuvel @ 2019-07-04 14:28 UTC (permalink / raw)
  To: Milan Broz, Eric Biggers
  Cc: Herbert Xu, device-mapper development,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

(+ Eric)

On Thu, 4 Jul 2019 at 15:29, Milan Broz <gmazyland@gmail.com> wrote:
>
> Hi Herbert,
>
> I have a question about the crypto_cipher API in dm-crypt:
>
> We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
> but I am not sure what API now should be used instead.
>

Not precisely - what I would like to do is to make the cipher part of
the internal crypto API. The reason is that there are too many
occurrences where non-trivial chaining modes have been cobbled
together from the cipher API.

> See the patch below - all we need is to one block encryption for IV.
>
> This algorithm makes sense only for FDE (old compatible Bitlocker devices),
> I really do not want this to be shared in some crypto module...
>
> What API should I use here? Sync skcipher? Is the crypto_cipher API
> really a problem in this case?
>

Are arbitrary ciphers supported? Or are you only interested in AES? In
the former case, I'd suggest the sync skcipher API to instantiate
"ecb(%s)", otherwise, use the upcoming AES library interface.

> On 04/07/2019 15:10, Milan Broz wrote:
> > This IV is used in some BitLocker devices with CBC encryption mode.
> >
> > NOTE: maybe we need to use another crypto API if the bare cipher
> >       API is going to be deprecated.
> >
> > Signed-off-by: Milan Broz <gmazyland@gmail.com>
> > ---
> >  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 81 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> > index 96ead4492787..a5ffa1ac6a28 100644
> > --- a/drivers/md/dm-crypt.c
> > +++ b/drivers/md/dm-crypt.c
> > @@ -120,6 +120,10 @@ struct iv_tcw_private {
> >       u8 *whitening;
> >  };
> >
> > +struct iv_eboiv_private {
> > +     struct crypto_cipher *tfm;
> > +};
> > +
> >  /*
> >   * Crypt: maps a linear range of a block device
> >   * and encrypts / decrypts at the same time.
> > @@ -159,6 +163,7 @@ struct crypt_config {
> >               struct iv_benbi_private benbi;
> >               struct iv_lmk_private lmk;
> >               struct iv_tcw_private tcw;
> > +             struct iv_eboiv_private eboiv;
> >       } iv_gen_private;
> >       u64 iv_offset;
> >       unsigned int iv_size;
> > @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
> >   *       is calculated from initial key, sector number and mixed using CRC32.
> >   *       Note that this encryption scheme is vulnerable to watermarking attacks
> >   *       and should be used for old compatible containers access only.
> > + *
> > + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
> > + *        The IV is encrypted little-endian byte-offset (with the same key
> > + *        and cipher as the volume).
> >   */
> >
> >  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
> > @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
> >       return 0;
> >  }
> >
> > +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
> > +{
> > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > +
> > +     crypto_free_cipher(eboiv->tfm);
> > +     eboiv->tfm = NULL;
> > +}
> > +
> > +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
> > +                         const char *opts)
> > +{
> > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > +     struct crypto_cipher *tfm;
> > +
> > +     tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
> > +     if (IS_ERR(tfm)) {
> > +             ti->error = "Error allocating crypto tfm for EBOIV";
> > +             return PTR_ERR(tfm);
> > +     }
> > +
> > +     if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
> > +             ti->error = "Block size of EBOIV cipher does "
> > +                         "not match IV size of block cipher";
> > +             crypto_free_cipher(tfm);
> > +             return -EINVAL;
> > +     }
> > +
> > +     eboiv->tfm = tfm;
> > +     return 0;
> > +}
> > +
> > +static int crypt_iv_eboiv_init(struct crypt_config *cc)
> > +{
> > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > +     int err;
> > +
> > +     err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
> > +     if (err)
> > +             return err;
> > +
> > +     return 0;
> > +}
> > +
> > +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
> > +{
> > +     /* Called after cc->key is set to random key in crypt_wipe() */
> > +     return crypt_iv_eboiv_init(cc);
> > +}
> > +
> > +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
> > +                         struct dm_crypt_request *dmreq)
> > +{
> > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > +
> > +     memset(iv, 0, cc->iv_size);
> > +     *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
> > +     crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
> > +
> > +     return 0;
> > +}
> > +
> >  static const struct crypt_iv_operations crypt_iv_plain_ops = {
> >       .generator = crypt_iv_plain_gen
> >  };
> > @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
> >       .generator = crypt_iv_random_gen
> >  };
> >
> > +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
> > +     .ctr       = crypt_iv_eboiv_ctr,
> > +     .dtr       = crypt_iv_eboiv_dtr,
> > +     .init      = crypt_iv_eboiv_init,
> > +     .wipe      = crypt_iv_eboiv_wipe,
> > +     .generator = crypt_iv_eboiv_gen
> > +};
> > +
> >  /*
> >   * Integrity extensions
> >   */
> > @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
> >               cc->iv_gen_ops = &crypt_iv_benbi_ops;
> >       else if (strcmp(ivmode, "null") == 0)
> >               cc->iv_gen_ops = &crypt_iv_null_ops;
> > +     else if (strcmp(ivmode, "eboiv") == 0)
> > +             cc->iv_gen_ops = &crypt_iv_eboiv_ops;
> >       else if (strcmp(ivmode, "lmk") == 0) {
> >               cc->iv_gen_ops = &crypt_iv_lmk_ops;
> >               /*
> > @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
> >
> >  static struct target_type crypt_target = {
> >       .name   = "crypt",
> > -     .version = {1, 18, 1},
> > +     .version = {1, 19, 0},
> >       .module = THIS_MODULE,
> >       .ctr    = crypt_ctr,
> >       .dtr    = crypt_dtr,
> >

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
@ 2019-07-04 14:28       ` Ard Biesheuvel
  0 siblings, 0 replies; 19+ messages in thread
From: Ard Biesheuvel @ 2019-07-04 14:28 UTC (permalink / raw)
  To: Milan Broz, Eric Biggers
  Cc: device-mapper development, Herbert Xu,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

(+ Eric)

On Thu, 4 Jul 2019 at 15:29, Milan Broz <gmazyland@gmail.com> wrote:
>
> Hi Herbert,
>
> I have a question about the crypto_cipher API in dm-crypt:
>
> We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
> but I am not sure what API now should be used instead.
>

Not precisely - what I would like to do is to make the cipher part of
the internal crypto API. The reason is that there are too many
occurrences where non-trivial chaining modes have been cobbled
together from the cipher API.

> See the patch below - all we need is to one block encryption for IV.
>
> This algorithm makes sense only for FDE (old compatible Bitlocker devices),
> I really do not want this to be shared in some crypto module...
>
> What API should I use here? Sync skcipher? Is the crypto_cipher API
> really a problem in this case?
>

Are arbitrary ciphers supported? Or are you only interested in AES? In
the former case, I'd suggest the sync skcipher API to instantiate
"ecb(%s)", otherwise, use the upcoming AES library interface.

> On 04/07/2019 15:10, Milan Broz wrote:
> > This IV is used in some BitLocker devices with CBC encryption mode.
> >
> > NOTE: maybe we need to use another crypto API if the bare cipher
> >       API is going to be deprecated.
> >
> > Signed-off-by: Milan Broz <gmazyland@gmail.com>
> > ---
> >  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 81 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> > index 96ead4492787..a5ffa1ac6a28 100644
> > --- a/drivers/md/dm-crypt.c
> > +++ b/drivers/md/dm-crypt.c
> > @@ -120,6 +120,10 @@ struct iv_tcw_private {
> >       u8 *whitening;
> >  };
> >
> > +struct iv_eboiv_private {
> > +     struct crypto_cipher *tfm;
> > +};
> > +
> >  /*
> >   * Crypt: maps a linear range of a block device
> >   * and encrypts / decrypts at the same time.
> > @@ -159,6 +163,7 @@ struct crypt_config {
> >               struct iv_benbi_private benbi;
> >               struct iv_lmk_private lmk;
> >               struct iv_tcw_private tcw;
> > +             struct iv_eboiv_private eboiv;
> >       } iv_gen_private;
> >       u64 iv_offset;
> >       unsigned int iv_size;
> > @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
> >   *       is calculated from initial key, sector number and mixed using CRC32.
> >   *       Note that this encryption scheme is vulnerable to watermarking attacks
> >   *       and should be used for old compatible containers access only.
> > + *
> > + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
> > + *        The IV is encrypted little-endian byte-offset (with the same key
> > + *        and cipher as the volume).
> >   */
> >
> >  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
> > @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
> >       return 0;
> >  }
> >
> > +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
> > +{
> > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > +
> > +     crypto_free_cipher(eboiv->tfm);
> > +     eboiv->tfm = NULL;
> > +}
> > +
> > +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
> > +                         const char *opts)
> > +{
> > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > +     struct crypto_cipher *tfm;
> > +
> > +     tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
> > +     if (IS_ERR(tfm)) {
> > +             ti->error = "Error allocating crypto tfm for EBOIV";
> > +             return PTR_ERR(tfm);
> > +     }
> > +
> > +     if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
> > +             ti->error = "Block size of EBOIV cipher does "
> > +                         "not match IV size of block cipher";
> > +             crypto_free_cipher(tfm);
> > +             return -EINVAL;
> > +     }
> > +
> > +     eboiv->tfm = tfm;
> > +     return 0;
> > +}
> > +
> > +static int crypt_iv_eboiv_init(struct crypt_config *cc)
> > +{
> > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > +     int err;
> > +
> > +     err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
> > +     if (err)
> > +             return err;
> > +
> > +     return 0;
> > +}
> > +
> > +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
> > +{
> > +     /* Called after cc->key is set to random key in crypt_wipe() */
> > +     return crypt_iv_eboiv_init(cc);
> > +}
> > +
> > +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
> > +                         struct dm_crypt_request *dmreq)
> > +{
> > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > +
> > +     memset(iv, 0, cc->iv_size);
> > +     *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
> > +     crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
> > +
> > +     return 0;
> > +}
> > +
> >  static const struct crypt_iv_operations crypt_iv_plain_ops = {
> >       .generator = crypt_iv_plain_gen
> >  };
> > @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
> >       .generator = crypt_iv_random_gen
> >  };
> >
> > +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
> > +     .ctr       = crypt_iv_eboiv_ctr,
> > +     .dtr       = crypt_iv_eboiv_dtr,
> > +     .init      = crypt_iv_eboiv_init,
> > +     .wipe      = crypt_iv_eboiv_wipe,
> > +     .generator = crypt_iv_eboiv_gen
> > +};
> > +
> >  /*
> >   * Integrity extensions
> >   */
> > @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
> >               cc->iv_gen_ops = &crypt_iv_benbi_ops;
> >       else if (strcmp(ivmode, "null") == 0)
> >               cc->iv_gen_ops = &crypt_iv_null_ops;
> > +     else if (strcmp(ivmode, "eboiv") == 0)
> > +             cc->iv_gen_ops = &crypt_iv_eboiv_ops;
> >       else if (strcmp(ivmode, "lmk") == 0) {
> >               cc->iv_gen_ops = &crypt_iv_lmk_ops;
> >               /*
> > @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
> >
> >  static struct target_type crypt_target = {
> >       .name   = "crypt",
> > -     .version = {1, 18, 1},
> > +     .version = {1, 19, 0},
> >       .module = THIS_MODULE,
> >       .ctr    = crypt_ctr,
> >       .dtr    = crypt_dtr,
> >

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
  2019-07-04 14:28       ` Ard Biesheuvel
@ 2019-07-04 14:30         ` Ard Biesheuvel
  -1 siblings, 0 replies; 19+ messages in thread
From: Ard Biesheuvel @ 2019-07-04 14:30 UTC (permalink / raw)
  To: Milan Broz, Eric Biggers
  Cc: Herbert Xu, device-mapper development,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

On Thu, 4 Jul 2019 at 16:28, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>
> (+ Eric)
>
> On Thu, 4 Jul 2019 at 15:29, Milan Broz <gmazyland@gmail.com> wrote:
> >
> > Hi Herbert,
> >
> > I have a question about the crypto_cipher API in dm-crypt:
> >
> > We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
> > but I am not sure what API now should be used instead.
> >
>
> Not precisely - what I would like to do is to make the cipher part of
> the internal crypto API. The reason is that there are too many
> occurrences where non-trivial chaining modes have been cobbled
> together from the cipher API.
>
> > See the patch below - all we need is to one block encryption for IV.
> >
> > This algorithm makes sense only for FDE (old compatible Bitlocker devices),
> > I really do not want this to be shared in some crypto module...
> >
> > What API should I use here? Sync skcipher? Is the crypto_cipher API
> > really a problem in this case?
> >
>
> Are arbitrary ciphers supported? Or are you only interested in AES? In
> the former case, I'd suggest the sync skcipher API to instantiate
> "ecb(%s)", otherwise, use the upcoming AES library interface.
>

Actually, if CBC is the only supported mode, you could also use the
skcipher itself to encrypt a single block of input (just encrypt the
IV using CBC but with an IV of all zeroes)


> > On 04/07/2019 15:10, Milan Broz wrote:
> > > This IV is used in some BitLocker devices with CBC encryption mode.
> > >
> > > NOTE: maybe we need to use another crypto API if the bare cipher
> > >       API is going to be deprecated.
> > >
> > > Signed-off-by: Milan Broz <gmazyland@gmail.com>
> > > ---
> > >  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
> > >  1 file changed, 81 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> > > index 96ead4492787..a5ffa1ac6a28 100644
> > > --- a/drivers/md/dm-crypt.c
> > > +++ b/drivers/md/dm-crypt.c
> > > @@ -120,6 +120,10 @@ struct iv_tcw_private {
> > >       u8 *whitening;
> > >  };
> > >
> > > +struct iv_eboiv_private {
> > > +     struct crypto_cipher *tfm;
> > > +};
> > > +
> > >  /*
> > >   * Crypt: maps a linear range of a block device
> > >   * and encrypts / decrypts at the same time.
> > > @@ -159,6 +163,7 @@ struct crypt_config {
> > >               struct iv_benbi_private benbi;
> > >               struct iv_lmk_private lmk;
> > >               struct iv_tcw_private tcw;
> > > +             struct iv_eboiv_private eboiv;
> > >       } iv_gen_private;
> > >       u64 iv_offset;
> > >       unsigned int iv_size;
> > > @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
> > >   *       is calculated from initial key, sector number and mixed using CRC32.
> > >   *       Note that this encryption scheme is vulnerable to watermarking attacks
> > >   *       and should be used for old compatible containers access only.
> > > + *
> > > + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
> > > + *        The IV is encrypted little-endian byte-offset (with the same key
> > > + *        and cipher as the volume).
> > >   */
> > >
> > >  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
> > > @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
> > >       return 0;
> > >  }
> > >
> > > +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
> > > +{
> > > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > > +
> > > +     crypto_free_cipher(eboiv->tfm);
> > > +     eboiv->tfm = NULL;
> > > +}
> > > +
> > > +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
> > > +                         const char *opts)
> > > +{
> > > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > > +     struct crypto_cipher *tfm;
> > > +
> > > +     tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
> > > +     if (IS_ERR(tfm)) {
> > > +             ti->error = "Error allocating crypto tfm for EBOIV";
> > > +             return PTR_ERR(tfm);
> > > +     }
> > > +
> > > +     if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
> > > +             ti->error = "Block size of EBOIV cipher does "
> > > +                         "not match IV size of block cipher";
> > > +             crypto_free_cipher(tfm);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     eboiv->tfm = tfm;
> > > +     return 0;
> > > +}
> > > +
> > > +static int crypt_iv_eboiv_init(struct crypt_config *cc)
> > > +{
> > > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > > +     int err;
> > > +
> > > +     err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
> > > +     if (err)
> > > +             return err;
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
> > > +{
> > > +     /* Called after cc->key is set to random key in crypt_wipe() */
> > > +     return crypt_iv_eboiv_init(cc);
> > > +}
> > > +
> > > +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
> > > +                         struct dm_crypt_request *dmreq)
> > > +{
> > > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > > +
> > > +     memset(iv, 0, cc->iv_size);
> > > +     *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
> > > +     crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > >  static const struct crypt_iv_operations crypt_iv_plain_ops = {
> > >       .generator = crypt_iv_plain_gen
> > >  };
> > > @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
> > >       .generator = crypt_iv_random_gen
> > >  };
> > >
> > > +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
> > > +     .ctr       = crypt_iv_eboiv_ctr,
> > > +     .dtr       = crypt_iv_eboiv_dtr,
> > > +     .init      = crypt_iv_eboiv_init,
> > > +     .wipe      = crypt_iv_eboiv_wipe,
> > > +     .generator = crypt_iv_eboiv_gen
> > > +};
> > > +
> > >  /*
> > >   * Integrity extensions
> > >   */
> > > @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
> > >               cc->iv_gen_ops = &crypt_iv_benbi_ops;
> > >       else if (strcmp(ivmode, "null") == 0)
> > >               cc->iv_gen_ops = &crypt_iv_null_ops;
> > > +     else if (strcmp(ivmode, "eboiv") == 0)
> > > +             cc->iv_gen_ops = &crypt_iv_eboiv_ops;
> > >       else if (strcmp(ivmode, "lmk") == 0) {
> > >               cc->iv_gen_ops = &crypt_iv_lmk_ops;
> > >               /*
> > > @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
> > >
> > >  static struct target_type crypt_target = {
> > >       .name   = "crypt",
> > > -     .version = {1, 18, 1},
> > > +     .version = {1, 19, 0},
> > >       .module = THIS_MODULE,
> > >       .ctr    = crypt_ctr,
> > >       .dtr    = crypt_dtr,
> > >

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
@ 2019-07-04 14:30         ` Ard Biesheuvel
  0 siblings, 0 replies; 19+ messages in thread
From: Ard Biesheuvel @ 2019-07-04 14:30 UTC (permalink / raw)
  To: Milan Broz, Eric Biggers
  Cc: device-mapper development, Herbert Xu,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

On Thu, 4 Jul 2019 at 16:28, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>
> (+ Eric)
>
> On Thu, 4 Jul 2019 at 15:29, Milan Broz <gmazyland@gmail.com> wrote:
> >
> > Hi Herbert,
> >
> > I have a question about the crypto_cipher API in dm-crypt:
> >
> > We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
> > but I am not sure what API now should be used instead.
> >
>
> Not precisely - what I would like to do is to make the cipher part of
> the internal crypto API. The reason is that there are too many
> occurrences where non-trivial chaining modes have been cobbled
> together from the cipher API.
>
> > See the patch below - all we need is to one block encryption for IV.
> >
> > This algorithm makes sense only for FDE (old compatible Bitlocker devices),
> > I really do not want this to be shared in some crypto module...
> >
> > What API should I use here? Sync skcipher? Is the crypto_cipher API
> > really a problem in this case?
> >
>
> Are arbitrary ciphers supported? Or are you only interested in AES? In
> the former case, I'd suggest the sync skcipher API to instantiate
> "ecb(%s)", otherwise, use the upcoming AES library interface.
>

Actually, if CBC is the only supported mode, you could also use the
skcipher itself to encrypt a single block of input (just encrypt the
IV using CBC but with an IV of all zeroes)


> > On 04/07/2019 15:10, Milan Broz wrote:
> > > This IV is used in some BitLocker devices with CBC encryption mode.
> > >
> > > NOTE: maybe we need to use another crypto API if the bare cipher
> > >       API is going to be deprecated.
> > >
> > > Signed-off-by: Milan Broz <gmazyland@gmail.com>
> > > ---
> > >  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
> > >  1 file changed, 81 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> > > index 96ead4492787..a5ffa1ac6a28 100644
> > > --- a/drivers/md/dm-crypt.c
> > > +++ b/drivers/md/dm-crypt.c
> > > @@ -120,6 +120,10 @@ struct iv_tcw_private {
> > >       u8 *whitening;
> > >  };
> > >
> > > +struct iv_eboiv_private {
> > > +     struct crypto_cipher *tfm;
> > > +};
> > > +
> > >  /*
> > >   * Crypt: maps a linear range of a block device
> > >   * and encrypts / decrypts at the same time.
> > > @@ -159,6 +163,7 @@ struct crypt_config {
> > >               struct iv_benbi_private benbi;
> > >               struct iv_lmk_private lmk;
> > >               struct iv_tcw_private tcw;
> > > +             struct iv_eboiv_private eboiv;
> > >       } iv_gen_private;
> > >       u64 iv_offset;
> > >       unsigned int iv_size;
> > > @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
> > >   *       is calculated from initial key, sector number and mixed using CRC32.
> > >   *       Note that this encryption scheme is vulnerable to watermarking attacks
> > >   *       and should be used for old compatible containers access only.
> > > + *
> > > + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
> > > + *        The IV is encrypted little-endian byte-offset (with the same key
> > > + *        and cipher as the volume).
> > >   */
> > >
> > >  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
> > > @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
> > >       return 0;
> > >  }
> > >
> > > +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
> > > +{
> > > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > > +
> > > +     crypto_free_cipher(eboiv->tfm);
> > > +     eboiv->tfm = NULL;
> > > +}
> > > +
> > > +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
> > > +                         const char *opts)
> > > +{
> > > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > > +     struct crypto_cipher *tfm;
> > > +
> > > +     tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
> > > +     if (IS_ERR(tfm)) {
> > > +             ti->error = "Error allocating crypto tfm for EBOIV";
> > > +             return PTR_ERR(tfm);
> > > +     }
> > > +
> > > +     if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
> > > +             ti->error = "Block size of EBOIV cipher does "
> > > +                         "not match IV size of block cipher";
> > > +             crypto_free_cipher(tfm);
> > > +             return -EINVAL;
> > > +     }
> > > +
> > > +     eboiv->tfm = tfm;
> > > +     return 0;
> > > +}
> > > +
> > > +static int crypt_iv_eboiv_init(struct crypt_config *cc)
> > > +{
> > > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > > +     int err;
> > > +
> > > +     err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
> > > +     if (err)
> > > +             return err;
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
> > > +{
> > > +     /* Called after cc->key is set to random key in crypt_wipe() */
> > > +     return crypt_iv_eboiv_init(cc);
> > > +}
> > > +
> > > +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
> > > +                         struct dm_crypt_request *dmreq)
> > > +{
> > > +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> > > +
> > > +     memset(iv, 0, cc->iv_size);
> > > +     *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
> > > +     crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > >  static const struct crypt_iv_operations crypt_iv_plain_ops = {
> > >       .generator = crypt_iv_plain_gen
> > >  };
> > > @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
> > >       .generator = crypt_iv_random_gen
> > >  };
> > >
> > > +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
> > > +     .ctr       = crypt_iv_eboiv_ctr,
> > > +     .dtr       = crypt_iv_eboiv_dtr,
> > > +     .init      = crypt_iv_eboiv_init,
> > > +     .wipe      = crypt_iv_eboiv_wipe,
> > > +     .generator = crypt_iv_eboiv_gen
> > > +};
> > > +
> > >  /*
> > >   * Integrity extensions
> > >   */
> > > @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
> > >               cc->iv_gen_ops = &crypt_iv_benbi_ops;
> > >       else if (strcmp(ivmode, "null") == 0)
> > >               cc->iv_gen_ops = &crypt_iv_null_ops;
> > > +     else if (strcmp(ivmode, "eboiv") == 0)
> > > +             cc->iv_gen_ops = &crypt_iv_eboiv_ops;
> > >       else if (strcmp(ivmode, "lmk") == 0) {
> > >               cc->iv_gen_ops = &crypt_iv_lmk_ops;
> > >               /*
> > > @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
> > >
> > >  static struct target_type crypt_target = {
> > >       .name   = "crypt",
> > > -     .version = {1, 18, 1},
> > > +     .version = {1, 19, 0},
> > >       .module = THIS_MODULE,
> > >       .ctr    = crypt_ctr,
> > >       .dtr    = crypt_dtr,
> > >

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
  2019-07-04 14:30         ` Ard Biesheuvel
@ 2019-07-04 17:45           ` Milan Broz
  -1 siblings, 0 replies; 19+ messages in thread
From: Milan Broz @ 2019-07-04 17:45 UTC (permalink / raw)
  To: Ard Biesheuvel, Eric Biggers
  Cc: Herbert Xu, device-mapper development,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

On 04/07/2019 16:30, Ard Biesheuvel wrote:
> On Thu, 4 Jul 2019 at 16:28, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>>
>> (+ Eric)
>>
>> On Thu, 4 Jul 2019 at 15:29, Milan Broz <gmazyland@gmail.com> wrote:
>>>
>>> Hi Herbert,
>>>
>>> I have a question about the crypto_cipher API in dm-crypt:
>>>
>>> We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
>>> but I am not sure what API now should be used instead.
>>>
>>
>> Not precisely - what I would like to do is to make the cipher part of
>> the internal crypto API. The reason is that there are too many
>> occurrences where non-trivial chaining modes have been cobbled
>> together from the cipher API.

Well, in the ESSIV case I understand there are two in-kernel users, so it makes
perfect sense to use common crypto API implementation.

For the rest, I perhaps still do not understand the reason to move this API
to "internal only" state.

(I am sure people will find an another way to to construct crazy things,
even if they are forced to use skcipher API. 8-)

>>> See the patch below - all we need is to one block encryption for IV.
>>>
>>> This algorithm makes sense only for FDE (old compatible Bitlocker devices),
>>> I really do not want this to be shared in some crypto module...
>>>
>>> What API should I use here? Sync skcipher? Is the crypto_cipher API
>>> really a problem in this case?
>>>
>>
>> Are arbitrary ciphers supported? Or are you only interested in AES? In
>> the former case, I'd suggest the sync skcipher API to instantiate
>> "ecb(%s)", otherwise, use the upcoming AES library interface.

For the Bitlocker compatibility, it is only AES in CBC mode, but we usually do
not limit IV use in dmcrypt.
(We still need to solve the Bitlocker Elephant diffuser, but that's another issue.)

> Actually, if CBC is the only supported mode, you could also use the
> skcipher itself to encrypt a single block of input (just encrypt the
> IV using CBC but with an IV of all zeroes)

I can then use ECB skcipher directly (IOW use skcipher ecb(aes) for IV).
(ECB mode must be present, because XTS is based on it anyway.)

Why I am asking is that with sync skcipher it means allocation of request
on stack - still more code than the patch I posted below.

We can do that. But if the crypto_cipher API stays exported, I do not see any
reason to write more complicated code.

We (dmcrypt) are pretty sophisticated user of crypto API already :)

Thanks,
Milan

> 
> 
>>> On 04/07/2019 15:10, Milan Broz wrote:
>>>> This IV is used in some BitLocker devices with CBC encryption mode.
>>>>
>>>> NOTE: maybe we need to use another crypto API if the bare cipher
>>>>       API is going to be deprecated.
>>>>
>>>> Signed-off-by: Milan Broz <gmazyland@gmail.com>
>>>> ---
>>>>  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
>>>>  1 file changed, 81 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
>>>> index 96ead4492787..a5ffa1ac6a28 100644
>>>> --- a/drivers/md/dm-crypt.c
>>>> +++ b/drivers/md/dm-crypt.c
>>>> @@ -120,6 +120,10 @@ struct iv_tcw_private {
>>>>       u8 *whitening;
>>>>  };
>>>>
>>>> +struct iv_eboiv_private {
>>>> +     struct crypto_cipher *tfm;
>>>> +};
>>>> +
>>>>  /*
>>>>   * Crypt: maps a linear range of a block device
>>>>   * and encrypts / decrypts at the same time.
>>>> @@ -159,6 +163,7 @@ struct crypt_config {
>>>>               struct iv_benbi_private benbi;
>>>>               struct iv_lmk_private lmk;
>>>>               struct iv_tcw_private tcw;
>>>> +             struct iv_eboiv_private eboiv;
>>>>       } iv_gen_private;
>>>>       u64 iv_offset;
>>>>       unsigned int iv_size;
>>>> @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
>>>>   *       is calculated from initial key, sector number and mixed using CRC32.
>>>>   *       Note that this encryption scheme is vulnerable to watermarking attacks
>>>>   *       and should be used for old compatible containers access only.
>>>> + *
>>>> + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
>>>> + *        The IV is encrypted little-endian byte-offset (with the same key
>>>> + *        and cipher as the volume).
>>>>   */
>>>>
>>>>  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
>>>> @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
>>>>       return 0;
>>>>  }
>>>>
>>>> +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
>>>> +{
>>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
>>>> +
>>>> +     crypto_free_cipher(eboiv->tfm);
>>>> +     eboiv->tfm = NULL;
>>>> +}
>>>> +
>>>> +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
>>>> +                         const char *opts)
>>>> +{
>>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
>>>> +     struct crypto_cipher *tfm;
>>>> +
>>>> +     tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
>>>> +     if (IS_ERR(tfm)) {
>>>> +             ti->error = "Error allocating crypto tfm for EBOIV";
>>>> +             return PTR_ERR(tfm);
>>>> +     }
>>>> +
>>>> +     if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
>>>> +             ti->error = "Block size of EBOIV cipher does "
>>>> +                         "not match IV size of block cipher";
>>>> +             crypto_free_cipher(tfm);
>>>> +             return -EINVAL;
>>>> +     }
>>>> +
>>>> +     eboiv->tfm = tfm;
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int crypt_iv_eboiv_init(struct crypt_config *cc)
>>>> +{
>>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
>>>> +     int err;
>>>> +
>>>> +     err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
>>>> +     if (err)
>>>> +             return err;
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
>>>> +{
>>>> +     /* Called after cc->key is set to random key in crypt_wipe() */
>>>> +     return crypt_iv_eboiv_init(cc);
>>>> +}
>>>> +
>>>> +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
>>>> +                         struct dm_crypt_request *dmreq)
>>>> +{
>>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
>>>> +
>>>> +     memset(iv, 0, cc->iv_size);
>>>> +     *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
>>>> +     crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>>  static const struct crypt_iv_operations crypt_iv_plain_ops = {
>>>>       .generator = crypt_iv_plain_gen
>>>>  };
>>>> @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
>>>>       .generator = crypt_iv_random_gen
>>>>  };
>>>>
>>>> +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
>>>> +     .ctr       = crypt_iv_eboiv_ctr,
>>>> +     .dtr       = crypt_iv_eboiv_dtr,
>>>> +     .init      = crypt_iv_eboiv_init,
>>>> +     .wipe      = crypt_iv_eboiv_wipe,
>>>> +     .generator = crypt_iv_eboiv_gen
>>>> +};
>>>> +
>>>>  /*
>>>>   * Integrity extensions
>>>>   */
>>>> @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
>>>>               cc->iv_gen_ops = &crypt_iv_benbi_ops;
>>>>       else if (strcmp(ivmode, "null") == 0)
>>>>               cc->iv_gen_ops = &crypt_iv_null_ops;
>>>> +     else if (strcmp(ivmode, "eboiv") == 0)
>>>> +             cc->iv_gen_ops = &crypt_iv_eboiv_ops;
>>>>       else if (strcmp(ivmode, "lmk") == 0) {
>>>>               cc->iv_gen_ops = &crypt_iv_lmk_ops;
>>>>               /*
>>>> @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
>>>>
>>>>  static struct target_type crypt_target = {
>>>>       .name   = "crypt",
>>>> -     .version = {1, 18, 1},
>>>> +     .version = {1, 19, 0},
>>>>       .module = THIS_MODULE,
>>>>       .ctr    = crypt_ctr,
>>>>       .dtr    = crypt_dtr,
>>>>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
@ 2019-07-04 17:45           ` Milan Broz
  0 siblings, 0 replies; 19+ messages in thread
From: Milan Broz @ 2019-07-04 17:45 UTC (permalink / raw)
  To: Ard Biesheuvel, Eric Biggers
  Cc: device-mapper development, Herbert Xu,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

On 04/07/2019 16:30, Ard Biesheuvel wrote:
> On Thu, 4 Jul 2019 at 16:28, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>>
>> (+ Eric)
>>
>> On Thu, 4 Jul 2019 at 15:29, Milan Broz <gmazyland@gmail.com> wrote:
>>>
>>> Hi Herbert,
>>>
>>> I have a question about the crypto_cipher API in dm-crypt:
>>>
>>> We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
>>> but I am not sure what API now should be used instead.
>>>
>>
>> Not precisely - what I would like to do is to make the cipher part of
>> the internal crypto API. The reason is that there are too many
>> occurrences where non-trivial chaining modes have been cobbled
>> together from the cipher API.

Well, in the ESSIV case I understand there are two in-kernel users, so it makes
perfect sense to use common crypto API implementation.

For the rest, I perhaps still do not understand the reason to move this API
to "internal only" state.

(I am sure people will find an another way to to construct crazy things,
even if they are forced to use skcipher API. 8-)

>>> See the patch below - all we need is to one block encryption for IV.
>>>
>>> This algorithm makes sense only for FDE (old compatible Bitlocker devices),
>>> I really do not want this to be shared in some crypto module...
>>>
>>> What API should I use here? Sync skcipher? Is the crypto_cipher API
>>> really a problem in this case?
>>>
>>
>> Are arbitrary ciphers supported? Or are you only interested in AES? In
>> the former case, I'd suggest the sync skcipher API to instantiate
>> "ecb(%s)", otherwise, use the upcoming AES library interface.

For the Bitlocker compatibility, it is only AES in CBC mode, but we usually do
not limit IV use in dmcrypt.
(We still need to solve the Bitlocker Elephant diffuser, but that's another issue.)

> Actually, if CBC is the only supported mode, you could also use the
> skcipher itself to encrypt a single block of input (just encrypt the
> IV using CBC but with an IV of all zeroes)

I can then use ECB skcipher directly (IOW use skcipher ecb(aes) for IV).
(ECB mode must be present, because XTS is based on it anyway.)

Why I am asking is that with sync skcipher it means allocation of request
on stack - still more code than the patch I posted below.

We can do that. But if the crypto_cipher API stays exported, I do not see any
reason to write more complicated code.

We (dmcrypt) are pretty sophisticated user of crypto API already :)

Thanks,
Milan

> 
> 
>>> On 04/07/2019 15:10, Milan Broz wrote:
>>>> This IV is used in some BitLocker devices with CBC encryption mode.
>>>>
>>>> NOTE: maybe we need to use another crypto API if the bare cipher
>>>>       API is going to be deprecated.
>>>>
>>>> Signed-off-by: Milan Broz <gmazyland@gmail.com>
>>>> ---
>>>>  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
>>>>  1 file changed, 81 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
>>>> index 96ead4492787..a5ffa1ac6a28 100644
>>>> --- a/drivers/md/dm-crypt.c
>>>> +++ b/drivers/md/dm-crypt.c
>>>> @@ -120,6 +120,10 @@ struct iv_tcw_private {
>>>>       u8 *whitening;
>>>>  };
>>>>
>>>> +struct iv_eboiv_private {
>>>> +     struct crypto_cipher *tfm;
>>>> +};
>>>> +
>>>>  /*
>>>>   * Crypt: maps a linear range of a block device
>>>>   * and encrypts / decrypts at the same time.
>>>> @@ -159,6 +163,7 @@ struct crypt_config {
>>>>               struct iv_benbi_private benbi;
>>>>               struct iv_lmk_private lmk;
>>>>               struct iv_tcw_private tcw;
>>>> +             struct iv_eboiv_private eboiv;
>>>>       } iv_gen_private;
>>>>       u64 iv_offset;
>>>>       unsigned int iv_size;
>>>> @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
>>>>   *       is calculated from initial key, sector number and mixed using CRC32.
>>>>   *       Note that this encryption scheme is vulnerable to watermarking attacks
>>>>   *       and should be used for old compatible containers access only.
>>>> + *
>>>> + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
>>>> + *        The IV is encrypted little-endian byte-offset (with the same key
>>>> + *        and cipher as the volume).
>>>>   */
>>>>
>>>>  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
>>>> @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
>>>>       return 0;
>>>>  }
>>>>
>>>> +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
>>>> +{
>>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
>>>> +
>>>> +     crypto_free_cipher(eboiv->tfm);
>>>> +     eboiv->tfm = NULL;
>>>> +}
>>>> +
>>>> +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
>>>> +                         const char *opts)
>>>> +{
>>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
>>>> +     struct crypto_cipher *tfm;
>>>> +
>>>> +     tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
>>>> +     if (IS_ERR(tfm)) {
>>>> +             ti->error = "Error allocating crypto tfm for EBOIV";
>>>> +             return PTR_ERR(tfm);
>>>> +     }
>>>> +
>>>> +     if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
>>>> +             ti->error = "Block size of EBOIV cipher does "
>>>> +                         "not match IV size of block cipher";
>>>> +             crypto_free_cipher(tfm);
>>>> +             return -EINVAL;
>>>> +     }
>>>> +
>>>> +     eboiv->tfm = tfm;
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int crypt_iv_eboiv_init(struct crypt_config *cc)
>>>> +{
>>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
>>>> +     int err;
>>>> +
>>>> +     err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
>>>> +     if (err)
>>>> +             return err;
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>> +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
>>>> +{
>>>> +     /* Called after cc->key is set to random key in crypt_wipe() */
>>>> +     return crypt_iv_eboiv_init(cc);
>>>> +}
>>>> +
>>>> +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
>>>> +                         struct dm_crypt_request *dmreq)
>>>> +{
>>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
>>>> +
>>>> +     memset(iv, 0, cc->iv_size);
>>>> +     *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
>>>> +     crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
>>>> +
>>>> +     return 0;
>>>> +}
>>>> +
>>>>  static const struct crypt_iv_operations crypt_iv_plain_ops = {
>>>>       .generator = crypt_iv_plain_gen
>>>>  };
>>>> @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
>>>>       .generator = crypt_iv_random_gen
>>>>  };
>>>>
>>>> +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
>>>> +     .ctr       = crypt_iv_eboiv_ctr,
>>>> +     .dtr       = crypt_iv_eboiv_dtr,
>>>> +     .init      = crypt_iv_eboiv_init,
>>>> +     .wipe      = crypt_iv_eboiv_wipe,
>>>> +     .generator = crypt_iv_eboiv_gen
>>>> +};
>>>> +
>>>>  /*
>>>>   * Integrity extensions
>>>>   */
>>>> @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
>>>>               cc->iv_gen_ops = &crypt_iv_benbi_ops;
>>>>       else if (strcmp(ivmode, "null") == 0)
>>>>               cc->iv_gen_ops = &crypt_iv_null_ops;
>>>> +     else if (strcmp(ivmode, "eboiv") == 0)
>>>> +             cc->iv_gen_ops = &crypt_iv_eboiv_ops;
>>>>       else if (strcmp(ivmode, "lmk") == 0) {
>>>>               cc->iv_gen_ops = &crypt_iv_lmk_ops;
>>>>               /*
>>>> @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
>>>>
>>>>  static struct target_type crypt_target = {
>>>>       .name   = "crypt",
>>>> -     .version = {1, 18, 1},
>>>> +     .version = {1, 19, 0},
>>>>       .module = THIS_MODULE,
>>>>       .ctr    = crypt_ctr,
>>>>       .dtr    = crypt_dtr,
>>>>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
  2019-07-04 17:45           ` Milan Broz
@ 2019-07-04 18:11             ` Ard Biesheuvel
  -1 siblings, 0 replies; 19+ messages in thread
From: Ard Biesheuvel @ 2019-07-04 18:11 UTC (permalink / raw)
  To: Milan Broz
  Cc: Eric Biggers, Herbert Xu, device-mapper development,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

On Thu, 4 Jul 2019 at 19:45, Milan Broz <gmazyland@gmail.com> wrote:
>
> On 04/07/2019 16:30, Ard Biesheuvel wrote:
> > On Thu, 4 Jul 2019 at 16:28, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> >>
> >> (+ Eric)
> >>
> >> On Thu, 4 Jul 2019 at 15:29, Milan Broz <gmazyland@gmail.com> wrote:
> >>>
> >>> Hi Herbert,
> >>>
> >>> I have a question about the crypto_cipher API in dm-crypt:
> >>>
> >>> We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
> >>> but I am not sure what API now should be used instead.
> >>>
> >>
> >> Not precisely - what I would like to do is to make the cipher part of
> >> the internal crypto API. The reason is that there are too many
> >> occurrences where non-trivial chaining modes have been cobbled
> >> together from the cipher API.
>
> Well, in the ESSIV case I understand there are two in-kernel users, so it makes
> perfect sense to use common crypto API implementation.
>
> For the rest, I perhaps still do not understand the reason to move this API
> to "internal only" state.
>
> (I am sure people will find an another way to to construct crazy things,
> even if they are forced to use skcipher API. 8-)
>

True

To be clear, making the cipher API internal only is something that I
am proposing but hasn't been widely discussed yet. So if you make a
good argument why it is a terrible idea, I'm sure it will be taken
into account.

The main issue is that the cipher API is suboptimal if you process
many blocks in sequence, since SIMD implementations will not be able
to amortize the cost of kernel_fpu_begin()/end(). This is something
that we might be able to fix in other ways (and a SIMD get/put
interface has already been proposed which looks suitable for this as
well) but that would still involve an API change for something that
isn't the correct abstraction in the first place in many cases. (There
are multiple implementations of ccm(aes) using cipher_encrypt_one() in
a loop, for instance, and these are not able to benefit from, e.g,
the accelerated implementation that I created for arm64, since it open
codes the CCM operations)

> >>> See the patch below - all we need is to one block encryption for IV.
> >>>
> >>> This algorithm makes sense only for FDE (old compatible Bitlocker devices),
> >>> I really do not want this to be shared in some crypto module...
> >>>
> >>> What API should I use here? Sync skcipher? Is the crypto_cipher API
> >>> really a problem in this case?
> >>>
> >>
> >> Are arbitrary ciphers supported? Or are you only interested in AES? In
> >> the former case, I'd suggest the sync skcipher API to instantiate
> >> "ecb(%s)", otherwise, use the upcoming AES library interface.
>
> For the Bitlocker compatibility, it is only AES in CBC mode, but we usually do
> not limit IV use in dmcrypt.

Why on earth would you implement eboiv for compatibility purposes, and
then allow it to be used in random other combinations? Pushing back on
the use of arbitrary cipher cocktails is one of the reasons I'd prefer
the cipher API to become crypto internal, since it is typically much
better to stick with recommended combinations that are known to be
secure/

> (We still need to solve the Bitlocker Elephant diffuser, but that's another issue.)
>
> > Actually, if CBC is the only supported mode, you could also use the
> > skcipher itself to encrypt a single block of input (just encrypt the
> > IV using CBC but with an IV of all zeroes)
>
> I can then use ECB skcipher directly (IOW use skcipher ecb(aes) for IV).
> (ECB mode must be present, because XTS is based on it anyway.)
>
> Why I am asking is that with sync skcipher it means allocation of request
> on stack - still more code than the patch I posted below.
>

That is a very good point, and something that I have been meaning to
bring up myself: ever since we switched from [a]blkciphers so
skciphers, we lost the ability to operate synchronously on virtual
addresses, like we still have with shashes (as opposed to ahashes)
today. AEADs suffer from the same limitation.

The thing is, while switching to the cipher API does work around that,
it is not a proper fix, and going forward, we should really address
the above limitation in a sane way.

> We can do that. But if the crypto_cipher API stays exported, I do not see any
> reason to write more complicated code.
>
> We (dmcrypt) are pretty sophisticated user of crypto API already :)
>

That is absolutely true.

In summary, I think implementing eboiv for arbitrary ciphers would be
a mistake, since it is a mode that is intended for compatibility.
However, if you do, I think going with the cipher API for now is fine,
since you are using it in a sane way (i.e., to encrypt a single block
of plaintext with an a priori unknown cipher). If it ever becomes an
internal-only crypto API, we'll propose something else by that time.




> >
> >
> >>> On 04/07/2019 15:10, Milan Broz wrote:
> >>>> This IV is used in some BitLocker devices with CBC encryption mode.
> >>>>
> >>>> NOTE: maybe we need to use another crypto API if the bare cipher
> >>>>       API is going to be deprecated.
> >>>>
> >>>> Signed-off-by: Milan Broz <gmazyland@gmail.com>
> >>>> ---
> >>>>  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
> >>>>  1 file changed, 81 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> >>>> index 96ead4492787..a5ffa1ac6a28 100644
> >>>> --- a/drivers/md/dm-crypt.c
> >>>> +++ b/drivers/md/dm-crypt.c
> >>>> @@ -120,6 +120,10 @@ struct iv_tcw_private {
> >>>>       u8 *whitening;
> >>>>  };
> >>>>
> >>>> +struct iv_eboiv_private {
> >>>> +     struct crypto_cipher *tfm;
> >>>> +};
> >>>> +
> >>>>  /*
> >>>>   * Crypt: maps a linear range of a block device
> >>>>   * and encrypts / decrypts at the same time.
> >>>> @@ -159,6 +163,7 @@ struct crypt_config {
> >>>>               struct iv_benbi_private benbi;
> >>>>               struct iv_lmk_private lmk;
> >>>>               struct iv_tcw_private tcw;
> >>>> +             struct iv_eboiv_private eboiv;
> >>>>       } iv_gen_private;
> >>>>       u64 iv_offset;
> >>>>       unsigned int iv_size;
> >>>> @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
> >>>>   *       is calculated from initial key, sector number and mixed using CRC32.
> >>>>   *       Note that this encryption scheme is vulnerable to watermarking attacks
> >>>>   *       and should be used for old compatible containers access only.
> >>>> + *
> >>>> + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
> >>>> + *        The IV is encrypted little-endian byte-offset (with the same key
> >>>> + *        and cipher as the volume).
> >>>>   */
> >>>>
> >>>>  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
> >>>> @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
> >>>>       return 0;
> >>>>  }
> >>>>
> >>>> +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
> >>>> +{
> >>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> >>>> +
> >>>> +     crypto_free_cipher(eboiv->tfm);
> >>>> +     eboiv->tfm = NULL;
> >>>> +}
> >>>> +
> >>>> +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
> >>>> +                         const char *opts)
> >>>> +{
> >>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> >>>> +     struct crypto_cipher *tfm;
> >>>> +
> >>>> +     tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
> >>>> +     if (IS_ERR(tfm)) {
> >>>> +             ti->error = "Error allocating crypto tfm for EBOIV";
> >>>> +             return PTR_ERR(tfm);
> >>>> +     }
> >>>> +
> >>>> +     if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
> >>>> +             ti->error = "Block size of EBOIV cipher does "
> >>>> +                         "not match IV size of block cipher";
> >>>> +             crypto_free_cipher(tfm);
> >>>> +             return -EINVAL;
> >>>> +     }
> >>>> +
> >>>> +     eboiv->tfm = tfm;
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>> +static int crypt_iv_eboiv_init(struct crypt_config *cc)
> >>>> +{
> >>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> >>>> +     int err;
> >>>> +
> >>>> +     err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
> >>>> +     if (err)
> >>>> +             return err;
> >>>> +
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>> +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
> >>>> +{
> >>>> +     /* Called after cc->key is set to random key in crypt_wipe() */
> >>>> +     return crypt_iv_eboiv_init(cc);
> >>>> +}
> >>>> +
> >>>> +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
> >>>> +                         struct dm_crypt_request *dmreq)
> >>>> +{
> >>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> >>>> +
> >>>> +     memset(iv, 0, cc->iv_size);
> >>>> +     *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
> >>>> +     crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
> >>>> +
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>>  static const struct crypt_iv_operations crypt_iv_plain_ops = {
> >>>>       .generator = crypt_iv_plain_gen
> >>>>  };
> >>>> @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
> >>>>       .generator = crypt_iv_random_gen
> >>>>  };
> >>>>
> >>>> +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
> >>>> +     .ctr       = crypt_iv_eboiv_ctr,
> >>>> +     .dtr       = crypt_iv_eboiv_dtr,
> >>>> +     .init      = crypt_iv_eboiv_init,
> >>>> +     .wipe      = crypt_iv_eboiv_wipe,
> >>>> +     .generator = crypt_iv_eboiv_gen
> >>>> +};
> >>>> +
> >>>>  /*
> >>>>   * Integrity extensions
> >>>>   */
> >>>> @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
> >>>>               cc->iv_gen_ops = &crypt_iv_benbi_ops;
> >>>>       else if (strcmp(ivmode, "null") == 0)
> >>>>               cc->iv_gen_ops = &crypt_iv_null_ops;
> >>>> +     else if (strcmp(ivmode, "eboiv") == 0)
> >>>> +             cc->iv_gen_ops = &crypt_iv_eboiv_ops;
> >>>>       else if (strcmp(ivmode, "lmk") == 0) {
> >>>>               cc->iv_gen_ops = &crypt_iv_lmk_ops;
> >>>>               /*
> >>>> @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
> >>>>
> >>>>  static struct target_type crypt_target = {
> >>>>       .name   = "crypt",
> >>>> -     .version = {1, 18, 1},
> >>>> +     .version = {1, 19, 0},
> >>>>       .module = THIS_MODULE,
> >>>>       .ctr    = crypt_ctr,
> >>>>       .dtr    = crypt_dtr,
> >>>>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
@ 2019-07-04 18:11             ` Ard Biesheuvel
  0 siblings, 0 replies; 19+ messages in thread
From: Ard Biesheuvel @ 2019-07-04 18:11 UTC (permalink / raw)
  To: Milan Broz
  Cc: open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	device-mapper development, Herbert Xu, Eric Biggers

On Thu, 4 Jul 2019 at 19:45, Milan Broz <gmazyland@gmail.com> wrote:
>
> On 04/07/2019 16:30, Ard Biesheuvel wrote:
> > On Thu, 4 Jul 2019 at 16:28, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> >>
> >> (+ Eric)
> >>
> >> On Thu, 4 Jul 2019 at 15:29, Milan Broz <gmazyland@gmail.com> wrote:
> >>>
> >>> Hi Herbert,
> >>>
> >>> I have a question about the crypto_cipher API in dm-crypt:
> >>>
> >>> We are apparently trying to deprecate cryto_cipher API (see the ESSIV patchset),
> >>> but I am not sure what API now should be used instead.
> >>>
> >>
> >> Not precisely - what I would like to do is to make the cipher part of
> >> the internal crypto API. The reason is that there are too many
> >> occurrences where non-trivial chaining modes have been cobbled
> >> together from the cipher API.
>
> Well, in the ESSIV case I understand there are two in-kernel users, so it makes
> perfect sense to use common crypto API implementation.
>
> For the rest, I perhaps still do not understand the reason to move this API
> to "internal only" state.
>
> (I am sure people will find an another way to to construct crazy things,
> even if they are forced to use skcipher API. 8-)
>

True

To be clear, making the cipher API internal only is something that I
am proposing but hasn't been widely discussed yet. So if you make a
good argument why it is a terrible idea, I'm sure it will be taken
into account.

The main issue is that the cipher API is suboptimal if you process
many blocks in sequence, since SIMD implementations will not be able
to amortize the cost of kernel_fpu_begin()/end(). This is something
that we might be able to fix in other ways (and a SIMD get/put
interface has already been proposed which looks suitable for this as
well) but that would still involve an API change for something that
isn't the correct abstraction in the first place in many cases. (There
are multiple implementations of ccm(aes) using cipher_encrypt_one() in
a loop, for instance, and these are not able to benefit from, e.g,
the accelerated implementation that I created for arm64, since it open
codes the CCM operations)

> >>> See the patch below - all we need is to one block encryption for IV.
> >>>
> >>> This algorithm makes sense only for FDE (old compatible Bitlocker devices),
> >>> I really do not want this to be shared in some crypto module...
> >>>
> >>> What API should I use here? Sync skcipher? Is the crypto_cipher API
> >>> really a problem in this case?
> >>>
> >>
> >> Are arbitrary ciphers supported? Or are you only interested in AES? In
> >> the former case, I'd suggest the sync skcipher API to instantiate
> >> "ecb(%s)", otherwise, use the upcoming AES library interface.
>
> For the Bitlocker compatibility, it is only AES in CBC mode, but we usually do
> not limit IV use in dmcrypt.

Why on earth would you implement eboiv for compatibility purposes, and
then allow it to be used in random other combinations? Pushing back on
the use of arbitrary cipher cocktails is one of the reasons I'd prefer
the cipher API to become crypto internal, since it is typically much
better to stick with recommended combinations that are known to be
secure/

> (We still need to solve the Bitlocker Elephant diffuser, but that's another issue.)
>
> > Actually, if CBC is the only supported mode, you could also use the
> > skcipher itself to encrypt a single block of input (just encrypt the
> > IV using CBC but with an IV of all zeroes)
>
> I can then use ECB skcipher directly (IOW use skcipher ecb(aes) for IV).
> (ECB mode must be present, because XTS is based on it anyway.)
>
> Why I am asking is that with sync skcipher it means allocation of request
> on stack - still more code than the patch I posted below.
>

That is a very good point, and something that I have been meaning to
bring up myself: ever since we switched from [a]blkciphers so
skciphers, we lost the ability to operate synchronously on virtual
addresses, like we still have with shashes (as opposed to ahashes)
today. AEADs suffer from the same limitation.

The thing is, while switching to the cipher API does work around that,
it is not a proper fix, and going forward, we should really address
the above limitation in a sane way.

> We can do that. But if the crypto_cipher API stays exported, I do not see any
> reason to write more complicated code.
>
> We (dmcrypt) are pretty sophisticated user of crypto API already :)
>

That is absolutely true.

In summary, I think implementing eboiv for arbitrary ciphers would be
a mistake, since it is a mode that is intended for compatibility.
However, if you do, I think going with the cipher API for now is fine,
since you are using it in a sane way (i.e., to encrypt a single block
of plaintext with an a priori unknown cipher). If it ever becomes an
internal-only crypto API, we'll propose something else by that time.




> >
> >
> >>> On 04/07/2019 15:10, Milan Broz wrote:
> >>>> This IV is used in some BitLocker devices with CBC encryption mode.
> >>>>
> >>>> NOTE: maybe we need to use another crypto API if the bare cipher
> >>>>       API is going to be deprecated.
> >>>>
> >>>> Signed-off-by: Milan Broz <gmazyland@gmail.com>
> >>>> ---
> >>>>  drivers/md/dm-crypt.c | 82 ++++++++++++++++++++++++++++++++++++++++++-
> >>>>  1 file changed, 81 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> >>>> index 96ead4492787..a5ffa1ac6a28 100644
> >>>> --- a/drivers/md/dm-crypt.c
> >>>> +++ b/drivers/md/dm-crypt.c
> >>>> @@ -120,6 +120,10 @@ struct iv_tcw_private {
> >>>>       u8 *whitening;
> >>>>  };
> >>>>
> >>>> +struct iv_eboiv_private {
> >>>> +     struct crypto_cipher *tfm;
> >>>> +};
> >>>> +
> >>>>  /*
> >>>>   * Crypt: maps a linear range of a block device
> >>>>   * and encrypts / decrypts at the same time.
> >>>> @@ -159,6 +163,7 @@ struct crypt_config {
> >>>>               struct iv_benbi_private benbi;
> >>>>               struct iv_lmk_private lmk;
> >>>>               struct iv_tcw_private tcw;
> >>>> +             struct iv_eboiv_private eboiv;
> >>>>       } iv_gen_private;
> >>>>       u64 iv_offset;
> >>>>       unsigned int iv_size;
> >>>> @@ -290,6 +295,10 @@ static struct crypto_aead *any_tfm_aead(struct crypt_config *cc)
> >>>>   *       is calculated from initial key, sector number and mixed using CRC32.
> >>>>   *       Note that this encryption scheme is vulnerable to watermarking attacks
> >>>>   *       and should be used for old compatible containers access only.
> >>>> + *
> >>>> + * eboiv: Encrypted byte-offset IV (used in Bitlocker in CBC mode)
> >>>> + *        The IV is encrypted little-endian byte-offset (with the same key
> >>>> + *        and cipher as the volume).
> >>>>   */
> >>>>
> >>>>  static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv,
> >>>> @@ -838,6 +847,67 @@ static int crypt_iv_random_gen(struct crypt_config *cc, u8 *iv,
> >>>>       return 0;
> >>>>  }
> >>>>
> >>>> +static void crypt_iv_eboiv_dtr(struct crypt_config *cc)
> >>>> +{
> >>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> >>>> +
> >>>> +     crypto_free_cipher(eboiv->tfm);
> >>>> +     eboiv->tfm = NULL;
> >>>> +}
> >>>> +
> >>>> +static int crypt_iv_eboiv_ctr(struct crypt_config *cc, struct dm_target *ti,
> >>>> +                         const char *opts)
> >>>> +{
> >>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> >>>> +     struct crypto_cipher *tfm;
> >>>> +
> >>>> +     tfm = crypto_alloc_cipher(cc->cipher, 0, 0);
> >>>> +     if (IS_ERR(tfm)) {
> >>>> +             ti->error = "Error allocating crypto tfm for EBOIV";
> >>>> +             return PTR_ERR(tfm);
> >>>> +     }
> >>>> +
> >>>> +     if (crypto_cipher_blocksize(tfm) != cc->iv_size) {
> >>>> +             ti->error = "Block size of EBOIV cipher does "
> >>>> +                         "not match IV size of block cipher";
> >>>> +             crypto_free_cipher(tfm);
> >>>> +             return -EINVAL;
> >>>> +     }
> >>>> +
> >>>> +     eboiv->tfm = tfm;
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>> +static int crypt_iv_eboiv_init(struct crypt_config *cc)
> >>>> +{
> >>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> >>>> +     int err;
> >>>> +
> >>>> +     err = crypto_cipher_setkey(eboiv->tfm, cc->key, cc->key_size);
> >>>> +     if (err)
> >>>> +             return err;
> >>>> +
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>> +static int crypt_iv_eboiv_wipe(struct crypt_config *cc)
> >>>> +{
> >>>> +     /* Called after cc->key is set to random key in crypt_wipe() */
> >>>> +     return crypt_iv_eboiv_init(cc);
> >>>> +}
> >>>> +
> >>>> +static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
> >>>> +                         struct dm_crypt_request *dmreq)
> >>>> +{
> >>>> +     struct iv_eboiv_private *eboiv = &cc->iv_gen_private.eboiv;
> >>>> +
> >>>> +     memset(iv, 0, cc->iv_size);
> >>>> +     *(__le64 *)iv = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
> >>>> +     crypto_cipher_encrypt_one(eboiv->tfm, iv, iv);
> >>>> +
> >>>> +     return 0;
> >>>> +}
> >>>> +
> >>>>  static const struct crypt_iv_operations crypt_iv_plain_ops = {
> >>>>       .generator = crypt_iv_plain_gen
> >>>>  };
> >>>> @@ -890,6 +960,14 @@ static struct crypt_iv_operations crypt_iv_random_ops = {
> >>>>       .generator = crypt_iv_random_gen
> >>>>  };
> >>>>
> >>>> +static struct crypt_iv_operations crypt_iv_eboiv_ops = {
> >>>> +     .ctr       = crypt_iv_eboiv_ctr,
> >>>> +     .dtr       = crypt_iv_eboiv_dtr,
> >>>> +     .init      = crypt_iv_eboiv_init,
> >>>> +     .wipe      = crypt_iv_eboiv_wipe,
> >>>> +     .generator = crypt_iv_eboiv_gen
> >>>> +};
> >>>> +
> >>>>  /*
> >>>>   * Integrity extensions
> >>>>   */
> >>>> @@ -2293,6 +2371,8 @@ static int crypt_ctr_ivmode(struct dm_target *ti, const char *ivmode)
> >>>>               cc->iv_gen_ops = &crypt_iv_benbi_ops;
> >>>>       else if (strcmp(ivmode, "null") == 0)
> >>>>               cc->iv_gen_ops = &crypt_iv_null_ops;
> >>>> +     else if (strcmp(ivmode, "eboiv") == 0)
> >>>> +             cc->iv_gen_ops = &crypt_iv_eboiv_ops;
> >>>>       else if (strcmp(ivmode, "lmk") == 0) {
> >>>>               cc->iv_gen_ops = &crypt_iv_lmk_ops;
> >>>>               /*
> >>>> @@ -3093,7 +3173,7 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
> >>>>
> >>>>  static struct target_type crypt_target = {
> >>>>       .name   = "crypt",
> >>>> -     .version = {1, 18, 1},
> >>>> +     .version = {1, 19, 0},
> >>>>       .module = THIS_MODULE,
> >>>>       .ctr    = crypt_ctr,
> >>>>       .dtr    = crypt_dtr,
> >>>>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
  2019-07-04 18:11             ` Ard Biesheuvel
@ 2019-07-05  3:08               ` Herbert Xu
  -1 siblings, 0 replies; 19+ messages in thread
From: Herbert Xu @ 2019-07-05  3:08 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Milan Broz, Eric Biggers, device-mapper development,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

On Thu, Jul 04, 2019 at 08:11:46PM +0200, Ard Biesheuvel wrote:
> 
> To be clear, making the cipher API internal only is something that I
> am proposing but hasn't been widely discussed yet. So if you make a
> good argument why it is a terrible idea, I'm sure it will be taken
> into account.
> 
> The main issue is that the cipher API is suboptimal if you process
> many blocks in sequence, since SIMD implementations will not be able
> to amortize the cost of kernel_fpu_begin()/end(). This is something
> that we might be able to fix in other ways (and a SIMD get/put
> interface has already been proposed which looks suitable for this as
> well) but that would still involve an API change for something that
> isn't the correct abstraction in the first place in many cases. (There
> are multiple implementations of ccm(aes) using cipher_encrypt_one() in
> a loop, for instance, and these are not able to benefit from, e.g,
> the accelerated implementation that I created for arm64, since it open
> codes the CCM operations)

I agree with what you guys have concluded so far.  But I do have
something I want to say about eboiv's implementation itself.

AFAICS this is using the same key as the actual data.  So why
don't you combine it with the actual data when encrypting/decrypting?

That is, add a block at the front of the actual data containing
the little-endian byte offset and then use an IV of zero.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
@ 2019-07-05  3:08               ` Herbert Xu
  0 siblings, 0 replies; 19+ messages in thread
From: Herbert Xu @ 2019-07-05  3:08 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	device-mapper development, Milan Broz, Eric Biggers

On Thu, Jul 04, 2019 at 08:11:46PM +0200, Ard Biesheuvel wrote:
> 
> To be clear, making the cipher API internal only is something that I
> am proposing but hasn't been widely discussed yet. So if you make a
> good argument why it is a terrible idea, I'm sure it will be taken
> into account.
> 
> The main issue is that the cipher API is suboptimal if you process
> many blocks in sequence, since SIMD implementations will not be able
> to amortize the cost of kernel_fpu_begin()/end(). This is something
> that we might be able to fix in other ways (and a SIMD get/put
> interface has already been proposed which looks suitable for this as
> well) but that would still involve an API change for something that
> isn't the correct abstraction in the first place in many cases. (There
> are multiple implementations of ccm(aes) using cipher_encrypt_one() in
> a loop, for instance, and these are not able to benefit from, e.g,
> the accelerated implementation that I created for arm64, since it open
> codes the CCM operations)

I agree with what you guys have concluded so far.  But I do have
something I want to say about eboiv's implementation itself.

AFAICS this is using the same key as the actual data.  So why
don't you combine it with the actual data when encrypting/decrypting?

That is, add a block at the front of the actual data containing
the little-endian byte offset and then use an IV of zero.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
  2019-07-05  3:08               ` Herbert Xu
@ 2019-07-05  6:32                 ` Ard Biesheuvel
  -1 siblings, 0 replies; 19+ messages in thread
From: Ard Biesheuvel @ 2019-07-05  6:32 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Milan Broz, Eric Biggers, device-mapper development,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

On Fri, 5 Jul 2019 at 05:08, Herbert Xu <herbert@gondor.apana.org.au> wrote:
>
> On Thu, Jul 04, 2019 at 08:11:46PM +0200, Ard Biesheuvel wrote:
> >
> > To be clear, making the cipher API internal only is something that I
> > am proposing but hasn't been widely discussed yet. So if you make a
> > good argument why it is a terrible idea, I'm sure it will be taken
> > into account.
> >
> > The main issue is that the cipher API is suboptimal if you process
> > many blocks in sequence, since SIMD implementations will not be able
> > to amortize the cost of kernel_fpu_begin()/end(). This is something
> > that we might be able to fix in other ways (and a SIMD get/put
> > interface has already been proposed which looks suitable for this as
> > well) but that would still involve an API change for something that
> > isn't the correct abstraction in the first place in many cases. (There
> > are multiple implementations of ccm(aes) using cipher_encrypt_one() in
> > a loop, for instance, and these are not able to benefit from, e.g,
> > the accelerated implementation that I created for arm64, since it open
> > codes the CCM operations)
>
> I agree with what you guys have concluded so far.  But I do have
> something I want to say about eboiv's implementation itself.
>
> AFAICS this is using the same key as the actual data.  So why
> don't you combine it with the actual data when encrypting/decrypting?
>
> That is, add a block at the front of the actual data containing
> the little-endian byte offset and then use an IV of zero.
>

That would only work for encryption.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
@ 2019-07-05  6:32                 ` Ard Biesheuvel
  0 siblings, 0 replies; 19+ messages in thread
From: Ard Biesheuvel @ 2019-07-05  6:32 UTC (permalink / raw)
  To: Herbert Xu
  Cc: open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	device-mapper development, Milan Broz, Eric Biggers

On Fri, 5 Jul 2019 at 05:08, Herbert Xu <herbert@gondor.apana.org.au> wrote:
>
> On Thu, Jul 04, 2019 at 08:11:46PM +0200, Ard Biesheuvel wrote:
> >
> > To be clear, making the cipher API internal only is something that I
> > am proposing but hasn't been widely discussed yet. So if you make a
> > good argument why it is a terrible idea, I'm sure it will be taken
> > into account.
> >
> > The main issue is that the cipher API is suboptimal if you process
> > many blocks in sequence, since SIMD implementations will not be able
> > to amortize the cost of kernel_fpu_begin()/end(). This is something
> > that we might be able to fix in other ways (and a SIMD get/put
> > interface has already been proposed which looks suitable for this as
> > well) but that would still involve an API change for something that
> > isn't the correct abstraction in the first place in many cases. (There
> > are multiple implementations of ccm(aes) using cipher_encrypt_one() in
> > a loop, for instance, and these are not able to benefit from, e.g,
> > the accelerated implementation that I created for arm64, since it open
> > codes the CCM operations)
>
> I agree with what you guys have concluded so far.  But I do have
> something I want to say about eboiv's implementation itself.
>
> AFAICS this is using the same key as the actual data.  So why
> don't you combine it with the actual data when encrypting/decrypting?
>
> That is, add a block at the front of the actual data containing
> the little-endian byte offset and then use an IV of zero.
>

That would only work for encryption.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
  2019-07-05  6:32                 ` Ard Biesheuvel
@ 2019-07-05  8:51                   ` Herbert Xu
  -1 siblings, 0 replies; 19+ messages in thread
From: Herbert Xu @ 2019-07-05  8:51 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Milan Broz, Eric Biggers, device-mapper development,
	open list:HARDWARE RANDOM NUMBER GENERATOR CORE

On Fri, Jul 05, 2019 at 08:32:03AM +0200, Ard Biesheuvel wrote:
>
> > AFAICS this is using the same key as the actual data.  So why
> > don't you combine it with the actual data when encrypting/decrypting?
> >
> > That is, add a block at the front of the actual data containing
> > the little-endian byte offset and then use an IV of zero.
> >
> 
> That would only work for encryption.

True.  So this doesn't obviate the need to access the single-block
cipher.  But the code probably should still do it that way for
encryption for performance reasons.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector.
@ 2019-07-05  8:51                   ` Herbert Xu
  0 siblings, 0 replies; 19+ messages in thread
From: Herbert Xu @ 2019-07-05  8:51 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: open list:HARDWARE RANDOM NUMBER GENERATOR CORE,
	device-mapper development, Milan Broz, Eric Biggers

On Fri, Jul 05, 2019 at 08:32:03AM +0200, Ard Biesheuvel wrote:
>
> > AFAICS this is using the same key as the actual data.  So why
> > don't you combine it with the actual data when encrypting/decrypting?
> >
> > That is, add a block at the front of the actual data containing
> > the little-endian byte offset and then use an IV of zero.
> >
> 
> That would only work for encryption.

True.  So this doesn't obviate the need to access the single-block
cipher.  But the code probably should still do it that way for
encryption for performance reasons.

Cheers,
-- 
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2019-07-05  8:51 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-04 13:10 [PATCH 1/3] dm-crypt: Wipe private IV struct after key invalid flag is set Milan Broz
2019-07-04 13:10 ` [PATCH 2/3] dm-crypt: Remove obsolete comment about plumb IV Milan Broz
2019-07-04 13:10 ` [PATCH 3/3] dm-crypt: Implement eboiv - encrypted byte-offset initialization vector Milan Broz
2019-07-04 13:29   ` Milan Broz
2019-07-04 13:29     ` Milan Broz
2019-07-04 14:28     ` Ard Biesheuvel
2019-07-04 14:28       ` Ard Biesheuvel
2019-07-04 14:30       ` Ard Biesheuvel
2019-07-04 14:30         ` Ard Biesheuvel
2019-07-04 17:45         ` Milan Broz
2019-07-04 17:45           ` Milan Broz
2019-07-04 18:11           ` Ard Biesheuvel
2019-07-04 18:11             ` Ard Biesheuvel
2019-07-05  3:08             ` Herbert Xu
2019-07-05  3:08               ` Herbert Xu
2019-07-05  6:32               ` Ard Biesheuvel
2019-07-05  6:32                 ` Ard Biesheuvel
2019-07-05  8:51                 ` Herbert Xu
2019-07-05  8:51                   ` Herbert Xu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.