Files
cryptsetup/lib/utils_pbkdf.c
Milan Broz 580f0f1a28 Add some FIPS mode workarounds.
We cannot (yet) use Argon2 in FIPS mode, hack scripts and library
to use PBKDF2 or skip tests and fix tests to run in FIPS mode.
2019-01-24 17:04:13 +01:00

330 lines
8.9 KiB
C

/*
* utils_pbkdf - PBKDF ssettings for libcryptsetup
*
* Copyright (C) 2009-2018, Red Hat, Inc. All rights reserved.
* Copyright (C) 2009-2018, Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
#include <errno.h>
#include "internal.h"
const struct crypt_pbkdf_type default_pbkdf2 = {
.type = CRYPT_KDF_PBKDF2,
.hash = DEFAULT_LUKS1_HASH,
.time_ms = DEFAULT_LUKS1_ITER_TIME
};
const struct crypt_pbkdf_type default_argon2i = {
.type = CRYPT_KDF_ARGON2I,
.hash = DEFAULT_LUKS1_HASH,
.time_ms = DEFAULT_LUKS2_ITER_TIME,
.max_memory_kb = DEFAULT_LUKS2_MEMORY_KB,
.parallel_threads = DEFAULT_LUKS2_PARALLEL_THREADS
};
const struct crypt_pbkdf_type default_argon2id = {
.type = CRYPT_KDF_ARGON2ID,
.hash = DEFAULT_LUKS1_HASH,
.time_ms = DEFAULT_LUKS2_ITER_TIME,
.max_memory_kb = DEFAULT_LUKS2_MEMORY_KB,
.parallel_threads = DEFAULT_LUKS2_PARALLEL_THREADS
};
const struct crypt_pbkdf_type *crypt_get_pbkdf_type_params(const char *pbkdf_type)
{
if (!pbkdf_type)
return NULL;
if (!strcmp(pbkdf_type, CRYPT_KDF_PBKDF2))
return &default_pbkdf2;
else if (!strcmp(pbkdf_type, CRYPT_KDF_ARGON2I))
return &default_argon2i;
else if (!strcmp(pbkdf_type, CRYPT_KDF_ARGON2ID))
return &default_argon2id;
return NULL;
}
static uint32_t adjusted_phys_memory(void)
{
uint64_t memory_kb = crypt_getphysmemory_kb();
/* Ignore bogus value */
if (memory_kb < (128 * 1024) || memory_kb > UINT32_MAX)
return DEFAULT_LUKS2_MEMORY_KB;
/*
* Never use more than half of physical memory.
* OOM killer is too clever...
*/
memory_kb /= 2;
return memory_kb;
}
/*
* PBKDF configuration interface
*/
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;
r = init_crypto(cd);
if (r < 0)
return r;
if (!pbkdf->type ||
(!pbkdf->hash && !strcmp(pbkdf->type, "pbkdf2")))
return -EINVAL;
if (!pbkdf->time_ms && !(pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK)) {
log_err(cd, _("Requested PBKDF target time cannot be zero."));
return -EINVAL;
}
r = crypt_parse_pbkdf(pbkdf->type, &pbkdf_type);
if (r < 0) {
log_err(cd, _("Unknown PBKDF type %s."), pbkdf->type);
return r;
}
if (pbkdf->hash && crypt_hash_size(pbkdf->hash) < 0) {
log_err(cd, _("Requested hash %s is not supported."), pbkdf->hash);
return -EINVAL;
}
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)) {
log_err(cd, _("Requested PBKDF type is not supported for LUKS1."));
return -EINVAL;
}
if (!strcmp(pbkdf_type, CRYPT_KDF_PBKDF2)) {
if (pbkdf->max_memory_kb || pbkdf->parallel_threads) {
log_err(cd, _("PBKDF max memory or parallel threads must not be set with pbkdf2."));
return -EINVAL;
}
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK &&
pbkdf->iterations < pbkdf_limits.min_iterations) {
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u)."),
pbkdf_type, pbkdf_limits.min_iterations);
return -EINVAL;
}
return 0;
}
/* TODO: properly define minimal iterations and also minimal memory values */
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
if (pbkdf->iterations < pbkdf_limits.min_iterations) {
log_err(cd, _("Forced iteration count is too low for %s (minimum is %u)."),
pbkdf_type, pbkdf_limits.min_iterations);
r = -EINVAL;
}
if (pbkdf->max_memory_kb < pbkdf_limits.min_memory) {
log_err(cd, _("Forced memory cost is too low for %s (minimum is %u kilobytes)."),
pbkdf_type, pbkdf_limits.min_memory);
r = -EINVAL;
}
}
if (pbkdf->max_memory_kb > pbkdf_limits.max_memory) {
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes)."),
pbkdf_limits.max_memory);
r = -EINVAL;
}
if (!pbkdf->max_memory_kb) {
log_err(cd, _("Requested maximum PBKDF memory cannot be zero."));
r = -EINVAL;
}
if (!pbkdf->parallel_threads) {
log_err(cd, _("Requested PBKDF parallel threads cannot be zero."));
r = -EINVAL;
}
return r;
}
int init_pbkdf_type(struct crypt_device *cd,
const struct crypt_pbkdf_type *pbkdf,
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;
int r;
if (crypt_fips_mode()) {
if (pbkdf && strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
log_err(cd, "Only PBKDF2 is supported in FIPS mode.");
return -EINVAL;
}
if (!pbkdf)
pbkdf = crypt_get_pbkdf_type_params(CRYPT_KDF_PBKDF2);
}
if (!pbkdf && dev_type && !strcmp(dev_type, CRYPT_LUKS2))
pbkdf = crypt_get_pbkdf_type_params(DEFAULT_LUKS2_PBKDF);
else if (!pbkdf)
pbkdf = crypt_get_pbkdf_type_params(CRYPT_KDF_PBKDF2);
r = verify_pbkdf_params(cd, pbkdf);
if (r)
return r;
r = crypt_pbkdf_get_limits(pbkdf->type, &pbkdf_limits);
if (r < 0)
return r;
type = strdup(pbkdf->type);
hash = pbkdf->hash ? strdup(pbkdf->hash) : NULL;
if (!type || (!hash && pbkdf->hash)) {
free(CONST_CAST(void*)type);
free(CONST_CAST(void*)hash);
return -ENOMEM;
}
free(CONST_CAST(void*)cd_pbkdf->type);
free(CONST_CAST(void*)cd_pbkdf->hash);
cd_pbkdf->type = type;
cd_pbkdf->hash = hash;
old_flags = cd_pbkdf->flags;
cd_pbkdf->flags = pbkdf->flags;
/* Reset iteration count so benchmark must run again. */
if (cd_pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK)
cd_pbkdf->iterations = pbkdf->iterations;
else
cd_pbkdf->iterations = 0;
if (old_flags & CRYPT_PBKDF_ITER_TIME_SET)
cd_pbkdf->flags |= CRYPT_PBKDF_ITER_TIME_SET;
else
cd_pbkdf->time_ms = pbkdf->time_ms;
cd_pbkdf->max_memory_kb = pbkdf->max_memory_kb;
cd_pbkdf->parallel_threads = pbkdf->parallel_threads;
if (cd_pbkdf->parallel_threads > pbkdf_limits.max_parallel) {
log_dbg(cd, "Maximum PBKDF threads is %d (requested %d).",
pbkdf_limits.max_parallel, cd_pbkdf->parallel_threads);
cd_pbkdf->parallel_threads = pbkdf_limits.max_parallel;
}
if (cd_pbkdf->parallel_threads) {
cpus = crypt_cpusonline();
if (cd_pbkdf->parallel_threads > cpus) {
log_dbg(cd, "Only %u active CPUs detected, "
"PBKDF threads decreased from %d to %d.",
cpus, cd_pbkdf->parallel_threads, cpus);
cd_pbkdf->parallel_threads = cpus;
}
}
if (cd_pbkdf->max_memory_kb) {
memory_kb = adjusted_phys_memory();
if (cd_pbkdf->max_memory_kb > memory_kb) {
log_dbg(cd, "Not enough physical memory detected, "
"PBKDF max memory decreased from %dkB to %dkB.",
cd_pbkdf->max_memory_kb, memory_kb);
cd_pbkdf->max_memory_kb = memory_kb;
}
}
log_dbg(cd, "PBKDF %s, hash %s, time_ms %u (iterations %u), max_memory_kb %u, parallel_threads %u.",
cd_pbkdf->type ?: "(none)", cd_pbkdf->hash ?: "(none)", cd_pbkdf->time_ms,
cd_pbkdf->iterations, cd_pbkdf->max_memory_kb, cd_pbkdf->parallel_threads);
return 0;
}
/* Libcryptsetup API */
int crypt_set_pbkdf_type(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf)
{
if (!cd)
return -EINVAL;
if (!pbkdf)
log_dbg(cd, "Resetting pbkdf type to default");
crypt_get_pbkdf(cd)->flags = 0;
return init_pbkdf_type(cd, pbkdf, crypt_get_type(cd));
}
const struct crypt_pbkdf_type *crypt_get_pbkdf_type(struct crypt_device *cd)
{
if (!cd)
return NULL;
return crypt_get_pbkdf(cd)->type ? crypt_get_pbkdf(cd) : NULL;
}
const struct crypt_pbkdf_type *crypt_get_pbkdf_default(const char *type)
{
if (!type)
return NULL;
if (!strcmp(type, CRYPT_LUKS1) || crypt_fips_mode())
return crypt_get_pbkdf_type_params(CRYPT_KDF_PBKDF2);
else if (!strcmp(type, CRYPT_LUKS2))
return crypt_get_pbkdf_type_params(DEFAULT_LUKS2_PBKDF);
return NULL;
}
void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_ms)
{
struct crypt_pbkdf_type *pbkdf;
uint32_t old_time_ms;
if (!cd || iteration_time_ms > UINT32_MAX)
return;
pbkdf = crypt_get_pbkdf(cd);
old_time_ms = pbkdf->time_ms;
pbkdf->time_ms = (uint32_t)iteration_time_ms;
if (pbkdf->type && verify_pbkdf_params(cd, pbkdf)) {
pbkdf->time_ms = old_time_ms;
log_dbg(cd, "Invalid iteration time.");
return;
}
pbkdf->flags |= CRYPT_PBKDF_ITER_TIME_SET;
/* iterations must be benchmarked now */
pbkdf->flags &= ~(CRYPT_PBKDF_NO_BENCHMARK);
pbkdf->iterations = 0;
log_dbg(cd, "Iteration time set to %" PRIu64 " milliseconds.", iteration_time_ms);
}