Change in iterations counts:
authorMilan Broz <gmazyland@gmail.com>
Wed, 30 Dec 2009 19:02:44 +0000 (19:02 +0000)
committerMilan Broz <gmazyland@gmail.com>
Wed, 30 Dec 2009 19:02:44 +0000 (19:02 +0000)
  * Fix key slot iteration count calculation (small -i value was the same as default).
  * The slot and key digest iteration minimun is now 1000.
  * The key digest iteration # is calculated from iteration time (approx 1/8 of that).

If something very strange happens, and the generated key is not completely random
(wrong RNG), attacker can skip the whole kesylot area processing and try to
brute force key according to limited set of keys.

The iteration time (default, inherited from slot iteration time, is cca 120ms)
can make this attack slower, if not impossible.

Note, that this is just theorethic problem, anyway it is better to be prepared
if possible:-)

git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@159 36d66b0a-2a48-0410-832c-cd162a569da5

ChangeLog
lib/internal.h
lib/setup.c
luks/keymanage.c
luks/luks.h

index 02e5ebc..55c015e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2009-12-30  Milan Broz  <mbroz@redhat.com>
+       * Fix key slot iteration count calculation (small -i value was the same as default).
+       * The slot and key digest iteration minimun is now 1000.
+       * The key digest iteration # is calculated from iteration time (approx 1/8 of that).
+
 2009-12-11  Milan Broz  <mbroz@redhat.com>
        * Fix error handling during reading passhrase.
 
index 50529c4..1c16f16 100644 (file)
@@ -25,7 +25,7 @@
 
 #define CRYPT_FLAG_PRIVATE_MASK ((unsigned int)-1 << 24)
 
-#define at_least_one(a) ({ __typeof__(a) __at_least_one=(a); (__at_least_one)?__at_least_one:1; })
+#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
 
 struct hash_type {
        char            *name;
index 9f69d07..e66fcaf 100644 (file)
@@ -1101,7 +1101,8 @@ static int _crypt_format_luks1(struct crypt_device *cd,
        r = LUKS_generate_phdr(&cd->hdr, cd->volume_key, cipher, cipher_mode,
                               (params && params->hash) ? params->hash : "sha1",
                               uuid, LUKS_STRIPES,
-                              params ? params->data_alignment: DEFAULT_ALIGNMENT, cd);
+                              params ? params->data_alignment: DEFAULT_ALIGNMENT,
+                              cd->iteration_time, &cd->PBKDF2_per_sec, cd);
        if(r < 0)
                return r;
 
index 63700da..2533e4a 100644 (file)
@@ -385,11 +385,28 @@ int LUKS_write_phdr(const char *device,
        return r;
 }
 
+static int LUKS_PBKDF2_performance_check(const char *hashSpec,
+                                        uint64_t *PBKDF2_per_sec,
+                                        struct crypt_device *ctx)
+{
+       if (!*PBKDF2_per_sec) {
+               if (PBKDF2_performance_check(hashSpec, PBKDF2_per_sec) < 0) {
+                       log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s)."), hashSpec);
+                       return -EINVAL;
+               }
+               log_dbg("PBKDF2: %" PRIu64 " iterations per second using hash %s.", *PBKDF2_per_sec, hashSpec);
+       }
+
+       return 0;
+}
+
 int LUKS_generate_phdr(struct luks_phdr *header,
                       const struct luks_masterkey *mk,
                       const char *cipherName, const char *cipherMode, const char *hashSpec,
                       const char *uuid, unsigned int stripes,
                       unsigned int alignPayload,
+                      uint32_t iteration_time_ms,
+                      uint64_t *PBKDF2_per_sec,
                       struct crypt_device *ctx)
 {
        unsigned int i=0;
@@ -423,8 +440,14 @@ int LUKS_generate_phdr(struct luks_phdr *header,
                return r;
        }
 
+       if ((r = LUKS_PBKDF2_performance_check(header->hashSpec, PBKDF2_per_sec, ctx)))
+               return r;
+
        /* Compute master key digest */
-       header->mkDigestIterations = LUKS_MKD_ITER;
+       iteration_time_ms /= 8;
+       header->mkDigestIterations = at_least((uint32_t)(*PBKDF2_per_sec/1024) * iteration_time_ms,
+                                             LUKS_MKD_ITERATIONS_MIN);
+
        r = PBKDF2_HMAC(header->hashSpec,mk->key,mk->keyLength,
                        header->mkDigestSalt,LUKS_SALTSIZE,
                        header->mkDigestIterations,
@@ -454,7 +477,8 @@ int LUKS_generate_phdr(struct luks_phdr *header,
                uuid_generate(partitionUuid);
         uuid_unparse(partitionUuid, header->uuid);
 
-       log_dbg("Data offset %d, UUID %s", header->payloadOffset, header->uuid);
+       log_dbg("Data offset %d, UUID %s, digest iterations %" PRIu32,
+               header->payloadOffset, header->uuid, header->mkDigestIterations);
 
        return 0;
 }
@@ -469,6 +493,7 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
        char derivedKey[hdr->keyBytes];
        char *AfKey;
        unsigned int AFEKSize;
+       uint64_t PBKDF2_temp;
        int r;
 
        if(hdr->keyblock[keyIndex].active != LUKS_KEY_DISABLED) {
@@ -484,17 +509,20 @@ int LUKS_set_key(const char *device, unsigned int keyIndex,
 
        log_dbg("Calculating data for key slot %d", keyIndex);
 
-       if (!*PBKDF2_per_sec) {
-               if (PBKDF2_performance_check(hdr->hashSpec, PBKDF2_per_sec) < 0) {
-                       log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s)."), hdr->hashSpec);
-                       return -EINVAL;
-               }
-               log_dbg("PBKDF2: %" PRIu64 " iterations per second using hash %s.", *PBKDF2_per_sec, hdr->hashSpec);
-       }
+       if ((r = LUKS_PBKDF2_performance_check(hdr->hashSpec, PBKDF2_per_sec, ctx)))
+               return r;
+
+       /*
+        * Avoid floating point operation
+        * Final iteration count is at least LUKS_SLOT_ITERATIONS_MIN
+        */
+       PBKDF2_temp = (*PBKDF2_per_sec / 2) * (uint64_t)iteration_time_ms;
+       PBKDF2_temp /= 1024;
+       if (PBKDF2_temp > UINT32_MAX)
+               PBKDF2_temp = UINT32_MAX;
+       hdr->keyblock[keyIndex].passwordIterations = at_least((uint32_t)PBKDF2_temp,
+                                                             LUKS_SLOT_ITERATIONS_MIN);
 
-       /* Avoid floating point operation - don't tell anyone that second have no 1024 miliseconds :-) */
-       iteration_time_ms = at_least_one(iteration_time_ms / 1024);
-       hdr->keyblock[keyIndex].passwordIterations = at_least_one((uint32_t)(*PBKDF2_per_sec/2) * iteration_time_ms);
        log_dbg("Key slot %d use %d password iterations.", keyIndex, hdr->keyblock[keyIndex].passwordIterations);
 
        r = getRandom(hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE);
index a395173..8b49093 100644 (file)
 #define LUKS_SALTSIZE 32
 #define LUKS_NUMKEYS 8
 
-// Numbers of iterations for the master key digest
-#define LUKS_MKD_ITER 10
-
-// LUKS_KT defines Key types
+// Minimal number of iterations
+#define LUKS_MKD_ITERATIONS_MIN  1000
+#define LUKS_SLOT_ITERATIONS_MIN 1000
 
 #define LUKS_KEY_DISABLED_OLD 0
 #define LUKS_KEY_ENABLED_OLD 0xCAFE
@@ -29,7 +28,6 @@
 #define LUKS_STRIPES 4000
 
 // partition header starts with magic
-
 #define LUKS_MAGIC {'L','U','K','S', 0xba, 0xbe};
 #define LUKS_MAGIC_L 6
 
@@ -93,6 +91,8 @@ int LUKS_generate_phdr(
        const char *uuid,
        unsigned int stripes,
        unsigned int alignPayload,
+       uint32_t iteration_time_ms,
+       uint64_t *PBKDF2_per_sec,
        struct crypt_device *ctx);
 
 int LUKS_read_phdr(