Add PBKDF2 benchmark.
authorMilan Broz <gmazyland@gmail.com>
Wed, 5 Dec 2012 19:35:42 +0000 (20:35 +0100)
committerMilan Broz <gmazyland@gmail.com>
Wed, 5 Dec 2012 19:35:42 +0000 (20:35 +0100)
lib/crypto_backend/crypto_backend.h
lib/crypto_backend/pbkdf_check.c
lib/libcryptsetup.h
lib/libcryptsetup.sym
lib/luks1/keymanage.c
lib/utils_benchmark.c
src/cryptsetup.c

index be5c6f0..0c71d9d 100644 (file)
@@ -56,7 +56,10 @@ enum { CRYPT_RND_NORMAL = 0, CRYPT_RND_KEY = 1, CRYPT_RND_SALT = 2 };
 int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
 
 /* PBKDF*/
-int crypt_pbkdf_check(const char *kdf, const char *hash, uint64_t *iter_secs);
+int crypt_pbkdf_check(const char *kdf, const char *hash,
+                     const char *password, size_t password_size,
+                     const char *salt, size_t salt_size,
+                     uint64_t *iter_secs);
 int crypt_pbkdf(const char *kdf, const char *hash,
                const char *password, size_t password_length,
                const char *salt, size_t salt_length,
index 086aa38..69f6bfb 100644 (file)
@@ -38,7 +38,10 @@ static long time_ms(struct rusage *start, struct rusage *end)
 }
 
 /* This code benchmarks PBKDF and returns iterations/second using specified hash */
-int crypt_pbkdf_check(const char *kdf, const char *hash, uint64_t *iter_secs)
+int crypt_pbkdf_check(const char *kdf, const char *hash,
+                     const char *password, size_t password_size,
+                     const char *salt, size_t salt_size,
+                     uint64_t *iter_secs)
 {
        struct rusage rstart, rend;
        int r = 0, step = 0;
@@ -54,7 +57,8 @@ int crypt_pbkdf_check(const char *kdf, const char *hash, uint64_t *iter_secs)
                if (getrusage(RUSAGE_SELF, &rstart) < 0)
                        return -EINVAL;
 
-               r = crypt_pbkdf(kdf, hash, "foo", 3, "bar", 3, &buf, 1, iterations);
+               r = crypt_pbkdf(kdf, hash, password, password_size, salt,
+                               salt_size, &buf, 1, iterations);
                if (r < 0)
                        return r;
 
index 0f19f03..04c53fb 100644 (file)
@@ -905,6 +905,15 @@ int crypt_benchmark(struct crypt_device *cd,
        double *encryption_mbs,
        double *decryption_mbs);
 
+int crypt_benchmark_kdf(struct crypt_device *cd,
+       const char *kdf,
+       const char *hash,
+       const char *password,
+       size_t password_size,
+       const char *salt,
+       size_t salt_size,
+       uint64_t *iterations_sec);
+
 /**
  * Get cipher used in device
  *
index 78bc281..801add6 100644 (file)
@@ -40,6 +40,7 @@ CRYPTSETUP_1.0 {
                crypt_status;
                crypt_dump;
                crypt_benchmark;
+               crypt_benchmark_kdf;
                crypt_get_cipher;
                crypt_get_cipher_mode;
                crypt_get_uuid;
index 3bd57ee..204484a 100644 (file)
@@ -598,21 +598,6 @@ int LUKS_write_phdr(struct luks_phdr *hdr,
        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 (crypt_pbkdf_check("pbkdf2", hashSpec, PBKDF2_per_sec) < 0) {
-                       log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"), 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 volume_key *vk,
                       const char *cipherName, const char *cipherMode, const char *hashSpec,
@@ -669,8 +654,13 @@ int LUKS_generate_phdr(struct luks_phdr *header,
                return r;
        }
 
-       if ((r = LUKS_PBKDF2_performance_check(header->hashSpec, PBKDF2_per_sec, ctx)))
+       r = crypt_benchmark_kdf(ctx, "pbkdf2", header->hashSpec,
+                               "foo", 3, "bar", 3, PBKDF2_per_sec);
+       if (r < 0) {
+               log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"),
+                       header->hashSpec);
                return r;
+       }
 
        /* Compute master key digest */
        iteration_time_ms /= 8;
@@ -760,8 +750,13 @@ int LUKS_set_key(unsigned int keyIndex,
 
        log_dbg("Calculating data for key slot %d", keyIndex);
 
-       if ((r = LUKS_PBKDF2_performance_check(hdr->hashSpec, PBKDF2_per_sec, ctx)))
+       r = crypt_benchmark_kdf(ctx, "pbkdf2", hdr->hashSpec,
+                               "foo", 3, "bar", 3, PBKDF2_per_sec);
+       if (r < 0) {
+               log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"),
+                       hdr->hashSpec);
                return r;
+       }
 
        /*
         * Avoid floating point operation
index 850ac7c..4ee0c03 100644 (file)
@@ -215,3 +215,33 @@ out:
        free(cp.iv);
        return r;
 }
+
+int crypt_benchmark_kdf(struct crypt_device *cd,
+       const char *kdf,
+       const char *hash,
+       const char *password,
+       size_t password_size,
+       const char *salt,
+       size_t salt_size,
+       uint64_t *iterations_sec)
+{
+       int r;
+
+       if (!iterations_sec)
+               return -EINVAL;
+
+       r = init_crypto(cd);
+       if (r < 0)
+               return r;
+
+       if (!strncmp(kdf, "pbkdf2", 6))
+               r = crypt_pbkdf_check(kdf, hash, password, password_size,
+                                     salt, salt_size, iterations_sec);
+       else
+               r = -EINVAL;
+
+       if (!r)
+               log_dbg("KDF %s, hash %s: %" PRIu64 " iterations per second.",
+                       kdf, hash, *iterations_sec);
+       return r;
+}
index e969373..6fb3f8e 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2004, Christophe Saout <christophe@saout.de>
  * Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
  * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2009-2012, Milan Broz
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -422,6 +423,21 @@ out:
        return r;
 }
 
+static int action_benchmark_kdf(const char *hash)
+{
+       uint64_t kdf_iters;
+       int r;
+
+       r = crypt_benchmark_kdf(NULL, "pbkdf2", hash, "foo", 3, "bar", 3,
+                               &kdf_iters);
+       if (r < 0)
+               log_std("PBKDF2-%-9s     N/A\n", hash);
+       else
+               log_std("PBKDF2-%-9s %7" PRIu64 " iterations per second\n",
+                       hash, kdf_iters);
+       return r;
+}
+
 static int action_benchmark(void)
 {
        static struct {
@@ -444,8 +460,6 @@ static int action_benchmark(void)
                { "twofish", "xts", 64, 16 },
                {  NULL, NULL, 0, 0 }
        };
-       const char *header = "# Tests are approximate using memory only (no storage IO).\n"
-                             "#  Algorithm | Key | Encryption | Decryption\n";
        char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
        double enc_mbr = 0, dec_mbr = 0;
        int key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS);
@@ -454,7 +468,10 @@ static int action_benchmark(void)
        char *c;
        int i, r;
 
-       if (opt_cipher) {
+       log_std("# Tests are approximate using memory only (no storage IO).\n");
+       if (opt_hash) {
+               r = action_benchmark_kdf(opt_hash);
+       } else if (opt_cipher) {
                r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
                if (r < 0) {
                        log_err(_("No known cipher specification pattern detected.\n"));
@@ -473,7 +490,7 @@ static int action_benchmark(void)
                                    key_size / 8, iv_size, buffer_size,
                                    &enc_mbr, &dec_mbr);
                if (!r) {
-                       log_std("%s", header);
+                       log_std("#  Algorithm | Key | Encryption | Decryption\n");
                        strncat(cipher, "-", MAX_CIPHER_LEN);
                        strncat(cipher, cipher_mode, MAX_CIPHER_LEN);
                        log_std("%12s  %4db  %5.1f MiB/s  %5.1f MiB/s\n",
@@ -481,6 +498,11 @@ static int action_benchmark(void)
                } else if (r == -ENOENT)
                        log_err(_("Cipher %s is not available.\n"), opt_cipher);
        } else {
+               action_benchmark_kdf("sha1");
+               action_benchmark_kdf("sha256");
+               action_benchmark_kdf("sha512");
+               action_benchmark_kdf("ripemd160");
+               action_benchmark_kdf("whirlpool");
                for (i = 0; bciphers[i].cipher; i++) {
                        r = crypt_benchmark(NULL, bciphers[i].cipher, bciphers[i].mode,
                                            bciphers[i].key_size, bciphers[i].iv_size,
@@ -490,7 +512,7 @@ static int action_benchmark(void)
                        if (r == -ENOENT)
                                skipped++;
                        if (i == 0)
-                               log_std("%s", header);
+                               log_std("#  Algorithm | Key | Encryption | Decryption\n");
 
                        snprintf(cipher, MAX_CIPHER_LEN, "%s-%s",
                                 bciphers[i].cipher, bciphers[i].mode);