Commit 4609fd87 authored by Milan Broz's avatar Milan Broz

Fix PBKDF2 iteration benchmark for longer key sizes.

The previous PBKDF2 benchmark code did not take into account
output key length.
For SHA1 (with 160-bits output) and 256-bit keys (and longer)
it means that the final value was higher than it should be.

For other hash algorithms (like SHA256 or SHA512) it caused
that iteration count was smaller (in comparison to SHA1) than
expected for the requested time period.

This patch fixes the code to use key size for the formatted device
(or default LUKS key size if running in informational benchmark mode).

Thanks to A.Visconti, S.Bossi, A.Calo and H.Ragab
(http://www.club.di.unimi.it/) for point this out.
(Based on "What users should know about Full Disk Encryption
based on LUKS" paper to be presented on CANS2015).
parent 9e90d914
......@@ -58,9 +58,9 @@ int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
/* PBKDF*/
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);
const char *password, size_t password_length,
const char *salt, size_t salt_length,
size_t key_length, 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,
......
......@@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
......@@ -52,31 +53,39 @@ 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,
const char *password, size_t password_size,
const char *salt, size_t salt_size,
uint64_t *iter_secs)
const char *password, size_t password_length,
const char *salt, size_t salt_length,
size_t key_length, uint64_t *iter_secs)
{
struct rusage rstart, rend;
int r = 0, step = 0;
long ms = 0;
char buf;
char *key = NULL;
unsigned int iterations;
if (!kdf || !hash)
if (!kdf || !hash || key_length <= 0)
return -EINVAL;
key = malloc(key_length);
if (!key)
return -ENOMEM;
iterations = 1 << 15;
while (ms < 500) {
if (getrusage(RUSAGE_SELF, &rstart) < 0)
return -EINVAL;
if (getrusage(RUSAGE_SELF, &rstart) < 0) {
r = -EINVAL;
goto out;
}
r = crypt_pbkdf(kdf, hash, password, password_size, salt,
salt_size, &buf, 1, iterations);
r = crypt_pbkdf(kdf, hash, password, password_length, salt,
salt_length, key, key_length, iterations);
if (r < 0)
return r;
goto out;
if (getrusage(RUSAGE_SELF, &rend) < 0)
return -EINVAL;
if (getrusage(RUSAGE_SELF, &rend) < 0) {
r = -EINVAL;
goto out;
}
ms = time_ms(&rstart, &rend);
if (ms > 500)
......@@ -91,11 +100,18 @@ int crypt_pbkdf_check(const char *kdf, const char *hash,
else
iterations <<= 1;
if (++step > 10 || !iterations)
return -EINVAL;
if (++step > 10 || !iterations) {
r = -EINVAL;
goto out;
}
}
if (iter_secs)
*iter_secs = (iterations * 1000) / ms;
out:
if (key) {
crypt_backend_memzero(key, key_length);
free(key);
}
return r;
}
......@@ -804,7 +804,7 @@ int LUKS_set_key(unsigned int keyIndex,
* 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 = *PBKDF2_per_sec * (uint64_t)iteration_time_ms;
PBKDF2_temp /= 1024;
if (PBKDF2_temp > UINT32_MAX)
PBKDF2_temp = UINT32_MAX;
......
......@@ -240,7 +240,7 @@ int crypt_benchmark_kdf(struct crypt_device *cd,
size_t salt_size,
uint64_t *iterations_sec)
{
int r;
int r, key_length = 0;
if (!iterations_sec)
return -EINVAL;
......@@ -249,14 +249,21 @@ int crypt_benchmark_kdf(struct crypt_device *cd,
if (r < 0)
return r;
// FIXME: this should be in KDF check API parameters later
if (cd)
key_length = crypt_get_volume_key_size(cd);
if (key_length == 0)
key_length = DEFAULT_LUKS1_KEYBITS / 8;
if (!strncmp(kdf, "pbkdf2", 6))
r = crypt_pbkdf_check(kdf, hash, password, password_size,
salt, salt_size, iterations_sec);
salt, salt_size, key_length, iterations_sec);
else
r = -EINVAL;
if (!r)
log_dbg("KDF %s, hash %s: %" PRIu64 " iterations per second.",
kdf, hash, *iterations_sec);
log_dbg("KDF %s, hash %s: %" PRIu64 " iterations per second (%d-bits key).",
kdf, hash, *iterations_sec, key_length * 8);
return r;
}
......@@ -491,8 +491,8 @@ static int action_benchmark_kdf(const char *hash)
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);
log_std("PBKDF2-%-9s %7" PRIu64 " iterations per second for %d-bit key\n",
hash, kdf_iters, DEFAULT_LUKS1_KEYBITS);
return r;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment