qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 1/6] crypto: make PBKDF iterations configurable for


From: Daniel P. Berrange
Subject: [Qemu-devel] [PATCH 1/6] crypto: make PBKDF iterations configurable for LUKS format
Date: Thu, 8 Sep 2016 17:27:22 +0100

As protection against bruteforcing passphrases, the PBKDF
algorithm is tuned by counting the number of iterations
needed to produce 1 second of running time. If the machine
that the image will be used on is much faster than the
machine where the image is created, it can be desirable
to raise the number of limits. This adds a new 'iter-time'
property that allows the user to choose the iteration
wallclock time.

Signed-off-by: Daniel P. Berrange <address@hidden>
---
 block/crypto.c      |  6 ++++++
 crypto/block-luks.c | 32 +++++++++++++++++++++++---------
 qapi/crypto.json    |  6 +++++-
 3 files changed, 34 insertions(+), 10 deletions(-)

diff --git a/block/crypto.c b/block/crypto.c
index 7f61e12..7aa7eb5 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 aba4455..a5d9ebc 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -917,8 +917,12 @@ qcrypto_block_luks_create(QCryptoBlock *block,
     const char *hash_alg;
     char *cipher_mode_spec = NULL;
     QCryptoCipherAlgorithm ivcipheralg = 0;
+    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;
     }
@@ -1064,7 +1068,7 @@ qcrypto_block_luks_create(QCryptoBlock *block,
     /* Determine how many iterations we need to hash the master
      * key, in order to have 1 second of compute time used
      */
-    luks->header.master_key_iterations =
+    iters = luks_opts.iter_time *
         qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
                                    masterkey, luks->header.key_bytes,
                                    luks->header.master_key_salt,
@@ -1074,15 +1078,19 @@ qcrypto_block_luks_create(QCryptoBlock *block,
         error_propagate(errp, local_err);
         goto error;
     }
-
+    /* iter_time was in millis, but count_iters reported for secs */
+    iters /= 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
      * in total time to check all keys */
-    luks->header.master_key_iterations /= 8;
+    iters /= 8;
+    if (iters > UINT32_MAX) {
+        error_setg(errp, "Too many PBKDF iterations for LUKS format");
+        goto error;
+    }
     luks->header.master_key_iterations = MAX(
-        luks->header.master_key_iterations,
-        QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);
+        iters, QCRYPTO_BLOCK_LUKS_MIN_MASTER_KEY_ITERS);
 
 
     /* Hash the master key, saving the result in the LUKS
@@ -1131,7 +1139,7 @@ qcrypto_block_luks_create(QCryptoBlock *block,
     /* Again we determine how many iterations are required to
      * hash the user password while consuming 1 second of compute
      * time */
-    luks->header.key_slots[0].iterations =
+    iters = luks_opts.iter_time *
         qcrypto_pbkdf2_count_iters(luks_opts.hash_alg,
                                    (uint8_t *)password, strlen(password),
                                    luks->header.key_slots[0].salt,
@@ -1141,12 +1149,18 @@ qcrypto_block_luks_create(QCryptoBlock *block,
         error_propagate(errp, local_err);
         goto error;
     }
+
+    /* iter_time was in millis, but count_iters reported for secs */
+    iters /= 1000;
     /* Why /= 2 ?  That matches cryptsetup, but there's no
      * explanation why they chose /= 2... */
-    luks->header.key_slots[0].iterations /= 2;
+    iters /= 2;
+    if (iters > UINT32_MAX) {
+        error_setg(errp, "Too many PBKDF iterations for LUKS format");
+        goto error;
+    }
     luks->header.key_slots[0].iterations = MAX(
-        luks->header.key_slots[0].iterations,
-        QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
+        iters, QCRYPTO_BLOCK_LUKS_MIN_SLOT_KEY_ITERS);
 
 
     /* Generate a key that we'll use to encrypt the master
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 34d2583..1527f4b 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'}}
 
 
 ##
-- 
2.7.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]