From 16dc58312cb8b29024996b6e413c368a99e85398 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 8 Feb 2018 14:22:56 +0100 Subject: [PATCH] Move PBKDF limits to crypto backend (to one place). --- lib/crypto_backend/crypto_backend.h | 7 ++++++ lib/crypto_backend/pbkdf_check.c | 36 ++++++++++++++++++++++++++--- lib/internal.h | 4 ---- lib/luks2/luks2_digest_pbkdf2.c | 7 +++++- lib/utils_benchmark.c | 7 +++++- lib/utils_pbkdf.c | 32 ++++++++++++++++--------- 6 files changed, 73 insertions(+), 20 deletions(-) diff --git a/lib/crypto_backend/crypto_backend.h b/lib/crypto_backend/crypto_backend.h index 9dd57e9b..a5c52656 100644 --- a/lib/crypto_backend/crypto_backend.h +++ b/lib/crypto_backend/crypto_backend.h @@ -57,6 +57,13 @@ int crypt_hmac_destroy(struct crypt_hmac *ctx); 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); +struct crypt_pbkdf_limits { + uint32_t min_iterations, max_iterations; + uint32_t min_memory, max_memory; + uint32_t min_parallel, max_parallel; +}; +int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *l); + /* PBKDF*/ int crypt_pbkdf(const char *kdf, const char *hash, const char *password, size_t password_length, diff --git a/lib/crypto_backend/pbkdf_check.c b/lib/crypto_backend/pbkdf_check.c index e5b6e9fb..d06e0f7c 100644 --- a/lib/crypto_backend/pbkdf_check.c +++ b/lib/crypto_backend/pbkdf_check.c @@ -34,6 +34,33 @@ #define BENCH_SAMPLES_FAST 3 #define BENCH_SAMPLES_SLOW 1 +/* These PBKDF2 limits must be never violated */ +int crypt_pbkdf_get_limits(const char *kdf, struct crypt_pbkdf_limits *limits) +{ + if (!kdf || !limits) + return -EINVAL; + + if (!strcmp(kdf, "pbkdf2")) { + limits->min_iterations = 1000; /* recommendation in NIST SP 800-132 */ + limits->max_iterations = UINT32_MAX; + limits->min_memory = 0; /* N/A */ + limits->max_memory = 0; /* N/A */ + limits->min_parallel = 0; /* N/A */ + limits->max_parallel = 0; /* N/A */ + return 0; + } else if (!strncmp(kdf, "argon2", 6)) { + limits->min_iterations = 4; + limits->max_iterations = UINT32_MAX; + limits->min_memory = 32; + limits->max_memory = 4*1024*1024; /* 4GiB */ + limits->min_parallel = 1; + limits->max_parallel = 4; + return 0; + } + + return -EINVAL; +} + static long time_ms(struct rusage *start, struct rusage *end) { int count_kernel_time = 0; @@ -362,8 +389,6 @@ out: return r; } -#define ARGON2_MIN_T_COST 4 - int crypt_pbkdf_perf(const char *kdf, const char *hash, const char *password, size_t password_size, const char *salt, size_t salt_size, @@ -372,11 +397,16 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash, uint32_t *iterations_out, uint32_t *memory_out, int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr) { + struct crypt_pbkdf_limits pbkdf_limits; int r = -EINVAL; if (!kdf || !iterations_out || !memory_out) return -EINVAL; + r = crypt_pbkdf_get_limits(kdf, &pbkdf_limits); + if (r < 0) + return r; + *memory_out = 0; *iterations_out = 0; @@ -388,7 +418,7 @@ int crypt_pbkdf_perf(const char *kdf, const char *hash, else if (!strncmp(kdf, "argon2", 6)) r = crypt_argon2_check(kdf, password, password_size, salt, salt_size, volume_key_size, - ARGON2_MIN_T_COST, max_memory_kb, + pbkdf_limits.min_iterations, max_memory_kb, parallel_threads, time_ms, iterations_out, memory_out, progress, usrptr); return r; diff --git a/lib/internal.h b/lib/internal.h index 995f55f4..b4629dec 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -51,10 +51,6 @@ #define DEFAULT_MEM_ALIGNMENT 4096 #define MAX_ERROR_LENGTH 512 -#define MAX_PBKDF_THREADS 4 -#define MAX_PBKDF_MEMORY 4*1024*1024 /* 4GiB */ -#define MIN_PBKDF2_ITERATIONS 1000 /* recommendation in NIST SP 800-132 */ - #define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); }) struct crypt_device; diff --git a/lib/luks2/luks2_digest_pbkdf2.c b/lib/luks2/luks2_digest_pbkdf2.c index d8bc6439..894d681d 100644 --- a/lib/luks2/luks2_digest_pbkdf2.c +++ b/lib/luks2/luks2_digest_pbkdf2.c @@ -98,6 +98,7 @@ static int PBKDF2_digest_store(struct crypt_device *cd, int r; char *base64_str; struct luks2_hdr *hdr; + struct crypt_pbkdf_limits pbkdf_limits; struct crypt_pbkdf_type pbkdf = { .type = CRYPT_KDF_PBKDF2, .hash = "sha256", @@ -110,8 +111,12 @@ static int PBKDF2_digest_store(struct crypt_device *cd, if (r < 0) return r; + r = crypt_pbkdf_get_limits(CRYPT_KDF_PBKDF2, &pbkdf_limits); + if (r < 0) + return r; + if (crypt_get_pbkdf(cd)->flags & CRYPT_PBKDF_NO_BENCHMARK) - pbkdf.iterations = MIN_PBKDF2_ITERATIONS; + pbkdf.iterations = pbkdf_limits.min_iterations; else { r = crypt_benchmark_pbkdf_internal(cd, &pbkdf, volume_key_len); if (r < 0) diff --git a/lib/utils_benchmark.c b/lib/utils_benchmark.c index 98515cca..592ce95a 100644 --- a/lib/utils_benchmark.c +++ b/lib/utils_benchmark.c @@ -289,6 +289,7 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd, struct crypt_pbkdf_type *pbkdf, size_t volume_key_size) { + struct crypt_pbkdf_limits pbkdf_limits; double PBKDF2_tmp; uint32_t ms_tmp; int r = -EINVAL; @@ -304,6 +305,10 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd, return -EINVAL; } + r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits); + if (r) + return r; + if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) { /* * For PBKDF2 it is enough to run benchmark for only 1 second @@ -326,7 +331,7 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd, PBKDF2_tmp = ((double)pbkdf->iterations * pbkdf->time_ms / 1000.); if (PBKDF2_tmp > (double)UINT32_MAX) return -EINVAL; - pbkdf->iterations = at_least((uint32_t)PBKDF2_tmp, MIN_PBKDF2_ITERATIONS); + pbkdf->iterations = at_least((uint32_t)PBKDF2_tmp, pbkdf_limits.min_iterations); } else { r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3, "0123456789abcdef0123456789abcdef", 32, diff --git a/lib/utils_pbkdf.c b/lib/utils_pbkdf.c index e113afa1..bcc77d2f 100644 --- a/lib/utils_pbkdf.c +++ b/lib/utils_pbkdf.c @@ -61,6 +61,7 @@ static uint32_t adjusted_phys_memory(void) int verify_pbkdf_params(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf) { + struct crypt_pbkdf_limits pbkdf_limits; const char *pbkdf_type; int r = 0; @@ -74,6 +75,10 @@ int verify_pbkdf_params(struct crypt_device *cd, return r; } + r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits); + if (r < 0) + return r; + if (crypt_get_type(cd) && !strcmp(crypt_get_type(cd), CRYPT_LUKS1) && strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) { @@ -87,9 +92,9 @@ int verify_pbkdf_params(struct crypt_device *cd, return -EINVAL; } if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK && - pbkdf->iterations < MIN_PBKDF2_ITERATIONS) { + pbkdf->iterations < pbkdf_limits.min_iterations) { log_err(cd, _("Forced iteration count is too low for %s (minimum is %u).\n"), - pbkdf_type, MIN_PBKDF2_ITERATIONS); + pbkdf_type, pbkdf_limits.min_iterations); return -EINVAL; } return 0; @@ -97,21 +102,21 @@ int verify_pbkdf_params(struct crypt_device *cd, /* TODO: properly define minimal iterations and also minimal memory values */ if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) { - if (pbkdf->iterations < 4) { + if (pbkdf->iterations < pbkdf_limits.min_iterations) { log_err(cd, _("Forced iteration count is too low for %s (minimum is %u).\n"), - pbkdf_type, 4); + pbkdf_type, pbkdf_limits.min_iterations); r = -EINVAL; } - if (pbkdf->max_memory_kb < 32) { + if (pbkdf->max_memory_kb < pbkdf_limits.min_memory) { log_err(cd, _("Forced memory cost is too low for %s (minimum is %u kilobytes).\n"), - pbkdf_type, 32); + pbkdf_type, pbkdf_limits.min_memory); r = -EINVAL; } } - if (pbkdf->max_memory_kb > MAX_PBKDF_MEMORY) { + if (pbkdf->max_memory_kb > pbkdf_limits.max_memory) { log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes).\n"), - MAX_PBKDF_MEMORY); + pbkdf_limits.max_memory); r = -EINVAL; } if (!pbkdf->max_memory_kb) { @@ -135,6 +140,7 @@ int init_pbkdf_type(struct crypt_device *cd, const char *dev_type) { struct crypt_pbkdf_type *cd_pbkdf = crypt_get_pbkdf(cd); + struct crypt_pbkdf_limits pbkdf_limits; const char *hash, *type; unsigned cpus; uint32_t old_flags, memory_kb; @@ -149,6 +155,10 @@ int init_pbkdf_type(struct crypt_device *cd, if (r) return r; + r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits); + if (r < 0) + return r; + /* * Crypto backend may be not initialized here, * cannot check if algorithms are really available. @@ -185,10 +195,10 @@ int init_pbkdf_type(struct crypt_device *cd, cd_pbkdf->max_memory_kb = pbkdf->max_memory_kb; cd_pbkdf->parallel_threads = pbkdf->parallel_threads; - if (cd_pbkdf->parallel_threads > MAX_PBKDF_THREADS) { + if (cd_pbkdf->parallel_threads > pbkdf_limits.max_parallel) { log_dbg("Maximum PBKDF threads is %d (requested %d).", - MAX_PBKDF_THREADS, cd_pbkdf->parallel_threads); - cd_pbkdf->parallel_threads = MAX_PBKDF_THREADS; + pbkdf_limits.max_parallel, cd_pbkdf->parallel_threads); + cd_pbkdf->parallel_threads = pbkdf_limits.max_parallel; } if (cd_pbkdf->parallel_threads) {