summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--block/crypto.c6
-rw-r--r--crypto/block-luks.c24
-rw-r--r--qapi/crypto.json6
3 files changed, 35 insertions, 1 deletions
diff --git a/block/crypto.c b/block/crypto.c
index 7f61e12686..7aa7eb553e 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -33,6 +33,7 @@
 #define BLOCK_CRYPTO_OPT_LUKS_IVGEN_ALG "ivgen-alg"
 #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"
 
 typedef struct BlockCrypto BlockCrypto;
 
@@ -183,6 +184,11 @@ static QemuOptsList block_crypto_create_opts_luks = {
             .type = QEMU_OPT_STRING,
             .help = "Name of encryption hash algorithm",
         },
+        {
+            .name = BLOCK_CRYPTO_OPT_LUKS_ITER_TIME,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Time to spend in PBKDF in milliseconds",
+        },
         { /* end of list */ }
     },
 };
diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index bc086acdab..91a4172287 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -920,6 +920,9 @@ qcrypto_block_luks_create(QCryptoBlock *block,
     uint64_t iters;
 
     memcpy(&luks_opts, &options->u.luks, sizeof(luks_opts));
+    if (!luks_opts.has_iter_time) {
+        luks_opts.iter_time = 1000;
+    }
     if (!luks_opts.has_cipher_alg) {
         luks_opts.cipher_alg = QCRYPTO_CIPHER_ALG_AES_256;
     }
@@ -1075,6 +1078,16 @@ qcrypto_block_luks_create(QCryptoBlock *block,
         goto error;
     }
 
+    if (iters > (ULLONG_MAX / luks_opts.iter_time)) {
+        error_setg_errno(errp, ERANGE,
+                         "PBKDF iterations %llu too large to scale",
+                         (unsigned long long)iters);
+        goto error;
+    }
+
+    /* iter_time was in millis, but count_iters reported for secs */
+    iters = iters * luks_opts.iter_time / 1000;
+
     /* Why /= 8 ?  That matches cryptsetup, but there's no
      * explanation why they chose /= 8... Probably so that
      * if all 8 keyslots are active we only spend 1 second
@@ -1144,6 +1157,17 @@ qcrypto_block_luks_create(QCryptoBlock *block,
         error_propagate(errp, local_err);
         goto error;
     }
+
+    if (iters > (ULLONG_MAX / luks_opts.iter_time)) {
+        error_setg_errno(errp, ERANGE,
+                         "PBKDF iterations %llu too large to scale",
+                         (unsigned long long)iters);
+        goto error;
+    }
+
+    /* iter_time was in millis, but count_iters reported for secs */
+    iters = iters * luks_opts.iter_time / 1000;
+
     /* Why /= 2 ?  That matches cryptsetup, but there's no
      * explanation why they chose /= 2... */
     iters /= 2;
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 34d2583154..2b6118f660 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -185,6 +185,9 @@
 #                  Currently defaults to 'sha256'
 # @hash-alg: #optional the master key hash algorithm
 #            Currently defaults to 'sha256'
+# @iter-time: #optional number of milliseconds to spend in
+#             PBKDF passphrase processing. Currently defaults
+#             to 1000. (since 2.8)
 # Since: 2.6
 ##
 { 'struct': 'QCryptoBlockCreateOptionsLUKS',
@@ -193,7 +196,8 @@
             '*cipher-mode': 'QCryptoCipherMode',
             '*ivgen-alg': 'QCryptoIVGenAlgorithm',
             '*ivgen-hash-alg': 'QCryptoHashAlgorithm',
-            '*hash-alg': 'QCryptoHashAlgorithm'}}
+            '*hash-alg': 'QCryptoHashAlgorithm',
+            '*iter-time': 'int'}}
 
 
 ##