diff mbox series

[v4,5/7] block: Support detached LUKS header creation using qemu-img

Message ID c573cf4d985b0386e2e419fcccd92245800cdeca.1706586786.git.yong.huang@smartx.com (mailing list archive)
State New, archived
Headers show
Series Support generic Luks encryption | expand

Commit Message

Yong Huang Jan. 30, 2024, 5:37 a.m. UTC
From: Hyman Huang <yong.huang@smartx.com>

Even though a LUKS header might be created with cryptsetup,
qemu-img should be enhanced to accommodate it as well.

Add the 'detached-header' option to specify the creation of
a detached LUKS header. This is how it is used:
$ qemu-img create --object secret,id=sec0,data=abc123 -f luks
> -o cipher-alg=aes-256,cipher-mode=xts -o key-secret=sec0
> -o detached-header=true header.luks

Using qemu-img or cryptsetup tools to query information of
an LUKS header image as follows:

Assume a detached LUKS header image has been created by:
$ dd if=/dev/zero of=test-header.img bs=1M count=32
$ dd if=/dev/zero of=test-payload.img bs=1M count=1000
$ cryptsetup luksFormat --header test-header.img test-payload.img
> --force-password --type luks1

Header image information could be queried using cryptsetup:
$ cryptsetup luksDump test-header.img

or qemu-img:
$ qemu-img info 'json:{"driver":"luks","file":{"filename":
> "test-payload.img"},"header":{"filename":"test-header.img"}}'

When using qemu-img, keep in mind that the entire disk
information specified by the JSON-format string above must be
supplied on the commandline; if not, an overlay check will reveal
a problem with the LUKS volume check logic.

Signed-off-by: Hyman Huang <yong.huang@smartx.com>
---
 block.c          |  5 ++++-
 block/crypto.c   | 10 +++++++++-
 block/crypto.h   |  8 ++++++++
 qapi/crypto.json |  5 ++++-
 4 files changed, 25 insertions(+), 3 deletions(-)

Comments

Daniel P. Berrangé Jan. 31, 2024, 11:50 a.m. UTC | #1
On Tue, Jan 30, 2024 at 01:37:23PM +0800, yong.huang@smartx.com wrote:
> From: Hyman Huang <yong.huang@smartx.com>
> 
> Even though a LUKS header might be created with cryptsetup,
> qemu-img should be enhanced to accommodate it as well.
> 
> Add the 'detached-header' option to specify the creation of
> a detached LUKS header. This is how it is used:
> $ qemu-img create --object secret,id=sec0,data=abc123 -f luks
> > -o cipher-alg=aes-256,cipher-mode=xts -o key-secret=sec0
> > -o detached-header=true header.luks
> 
> Using qemu-img or cryptsetup tools to query information of
> an LUKS header image as follows:
> 
> Assume a detached LUKS header image has been created by:
> $ dd if=/dev/zero of=test-header.img bs=1M count=32
> $ dd if=/dev/zero of=test-payload.img bs=1M count=1000
> $ cryptsetup luksFormat --header test-header.img test-payload.img
> > --force-password --type luks1
> 
> Header image information could be queried using cryptsetup:
> $ cryptsetup luksDump test-header.img
> 
> or qemu-img:
> $ qemu-img info 'json:{"driver":"luks","file":{"filename":
> > "test-payload.img"},"header":{"filename":"test-header.img"}}'
> 
> When using qemu-img, keep in mind that the entire disk
> information specified by the JSON-format string above must be
> supplied on the commandline; if not, an overlay check will reveal
> a problem with the LUKS volume check logic.
> 
> Signed-off-by: Hyman Huang <yong.huang@smartx.com>
> ---
>  block.c          |  5 ++++-
>  block/crypto.c   | 10 +++++++++-
>  block/crypto.h   |  8 ++++++++
>  qapi/crypto.json |  5 ++++-
>  4 files changed, 25 insertions(+), 3 deletions(-)

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>


With regards,
Daniel
Daniel P. Berrangé Feb. 9, 2024, 12:27 p.m. UTC | #2
On Tue, Jan 30, 2024 at 01:37:23PM +0800, yong.huang@smartx.com wrote:
> From: Hyman Huang <yong.huang@smartx.com>
> 
> Even though a LUKS header might be created with cryptsetup,
> qemu-img should be enhanced to accommodate it as well.
> 
> Add the 'detached-header' option to specify the creation of
> a detached LUKS header. This is how it is used:
> $ qemu-img create --object secret,id=sec0,data=abc123 -f luks
> > -o cipher-alg=aes-256,cipher-mode=xts -o key-secret=sec0
> > -o detached-header=true header.luks
> 
> Using qemu-img or cryptsetup tools to query information of
> an LUKS header image as follows:
> 
> Assume a detached LUKS header image has been created by:
> $ dd if=/dev/zero of=test-header.img bs=1M count=32
> $ dd if=/dev/zero of=test-payload.img bs=1M count=1000
> $ cryptsetup luksFormat --header test-header.img test-payload.img
> > --force-password --type luks1
> 
> Header image information could be queried using cryptsetup:
> $ cryptsetup luksDump test-header.img
> 
> or qemu-img:
> $ qemu-img info 'json:{"driver":"luks","file":{"filename":
> > "test-payload.img"},"header":{"filename":"test-header.img"}}'
> 
> When using qemu-img, keep in mind that the entire disk
> information specified by the JSON-format string above must be
> supplied on the commandline; if not, an overlay check will reveal
> a problem with the LUKS volume check logic.
> 
> Signed-off-by: Hyman Huang <yong.huang@smartx.com>
> ---
>  block.c          |  5 ++++-
>  block/crypto.c   | 10 +++++++++-
>  block/crypto.h   |  8 ++++++++
>  qapi/crypto.json |  5 ++++-
>  4 files changed, 25 insertions(+), 3 deletions(-)


> diff --git a/block/crypto.c b/block/crypto.c
> index 8e7ee5e9ac..65426d3a16 100644
> --- a/block/crypto.c
> +++ b/block/crypto.c
> @@ -791,6 +792,9 @@ block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename,
>      PreallocMode prealloc;
>      char *buf = NULL;
>      int64_t size;
> +    bool detached_hdr =
> +        qemu_opt_get_bool(opts, "detached-header", false);
> +    unsigned int cflags = 0;
>      int ret;
>      Error *local_err = NULL;
>  
> @@ -830,6 +834,10 @@ block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename,
>          goto fail;
>      }
>  
> +    if (detached_hdr) {
> +        cflags |= QCRYPTO_BLOCK_CREATE_DETACHED;
> +    }
> +

We're setting cflags but not using it ever.

>      /* Create format layer */
>      ret = block_crypto_co_create_generic(bs, size, create_opts,
>                                           prealloc, 0, errp);

This '0' here should be replaced by 'cflags', since you're
checking for QCRYPTO_BLOCK_CREATE_DETACHED inside the
block_crypto_co_create_generic method.

I'll make this change when I merge this, so no need to resend.


With regards,
Daniel
Markus Armbruster Feb. 19, 2024, 2:24 p.m. UTC | #3
yong.huang@smartx.com writes:

> From: Hyman Huang <yong.huang@smartx.com>
>
> Even though a LUKS header might be created with cryptsetup,
> qemu-img should be enhanced to accommodate it as well.
>
> Add the 'detached-header' option to specify the creation of
> a detached LUKS header. This is how it is used:
> $ qemu-img create --object secret,id=sec0,data=abc123 -f luks
>> -o cipher-alg=aes-256,cipher-mode=xts -o key-secret=sec0
>> -o detached-header=true header.luks
>
> Using qemu-img or cryptsetup tools to query information of
> an LUKS header image as follows:
>
> Assume a detached LUKS header image has been created by:
> $ dd if=/dev/zero of=test-header.img bs=1M count=32
> $ dd if=/dev/zero of=test-payload.img bs=1M count=1000
> $ cryptsetup luksFormat --header test-header.img test-payload.img
>> --force-password --type luks1
>
> Header image information could be queried using cryptsetup:
> $ cryptsetup luksDump test-header.img
>
> or qemu-img:
> $ qemu-img info 'json:{"driver":"luks","file":{"filename":
>> "test-payload.img"},"header":{"filename":"test-header.img"}}'
>
> When using qemu-img, keep in mind that the entire disk
> information specified by the JSON-format string above must be
> supplied on the commandline; if not, an overlay check will reveal
> a problem with the LUKS volume check logic.
>
> Signed-off-by: Hyman Huang <yong.huang@smartx.com>

[...]

> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index fd3d46ebd1..62fd145223 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -223,6 +223,8 @@
>  # @iter-time: number of milliseconds to spend in PBKDF passphrase
>  #     processing.  Currently defaults to 2000. (since 2.8)
>  #
> +# @detached-header: create a detached LUKS header. (since 9.0)
> +#

Behavior when @detached-header is present vs. behavior when it's absent?

>  # Since: 2.6
>  ##
>  { 'struct': 'QCryptoBlockCreateOptionsLUKS',
> @@ -232,7 +234,8 @@
>              '*ivgen-alg': 'QCryptoIVGenAlgorithm',
>              '*ivgen-hash-alg': 'QCryptoHashAlgorithm',
>              '*hash-alg': 'QCryptoHashAlgorithm',
> -            '*iter-time': 'int'}}
> +            '*iter-time': 'int',
> +            '*detached-header': 'bool'}}
>  
>  ##
>  # @QCryptoBlockOpenOptions:
diff mbox series

Patch

