Move PBKDF limits to crypto backend (to one place).

This commit is contained in:
Milan Broz
2018-02-08 14:22:56 +01:00
parent 169bd9db5e
commit 16dc58312c
6 changed files with 73 additions and 20 deletions

View File

@@ -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 }; 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); 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*/ /* PBKDF*/
int crypt_pbkdf(const char *kdf, const char *hash, int crypt_pbkdf(const char *kdf, const char *hash,
const char *password, size_t password_length, const char *password, size_t password_length,

View File

@@ -34,6 +34,33 @@
#define BENCH_SAMPLES_FAST 3 #define BENCH_SAMPLES_FAST 3
#define BENCH_SAMPLES_SLOW 1 #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) static long time_ms(struct rusage *start, struct rusage *end)
{ {
int count_kernel_time = 0; int count_kernel_time = 0;
@@ -362,8 +389,6 @@ out:
return r; return r;
} }
#define ARGON2_MIN_T_COST 4
int crypt_pbkdf_perf(const char *kdf, const char *hash, int crypt_pbkdf_perf(const char *kdf, const char *hash,
const char *password, size_t password_size, const char *password, size_t password_size,
const char *salt, size_t salt_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, uint32_t *iterations_out, uint32_t *memory_out,
int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr) int (*progress)(uint32_t time_ms, void *usrptr), void *usrptr)
{ {
struct crypt_pbkdf_limits pbkdf_limits;
int r = -EINVAL; int r = -EINVAL;
if (!kdf || !iterations_out || !memory_out) if (!kdf || !iterations_out || !memory_out)
return -EINVAL; return -EINVAL;
r = crypt_pbkdf_get_limits(kdf, &pbkdf_limits);
if (r < 0)
return r;
*memory_out = 0; *memory_out = 0;
*iterations_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)) else if (!strncmp(kdf, "argon2", 6))
r = crypt_argon2_check(kdf, password, password_size, r = crypt_argon2_check(kdf, password, password_size,
salt, salt_size, volume_key_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, parallel_threads, time_ms, iterations_out,
memory_out, progress, usrptr); memory_out, progress, usrptr);
return r; return r;

View File

@@ -51,10 +51,6 @@
#define DEFAULT_MEM_ALIGNMENT 4096 #define DEFAULT_MEM_ALIGNMENT 4096
#define MAX_ERROR_LENGTH 512 #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); }) #define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
struct crypt_device; struct crypt_device;

View File

@@ -98,6 +98,7 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
int r; int r;
char *base64_str; char *base64_str;
struct luks2_hdr *hdr; struct luks2_hdr *hdr;
struct crypt_pbkdf_limits pbkdf_limits;
struct crypt_pbkdf_type pbkdf = { struct crypt_pbkdf_type pbkdf = {
.type = CRYPT_KDF_PBKDF2, .type = CRYPT_KDF_PBKDF2,
.hash = "sha256", .hash = "sha256",
@@ -110,8 +111,12 @@ static int PBKDF2_digest_store(struct crypt_device *cd,
if (r < 0) if (r < 0)
return r; 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) if (crypt_get_pbkdf(cd)->flags & CRYPT_PBKDF_NO_BENCHMARK)
pbkdf.iterations = MIN_PBKDF2_ITERATIONS; pbkdf.iterations = pbkdf_limits.min_iterations;
else { else {
r = crypt_benchmark_pbkdf_internal(cd, &pbkdf, volume_key_len); r = crypt_benchmark_pbkdf_internal(cd, &pbkdf, volume_key_len);
if (r < 0) if (r < 0)

View File

@@ -289,6 +289,7 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
struct crypt_pbkdf_type *pbkdf, struct crypt_pbkdf_type *pbkdf,
size_t volume_key_size) size_t volume_key_size)
{ {
struct crypt_pbkdf_limits pbkdf_limits;
double PBKDF2_tmp; double PBKDF2_tmp;
uint32_t ms_tmp; uint32_t ms_tmp;
int r = -EINVAL; int r = -EINVAL;
@@ -304,6 +305,10 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
return -EINVAL; return -EINVAL;
} }
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
if (r)
return r;
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) { if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
/* /*
* For PBKDF2 it is enough to run benchmark for only 1 second * 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.); PBKDF2_tmp = ((double)pbkdf->iterations * pbkdf->time_ms / 1000.);
if (PBKDF2_tmp > (double)UINT32_MAX) if (PBKDF2_tmp > (double)UINT32_MAX)
return -EINVAL; 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 { } else {
r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3, r = crypt_benchmark_pbkdf(cd, pbkdf, "foo", 3,
"0123456789abcdef0123456789abcdef", 32, "0123456789abcdef0123456789abcdef", 32,

View File

@@ -61,6 +61,7 @@ static uint32_t adjusted_phys_memory(void)
int verify_pbkdf_params(struct crypt_device *cd, int verify_pbkdf_params(struct crypt_device *cd,
const struct crypt_pbkdf_type *pbkdf) const struct crypt_pbkdf_type *pbkdf)
{ {
struct crypt_pbkdf_limits pbkdf_limits;
const char *pbkdf_type; const char *pbkdf_type;
int r = 0; int r = 0;
@@ -74,6 +75,10 @@ int verify_pbkdf_params(struct crypt_device *cd,
return r; return r;
} }
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
if (r < 0)
return r;
if (crypt_get_type(cd) && if (crypt_get_type(cd) &&
!strcmp(crypt_get_type(cd), CRYPT_LUKS1) && !strcmp(crypt_get_type(cd), CRYPT_LUKS1) &&
strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) { strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) {
@@ -87,9 +92,9 @@ int verify_pbkdf_params(struct crypt_device *cd,
return -EINVAL; return -EINVAL;
} }
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK && 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"), 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 -EINVAL;
} }
return 0; return 0;
@@ -97,21 +102,21 @@ int verify_pbkdf_params(struct crypt_device *cd,
/* TODO: properly define minimal iterations and also minimal memory values */ /* TODO: properly define minimal iterations and also minimal memory values */
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) { 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"), 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; 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"), 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; 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"), 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; r = -EINVAL;
} }
if (!pbkdf->max_memory_kb) { if (!pbkdf->max_memory_kb) {
@@ -135,6 +140,7 @@ int init_pbkdf_type(struct crypt_device *cd,
const char *dev_type) const char *dev_type)
{ {
struct crypt_pbkdf_type *cd_pbkdf = crypt_get_pbkdf(cd); struct crypt_pbkdf_type *cd_pbkdf = crypt_get_pbkdf(cd);
struct crypt_pbkdf_limits pbkdf_limits;
const char *hash, *type; const char *hash, *type;
unsigned cpus; unsigned cpus;
uint32_t old_flags, memory_kb; uint32_t old_flags, memory_kb;
@@ -149,6 +155,10 @@ int init_pbkdf_type(struct crypt_device *cd,
if (r) if (r)
return r; return r;
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
if (r < 0)
return r;
/* /*
* Crypto backend may be not initialized here, * Crypto backend may be not initialized here,
* cannot check if algorithms are really available. * 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->max_memory_kb = pbkdf->max_memory_kb;
cd_pbkdf->parallel_threads = pbkdf->parallel_threads; 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).", log_dbg("Maximum PBKDF threads is %d (requested %d).",
MAX_PBKDF_THREADS, cd_pbkdf->parallel_threads); pbkdf_limits.max_parallel, cd_pbkdf->parallel_threads);
cd_pbkdf->parallel_threads = MAX_PBKDF_THREADS; cd_pbkdf->parallel_threads = pbkdf_limits.max_parallel;
} }
if (cd_pbkdf->parallel_threads) { if (cd_pbkdf->parallel_threads) {