mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Change PBKDF insterface to allow forced iterations (time cost) count.
Also move functions to separate utils_pbkdf.c file. PBKDF can be now set for any context. TODO: new setting is not covered by tests.
This commit is contained in:
@@ -63,6 +63,7 @@ libcryptsetup_la_SOURCES = \
|
||||
utils_device.c \
|
||||
utils_keyring.c \
|
||||
utils_keyring.h \
|
||||
utils_pbkdf.c \
|
||||
libdevmapper.c \
|
||||
utils_dm.h \
|
||||
volumekey.c \
|
||||
|
||||
@@ -66,6 +66,12 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
|
||||
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength);
|
||||
void crypt_free_volume_key(struct volume_key *vk);
|
||||
|
||||
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
|
||||
int init_pbkdf_type(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf,
|
||||
const char *dev_type);
|
||||
int verify_pbkdf_params(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf);
|
||||
int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
struct crypt_pbkdf_type *pbkdf,
|
||||
size_t volume_key_size);
|
||||
|
||||
@@ -155,15 +155,6 @@ void crypt_set_confirm_callback(struct crypt_device *cd,
|
||||
int (*confirm)(const char *msg, void *usrptr),
|
||||
void *usrptr);
|
||||
|
||||
/**
|
||||
* Set how long should cryptsetup iterate in PBKDF2 function.
|
||||
* Default value heads towards the iterations which takes around 1 second.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param iteration_time_ms the time in ms
|
||||
*/
|
||||
void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_ms);
|
||||
|
||||
/**
|
||||
* Set data device
|
||||
* For LUKS it is encrypted data device when LUKS header is separated.
|
||||
@@ -216,9 +207,15 @@ struct crypt_pbkdf_type {
|
||||
uint32_t iterations; /**< Iterations, 0 or benchmarked value. */
|
||||
uint32_t max_memory_kb; /**< Requested or benchmarked memory cost [kilobytes] */
|
||||
uint32_t parallel_threads;/**< Requested parallel cost [threads] */
|
||||
uint32_t flags; /**< CRYPT_PBKDF* flags */
|
||||
};
|
||||
|
||||
/** PBKDF2 for LUKS1 and LUKS2 */
|
||||
/** Iteration time set by crypt_set_iteration_time(), for compatibility only. */
|
||||
#define CRYPT_PBKDF_ITER_TIME_SET (1 << 0)
|
||||
/** Never run benchmarks, use pre-set value or defaults. */
|
||||
#define CRYPT_PBKDF_NO_BENCHMARK (1 << 1)
|
||||
|
||||
/** PBKDF2 according to RFC2898, LUKS1 legacy */
|
||||
#define CRYPT_KDF_PBKDF2 "pbkdf2"
|
||||
/** Argon2i according to RFC */
|
||||
#define CRYPT_KDF_ARGON2I "argon2i"
|
||||
@@ -227,14 +224,15 @@ struct crypt_pbkdf_type {
|
||||
|
||||
/**
|
||||
* Set default PBKDF (Password-Based Key Derivation Algorithm) for next keyslot
|
||||
* about to get created with any crypt_keyslot_add_*() call. Works only with
|
||||
* valid LUKSv2 device handles.
|
||||
* about to get created with any crypt_keyslot_add_*() call.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param pbkdf PBKDF parameters
|
||||
*
|
||||
* @return 0 on success or negative errno value otherwise.
|
||||
*
|
||||
* @note For LUKS1, only PBKDF2 is suppported, other settings will be rejected.
|
||||
* @note For non-LUKS context types the call succeeds, but PBKDF is not used.
|
||||
*/
|
||||
int crypt_set_pbkdf_type(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf);
|
||||
@@ -250,6 +248,18 @@ int crypt_set_pbkdf_type(struct crypt_device *cd,
|
||||
*/
|
||||
const struct crypt_pbkdf_type *crypt_get_pbkdf_type(struct crypt_device *cd);
|
||||
|
||||
/**
|
||||
* Set how long should cryptsetup iterate in PBKDF2 function.
|
||||
* Default value heads towards the iterations which takes around 1 second.
|
||||
* \b Deprecated, only for backward compatibility. Use @link crypt_set_pbkdf_type.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param iteration_time_ms the time in ms
|
||||
*
|
||||
* @note If the time value is not acceptable for active PBKDF, value is quietly ignored.
|
||||
*/
|
||||
void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_ms);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -778,7 +778,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
}
|
||||
|
||||
/* Compute master key digest */
|
||||
pbkdf = CONST_CAST(struct crypt_pbkdf_type *)crypt_get_pbkdf_type(ctx);
|
||||
pbkdf = crypt_get_pbkdf(ctx);
|
||||
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -869,7 +869,7 @@ int LUKS_set_key(unsigned int keyIndex,
|
||||
}
|
||||
|
||||
log_dbg("Calculating data for key slot %d", keyIndex);
|
||||
pbkdf = CONST_CAST(struct crypt_pbkdf_type *)crypt_get_pbkdf_type(ctx);
|
||||
pbkdf = crypt_get_pbkdf(ctx);
|
||||
r = crypt_benchmark_pbkdf_internal(ctx, pbkdf, vk->keylength);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
197
lib/setup.c
197
lib/setup.c
@@ -48,7 +48,6 @@ struct crypt_device {
|
||||
struct crypt_pbkdf_type pbkdf;
|
||||
|
||||
/* global context scope settings */
|
||||
unsigned iter_time_set:1;
|
||||
|
||||
// FIXME: private binary headers and access it properly
|
||||
// through sub-library (LUKS1, TCRYPT)
|
||||
@@ -546,168 +545,10 @@ int crypt_set_data_device(struct crypt_device *cd, const char *device)
|
||||
return crypt_check_data_device_size(cd);
|
||||
}
|
||||
|
||||
/*
|
||||
* PBKDF configuration interface
|
||||
*/
|
||||
static int verify_pbkdf_params(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf)
|
||||
/* internal only */
|
||||
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd)
|
||||
{
|
||||
const char *pbkdf_type;
|
||||
int r = 0;
|
||||
|
||||
if (!pbkdf->type || !pbkdf->hash || !pbkdf->time_ms)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: initialise crypto and check the hash and pbkdf are both available */
|
||||
r = crypt_parse_pbkdf(pbkdf->type, &pbkdf_type);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Unknown PBKDF type %s.\n"), pbkdf->type);
|
||||
return r;
|
||||
}
|
||||
|
||||
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.\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pbkdf->max_memory_kb > MAX_PBKDF_MEMORY) {
|
||||
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes).\n"),
|
||||
MAX_PBKDF_MEMORY);
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->max_memory_kb) {
|
||||
log_err(cd, _("Requested maximum PBKDF memory can not be zero.\n"));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->parallel_threads) {
|
||||
log_err(cd, _("Requested PBKDF parallel threads can not be zero.\n"));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->time_ms) {
|
||||
log_err(cd, _("Requested PBKDF target time can not be zero.\n"));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int init_pbkdf_type(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf)
|
||||
{
|
||||
const char *hash, *type;
|
||||
unsigned cpus;
|
||||
int r;
|
||||
struct crypt_pbkdf_type default_luks1 = {
|
||||
.type = CRYPT_KDF_PBKDF2,
|
||||
.hash = DEFAULT_LUKS1_HASH,
|
||||
.time_ms = cd->iter_time_set ? cd->pbkdf.time_ms : DEFAULT_LUKS1_ITER_TIME
|
||||
};
|
||||
|
||||
if (!pbkdf) {
|
||||
pbkdf = &default_luks1;
|
||||
|
||||
/*
|
||||
* black magic due to crypt_set_iteration_time() but we don't
|
||||
* want crypt_get_pbkdf_type() return invalid parameters
|
||||
*/
|
||||
r = verify_pbkdf_params(cd, pbkdf);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Crypto backend may be not initialized here,
|
||||
* cannot check if algorithms are really available.
|
||||
* It will fail later anyway :-)
|
||||
*/
|
||||
type = strdup(pbkdf->type);
|
||||
hash = strdup(pbkdf->hash);
|
||||
|
||||
if (!type || !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;
|
||||
|
||||
/* Reset iteration count so benchmark must run again. */
|
||||
cd->pbkdf.iterations = 0;
|
||||
|
||||
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 > MAX_PBKDF_THREADS) {
|
||||
log_dbg("Maximum PBKDF threads is %d (requested %d).",
|
||||
MAX_PBKDF_THREADS, cd->pbkdf.parallel_threads);
|
||||
cd->pbkdf.parallel_threads = MAX_PBKDF_THREADS;
|
||||
}
|
||||
|
||||
if (cd->pbkdf.parallel_threads) {
|
||||
cpus = crypt_cpusonline();
|
||||
if (cd->pbkdf.parallel_threads > cpus) {
|
||||
log_dbg("Only %u active CPUs detected, "
|
||||
"PBKDF threads decreased from %d to %d.",
|
||||
cpus, cd->pbkdf.parallel_threads, cpus);
|
||||
cd->pbkdf.parallel_threads = cpus;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_set_pbkdf_type(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!cd)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pbkdf) {
|
||||
log_dbg("Resetting pbkdf type to default");
|
||||
cd->iter_time_set = 0;
|
||||
return init_pbkdf_type(cd, NULL);
|
||||
}
|
||||
|
||||
log_dbg("PBKDF %s, hash %s, time_ms %u, max_memory_kb %u, parallel_threads %u.",
|
||||
pbkdf->type ?: "(none)", pbkdf->hash ?: "(none)", pbkdf->time_ms,
|
||||
pbkdf->max_memory_kb, pbkdf->parallel_threads);
|
||||
|
||||
if (verify_pbkdf_params(cd, pbkdf))
|
||||
return -EINVAL;
|
||||
|
||||
r = init_pbkdf_type(cd, pbkdf);
|
||||
if (!r)
|
||||
cd->iter_time_set = 1;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const struct crypt_pbkdf_type *crypt_get_pbkdf_type(struct crypt_device *cd)
|
||||
{
|
||||
return (cd && cd->pbkdf.type) ? &cd->pbkdf : NULL;
|
||||
}
|
||||
|
||||
void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_ms)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (!cd)
|
||||
return;
|
||||
|
||||
if (iteration_time_ms > UINT32_MAX)
|
||||
iteration_time_ms = DEFAULT_LUKS1_ITER_TIME;
|
||||
cd->pbkdf.time_ms = (uint32_t)iteration_time_ms;
|
||||
cd->iter_time_set = 1;
|
||||
|
||||
if (!r)
|
||||
log_dbg("Iteration time set to %" PRIu64 " miliseconds.", iteration_time_ms);
|
||||
return &cd->pbkdf;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -716,15 +557,14 @@ void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_m
|
||||
static int _crypt_load_luks1(struct crypt_device *cd, int require_header, int repair)
|
||||
{
|
||||
struct luks_phdr hdr;
|
||||
struct crypt_pbkdf_type pbkdf = {};
|
||||
int r;
|
||||
|
||||
r = init_crypto(cd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (repair && !cd->pbkdf.type) {
|
||||
r = init_pbkdf_type(cd, NULL);
|
||||
if (verify_pbkdf_params(cd, &cd->pbkdf)) {
|
||||
r = init_pbkdf_type(cd, NULL, CRYPT_LUKS1);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
@@ -733,13 +573,14 @@ static int _crypt_load_luks1(struct crypt_device *cd, int require_header, int re
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
pbkdf.type = CRYPT_KDF_PBKDF2;
|
||||
pbkdf.hash = hdr.hashSpec;
|
||||
pbkdf.time_ms = cd->iter_time_set ? cd->pbkdf.time_ms : DEFAULT_LUKS1_ITER_TIME;
|
||||
|
||||
r = init_pbkdf_type(cd, &pbkdf);
|
||||
if (r)
|
||||
return r;
|
||||
/* Set hash to the same as in the loaded header */
|
||||
if (!cd->pbkdf.hash || strcmp(cd->pbkdf.hash, hdr.hashSpec)) {
|
||||
free(CONST_CAST(void*)cd->pbkdf.hash);
|
||||
cd->pbkdf.hash = strdup(hdr.hashSpec);
|
||||
if (!cd->pbkdf.hash) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cd->type && !(cd->type = strdup(CRYPT_LUKS1)))
|
||||
return -ENOMEM;
|
||||
@@ -1289,14 +1130,16 @@ static int _crypt_format_luks1(struct crypt_device *cd,
|
||||
else
|
||||
cd->volume_key = crypt_generate_volume_key(cd, volume_key_size);
|
||||
|
||||
if(!cd->volume_key)
|
||||
if (!cd->volume_key)
|
||||
return -ENOMEM;
|
||||
|
||||
r = init_pbkdf_type(cd, NULL);
|
||||
if (r)
|
||||
return r;
|
||||
if (verify_pbkdf_params(cd, &cd->pbkdf)) {
|
||||
r = init_pbkdf_type(cd, NULL, CRYPT_LUKS1);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (params && params->hash && strcmp(params->hash, DEFAULT_LUKS1_HASH)) {
|
||||
if (params && params->hash && strcmp(params->hash, cd->pbkdf.hash)) {
|
||||
free(CONST_CAST(void*)cd->pbkdf.hash);
|
||||
cd->pbkdf.hash = strdup(params->hash);
|
||||
if (!cd->pbkdf.hash)
|
||||
|
||||
@@ -292,10 +292,15 @@ int crypt_benchmark_pbkdf_internal(struct crypt_device *cd,
|
||||
|
||||
/* Already benchmarked */
|
||||
if (pbkdf->iterations) {
|
||||
log_dbg("Reusing PBKDF benchmark values.");
|
||||
log_dbg("Reusing PBKDF values.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pbkdf->flags & CRYPT_PBKDF_NO_BENCHMARK) {
|
||||
log_err(cd, _("PBKDF benchmark disabled but iterations not set.\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
/*
|
||||
* For PBKDF2 it is enouch to run benchmark for only 1 second
|
||||
|
||||
212
lib/utils_pbkdf.c
Normal file
212
lib/utils_pbkdf.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* utils_pbkdf - PBKDF ssettings for libcryptsetup
|
||||
*
|
||||
* Copyright (C) 2009-2017, Red Hat, Inc. All rights reserved.
|
||||
* Copyright (C) 2009-2017, 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_luks1 = {
|
||||
.type = CRYPT_KDF_PBKDF2,
|
||||
.hash = DEFAULT_LUKS1_HASH,
|
||||
.time_ms = DEFAULT_LUKS1_ITER_TIME
|
||||
};
|
||||
|
||||
/*
|
||||
* PBKDF configuration interface
|
||||
*/
|
||||
int verify_pbkdf_params(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf)
|
||||
{
|
||||
const char *pbkdf_type;
|
||||
int r = 0;
|
||||
|
||||
if (!pbkdf->type || !pbkdf->hash || !pbkdf->time_ms)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: initialise crypto and check the hash and pbkdf are both available */
|
||||
r = crypt_parse_pbkdf(pbkdf->type, &pbkdf_type);
|
||||
if (r < 0) {
|
||||
log_err(cd, _("Unknown PBKDF type %s.\n"), pbkdf->type);
|
||||
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.\n"));
|
||||
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.\n"));
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pbkdf->max_memory_kb > MAX_PBKDF_MEMORY) {
|
||||
log_err(cd, _("Requested maximum PBKDF memory cost is too high (maximum is %d kilobytes).\n"),
|
||||
MAX_PBKDF_MEMORY);
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->max_memory_kb) {
|
||||
log_err(cd, _("Requested maximum PBKDF memory can not be zero.\n"));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->parallel_threads) {
|
||||
log_err(cd, _("Requested PBKDF parallel threads can not be zero.\n"));
|
||||
r = -EINVAL;
|
||||
}
|
||||
if (!pbkdf->time_ms) {
|
||||
log_err(cd, _("Requested PBKDF target time can not be zero.\n"));
|
||||
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);
|
||||
const char *hash, *type;
|
||||
unsigned cpus;
|
||||
uint32_t old_flags;
|
||||
int r;
|
||||
|
||||
if (!pbkdf)
|
||||
pbkdf = &default_luks1;
|
||||
|
||||
r = verify_pbkdf_params(cd, pbkdf);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/*
|
||||
* Crypto backend may be not initialized here,
|
||||
* cannot check if algorithms are really available.
|
||||
* It will fail later anyway :-)
|
||||
*/
|
||||
type = strdup(pbkdf->type);
|
||||
hash = strdup(pbkdf->hash);
|
||||
|
||||
if (!type || !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 > MAX_PBKDF_THREADS) {
|
||||
log_dbg("Maximum PBKDF threads is %d (requested %d).",
|
||||
MAX_PBKDF_THREADS, cd_pbkdf->parallel_threads);
|
||||
cd_pbkdf->parallel_threads = MAX_PBKDF_THREADS;
|
||||
}
|
||||
|
||||
if (cd_pbkdf->parallel_threads) {
|
||||
cpus = crypt_cpusonline();
|
||||
if (cd_pbkdf->parallel_threads > cpus) {
|
||||
log_dbg("Only %u active CPUs detected, "
|
||||
"PBKDF threads decreased from %d to %d.",
|
||||
cpus, cd_pbkdf->parallel_threads, cpus);
|
||||
cd_pbkdf->parallel_threads = cpus;
|
||||
}
|
||||
}
|
||||
|
||||
log_dbg("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("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;
|
||||
}
|
||||
|
||||
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("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("Iteration time set to %" PRIu64 " miliseconds.", iteration_time_ms);
|
||||
}
|
||||
@@ -9,6 +9,7 @@ lib/utils_loop.c
|
||||
lib/utils_fips.c
|
||||
lib/utils_device.c
|
||||
lib/utils_devpath.c
|
||||
lib/utils_pbkdf.c
|
||||
lib/utils_benchmark.c
|
||||
lib/utils_wipe.c
|
||||
lib/utils_keyring.c
|
||||
|
||||
@@ -48,7 +48,6 @@ static uint64_t opt_offset = 0;
|
||||
static uint64_t opt_skip = 0;
|
||||
static int opt_skip_valid = 0;
|
||||
static int opt_readonly = 0;
|
||||
static int opt_iteration_time = DEFAULT_LUKS1_ITER_TIME;
|
||||
static int opt_version_mode = 0;
|
||||
static int opt_timeout = 0;
|
||||
static int opt_tries = 3;
|
||||
@@ -68,9 +67,12 @@ static int opt_veracrypt = 0;
|
||||
static int opt_veracrypt_pim = -1;
|
||||
static int opt_veracrypt_query_pim = 0;
|
||||
static int opt_deferred_remove = 0;
|
||||
//FIXME: check uint32 overflow for long type
|
||||
static const char *opt_pbkdf = NULL;
|
||||
static long opt_pbkdf_memory = 1024;
|
||||
static long opt_pbkdf_parallel = 2;
|
||||
static long opt_pbkdf_iterations = 0;
|
||||
static int opt_iteration_time = 0;
|
||||
|
||||
static const char **action_argv;
|
||||
static int action_argc;
|
||||
@@ -753,6 +755,27 @@ fail:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int set_pbkdf_params(struct crypt_device *cd, const char *dev_type)
|
||||
{
|
||||
struct crypt_pbkdf_type pbkdf = {};
|
||||
|
||||
if (!strcmp(dev_type, CRYPT_LUKS1)) {
|
||||
if (opt_pbkdf && strcmp(opt_pbkdf, CRYPT_KDF_PBKDF2))
|
||||
return -EINVAL;
|
||||
pbkdf.type = CRYPT_KDF_PBKDF2;
|
||||
pbkdf.hash = opt_hash ?: DEFAULT_LUKS1_HASH;
|
||||
pbkdf.time_ms = opt_iteration_time ?: DEFAULT_LUKS1_ITER_TIME;
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if (opt_pbkdf_iterations) {
|
||||
pbkdf.iterations = opt_pbkdf_iterations;
|
||||
pbkdf.flags |= CRYPT_PBKDF_NO_BENCHMARK;
|
||||
}
|
||||
|
||||
return crypt_set_pbkdf_type(cd, &pbkdf);
|
||||
}
|
||||
|
||||
static int action_luksRepair(void)
|
||||
{
|
||||
struct crypt_device *cd = NULL;
|
||||
@@ -825,9 +848,6 @@ static int action_luksFormat(void)
|
||||
|
||||
keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8;
|
||||
|
||||
if (opt_iteration_time)
|
||||
crypt_set_iteration_time(cd, opt_iteration_time);
|
||||
|
||||
if (opt_random)
|
||||
crypt_set_rng_type(cd, CRYPT_RNG_RANDOM);
|
||||
else if (opt_urandom)
|
||||
@@ -845,6 +865,12 @@ static int action_luksFormat(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = set_pbkdf_params(cd, CRYPT_LUKS1);
|
||||
if (r) {
|
||||
log_err(_("Failed to set pbkdf parameters.\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode,
|
||||
opt_uuid, key, keysize, ¶ms);
|
||||
check_signal(&r);
|
||||
@@ -892,9 +918,6 @@ static int action_open_luks(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_iteration_time)
|
||||
crypt_set_iteration_time(cd, opt_iteration_time);
|
||||
|
||||
_set_activation_flags(&activate_flags);
|
||||
|
||||
if (opt_master_key_file) {
|
||||
@@ -1094,8 +1117,11 @@ static int action_luksAddKey(void)
|
||||
opt_force_password = 1;
|
||||
|
||||
keysize = crypt_get_volume_key_size(cd);
|
||||
if (opt_iteration_time)
|
||||
crypt_set_iteration_time(cd, opt_iteration_time);
|
||||
r = set_pbkdf_params(cd, crypt_get_type(cd));
|
||||
if (r) {
|
||||
log_err(_("Failed to set pbkdf parameters.\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (opt_master_key_file) {
|
||||
r = _read_mk(opt_master_key_file, &key, keysize);
|
||||
@@ -1175,8 +1201,11 @@ static int action_luksChangeKey(void)
|
||||
if (tools_is_cipher_null(crypt_get_cipher(cd)))
|
||||
opt_force_password = 1;
|
||||
|
||||
if (opt_iteration_time)
|
||||
crypt_set_iteration_time(cd, opt_iteration_time);
|
||||
r = set_pbkdf_params(cd, crypt_get_type(cd));
|
||||
if (r) {
|
||||
log_err(_("Failed to set pbkdf parameters.\n"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = tools_get_key(_("Enter passphrase to be changed: "),
|
||||
&password, &password_size,
|
||||
@@ -1632,7 +1661,6 @@ int main(int argc, const char **argv)
|
||||
{ "offset", 'o', POPT_ARG_STRING, &popt_tmp, 2, N_("The start offset in the backend device"), N_("SECTORS") },
|
||||
{ "skip", 'p', POPT_ARG_STRING, &popt_tmp, 3, N_("How many sectors of the encrypted data to skip at the beginning"), N_("SECTORS") },
|
||||
{ "readonly", 'r', POPT_ARG_NONE, &opt_readonly, 0, N_("Create a readonly mapping"), NULL },
|
||||
{ "iter-time", 'i', POPT_ARG_INT, &opt_iteration_time, 0, N_("PBKDF2 iteration time for LUKS (in ms)"), N_("msecs") },
|
||||
{ "batch-mode", 'q', POPT_ARG_NONE, &opt_batch_mode, 0, N_("Do not ask for confirmation"), NULL },
|
||||
{ "timeout", 't', POPT_ARG_INT, &opt_timeout, 0, N_("Timeout for interactive passphrase prompt (in seconds)"), N_("secs") },
|
||||
{ "tries", 'T', POPT_ARG_INT, &opt_tries, 0, N_("How often the input of the passphrase can be retried"), NULL },
|
||||
@@ -1656,9 +1684,11 @@ int main(int argc, const char **argv)
|
||||
{ "perf-same_cpu_crypt",'\0', POPT_ARG_NONE, &opt_perf_same_cpu_crypt, 0, N_("Use dm-crypt same_cpu_crypt performance compatibility option."), NULL },
|
||||
{ "perf-submit_from_crypt_cpus",'\0', POPT_ARG_NONE, &opt_perf_submit_from_crypt_cpus,0,N_("Use dm-crypt submit_from_crypt_cpus performance compatibility option."), NULL },
|
||||
{ "deferred", '\0', POPT_ARG_NONE, &opt_deferred_remove, 0, N_("Device removal is deferred until the last user closes it."), NULL },
|
||||
{ "pbkdf", '\0', POPT_ARG_STRING, &opt_pbkdf, 0, N_("Password-based key derivation algorithm (PBKDF) for LUKS2 (argon2/pbkdf2)."), NULL },
|
||||
{ "pbkdf-memory", '\0', POPT_ARG_LONG, &opt_pbkdf_memory, 0, N_("Password-based key derivation algorithm (PBKDF) memory cost limit"), N_("kilobytes") },
|
||||
{ "pbkdf-parallel", '\0', POPT_ARG_LONG, &opt_pbkdf_parallel, 0, N_("Password-based key derivation algorithm (PBKDF) parallel cost "), N_("threads") },
|
||||
{ "iter-time", 'i', POPT_ARG_INT, &opt_iteration_time, 0, N_("PBKDF iteration time for LUKS (in ms)"), N_("msecs") },
|
||||
{ "pbkdf", '\0', POPT_ARG_STRING, &opt_pbkdf, 0, N_("PBKDF algorithm (for LUKS2) (argon2i/argon2id/pbkdf2)."), NULL },
|
||||
{ "pbkdf-memory", '\0', POPT_ARG_LONG, &opt_pbkdf_memory, 0, N_("PBKDF memory cost limit"), N_("kilobytes") },
|
||||
{ "pbkdf-parallel", '\0', POPT_ARG_LONG, &opt_pbkdf_parallel, 0, N_("PBKDF parallel cost "), N_("threads") },
|
||||
{ "pbkdf-force-iterations",'\0',POPT_ARG_LONG, &opt_pbkdf_iterations, 0, N_("PBKDF iterations cost (forced, disables benchmark)"), NULL },
|
||||
POPT_TABLEEND
|
||||
};
|
||||
poptContext popt_context;
|
||||
@@ -1915,6 +1945,16 @@ int main(int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_pbkdf && crypt_parse_pbkdf(opt_pbkdf, &opt_pbkdf))
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("PBKDF can be only pbkdf2 or argon2i/argon2id.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_pbkdf_iterations && opt_iteration_time)
|
||||
usage(popt_context, EXIT_FAILURE,
|
||||
_("PBKDF forced iterations cannot be combined with iteration time option.\n"),
|
||||
poptGetInvocationName(popt_context));
|
||||
|
||||
if (opt_debug) {
|
||||
opt_verbose = 1;
|
||||
crypt_set_debug_level(-1);
|
||||
|
||||
Reference in New Issue
Block a user