diff --git a/block.c b/block.c
index 30afdcbba6..1ed9214f66 100644
--- a/block.c
+++ b/block.c
@@ -7357,7 +7357,10 @@  void bdrv_img_create(const char *filename, const char *fmt,
         goto out;
     }
 
-    if (size == -1) {
+    /* Parameter 'size' is not needed for detached LUKS header */
+    if (size == -1 &&
+        !(!strcmp(fmt, "luks") &&
+          qemu_opt_get_bool(opts, "detached-header", false))) {
         error_setg(errp, "Image creation needs a size parameter");
         goto out;
     }
diff --git a/block/crypto.c b/block/crypto.c
index 8e7ee5e9ac..65426d3a16 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -231,6 +231,7 @@  static QemuOptsList block_crypto_create_opts_luks = {
         BLOCK_CRYPTO_OPT_DEF_LUKS_IVGEN_HASH_ALG(""),
         BLOCK_CRYPTO_OPT_DEF_LUKS_HASH_ALG(""),
         BLOCK_CRYPTO_OPT_DEF_LUKS_ITER_TIME(""),
+        BLOCK_CRYPTO_OPT_DEF_LUKS_DETACHED_HEADER(""),
         { /* end of list */ }
     },
 };
@@ -405,7 +406,7 @@  block_crypto_co_create_generic(BlockDriverState *bs, int64_t size,
 
     data = (struct BlockCryptoCreateData) {
         .blk = blk,
-        .size = size,
+        .size = flags & QCRYPTO_BLOCK_CREATE_DETACHED ? 0 : size,
         .prealloc = prealloc,
     };
 
@@ -791,6 +792,9 @@  block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename,
     PreallocMode prealloc;
     char *buf = NULL;
     int64_t size;
+    bool detached_hdr =
+        qemu_opt_get_bool(opts, "detached-header", false);
+    unsigned int cflags = 0;
     int ret;
     Error *local_err = NULL;
 
@@ -830,6 +834,10 @@  block_crypto_co_create_opts_luks(BlockDriver *drv, const char *filename,
         goto fail;
     }
 
+    if (detached_hdr) {
+        cflags |= QCRYPTO_BLOCK_CREATE_DETACHED;
+    }
+
     /* Create format layer */
     ret = block_crypto_co_create_generic(bs, size, create_opts,
                                          prealloc, 0, errp);
diff --git a/block/crypto.h b/block/crypto.h
index 72e792c9af..dc3d2d5ed9 100644
--- a/block/crypto.h
+++ b/block/crypto.h
@@ -41,6 +41,7 @@ 
 #define BLOCK_CRYPTO_OPT_LUKS_IVGEN_HASH_ALG "ivgen-hash-alg"
 #define BLOCK_CRYPTO_OPT_LUKS_HASH_ALG "hash-alg"
 #define BLOCK_CRYPTO_OPT_LUKS_ITER_TIME "iter-time"
+#define BLOCK_CRYPTO_OPT_LUKS_DETACHED_HEADER "detached-header"
 #define BLOCK_CRYPTO_OPT_LUKS_KEYSLOT "keyslot"
 #define BLOCK_CRYPTO_OPT_LUKS_STATE "state"
 #define BLOCK_CRYPTO_OPT_LUKS_OLD_SECRET "old-secret"
@@ -100,6 +101,13 @@ 
         .help = "Select new state of affected keyslots (active/inactive)",\
     }
 
+#define BLOCK_CRYPTO_OPT_DEF_LUKS_DETACHED_HEADER(prefix)     \
+    {                                                         \
+        .name = prefix BLOCK_CRYPTO_OPT_LUKS_DETACHED_HEADER, \
+        .type = QEMU_OPT_BOOL,                                \
+        .help = "Create a detached LUKS header",              \
+    }
+
 #define BLOCK_CRYPTO_OPT_DEF_LUKS_KEYSLOT(prefix)              \
     {                                                          \
         .name = prefix BLOCK_CRYPTO_OPT_LUKS_KEYSLOT,          \
diff --git a/qapi/crypto.json b/qapi/crypto.json
index fd3d46ebd1..62fd145223 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -223,6 +223,8 @@ 
 # @iter-time: number of milliseconds to spend in PBKDF passphrase
 #     processing.  Currently defaults to 2000. (since 2.8)
 #
+# @detached-header: create a detached LUKS header. (since 9.0)
+#
 # Since: 2.6
 ##
 { 'struct': 'QCryptoBlockCreateOptionsLUKS',
@@ -232,7 +234,8 @@ 
             '*ivgen-alg': 'QCryptoIVGenAlgorithm',
             '*ivgen-hash-alg': 'QCryptoHashAlgorithm',
             '*hash-alg': 'QCryptoHashAlgorithm',
-            '*iter-time': 'int'}}
+            '*iter-time': 'int',
+            '*detached-header': 'bool'}}
 
 ##
 # @QCryptoBlockOpenOptions: