mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Change PBKDF interface API.
Prepare API for PBKDF that can set three costs - time (similar to iterations in PBKDF2) - memory (required memory for memory-hard function) - threads (required number of threads/CPUs). This patch also removes wrongly designed API call crypt_benchmark_kdf and replaces it with the new call crypt_benchmark_pbkdf. Two functions for PBKDF per context setting are introduced: crypt_set_pbkdf_type and crypt_get_pbkdf_type. The patch should be backward compatible when using crypt_set_iteration_time function (works only for PBKDF2). Signed-off-by: Milan Broz <gmazyland@gmail.com>
This commit is contained in:
@@ -60,7 +60,7 @@ int crypt_backend_rng(char *buffer, size_t length, int quality, int fips);
|
||||
int crypt_pbkdf_check(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
size_t key_length, uint64_t *iter_secs);
|
||||
size_t key_length, uint32_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,
|
||||
|
||||
@@ -55,7 +55,7 @@ static long time_ms(struct rusage *start, struct rusage *end)
|
||||
int crypt_pbkdf_check(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
size_t key_length, uint64_t *iter_secs)
|
||||
size_t key_length, uint32_t *iter_secs)
|
||||
{
|
||||
struct rusage rstart, rend;
|
||||
int r = 0, step = 0;
|
||||
|
||||
@@ -49,6 +49,9 @@
|
||||
#define DEFAULT_MEM_ALIGNMENT 4096
|
||||
#define MAX_ERROR_LENGTH 512
|
||||
|
||||
#define MAX_PBKDF_THREADS 8
|
||||
#define MAX_PBKDF_MEMORY 1024*1024 /* 1GiB */
|
||||
|
||||
#define at_least(a, b) ({ __typeof__(a) __at_least = (a); (__at_least >= (b))?__at_least:(b); })
|
||||
|
||||
struct crypt_device;
|
||||
@@ -115,6 +118,8 @@ ssize_t write_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf,
|
||||
ssize_t read_lseek_blockwise(int fd, size_t bsize, size_t alignment, void *buf, size_t count, off_t offset);
|
||||
|
||||
size_t crypt_getpagesize(void);
|
||||
unsigned crypt_cpusonline(void);
|
||||
|
||||
int init_crypto(struct crypt_device *ctx);
|
||||
|
||||
void logger(struct crypt_device *cd, int class, const char *file, int line, const char *format, ...) __attribute__ ((format (printf, 5, 6)));
|
||||
|
||||
@@ -176,7 +176,7 @@ void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_m
|
||||
int crypt_set_data_device(struct crypt_device *cd, const char *device);
|
||||
|
||||
/**
|
||||
* @defgroup rng Cryptsetup RNG
|
||||
* @defgroup rng Cryptsetup RNG and PBKDF
|
||||
*
|
||||
* @addtogroup rng
|
||||
* @{
|
||||
@@ -206,6 +206,49 @@ void crypt_set_rng_type(struct crypt_device *cd, int rng_type);
|
||||
*/
|
||||
int crypt_get_rng_type(struct crypt_device *cd);
|
||||
|
||||
/**
|
||||
* PBKDF parameters.
|
||||
*/
|
||||
struct crypt_pbkdf_type {
|
||||
const char *type; /**< PBKDF algorithm */
|
||||
const char *hash; /**< Hash algorithm */
|
||||
uint32_t time_ms; /**< Requested time cost [milliseconds] */
|
||||
uint32_t max_memory_kb; /**< Requested memory cost [kilobytes] */
|
||||
uint32_t parallel_threads;/**< Requested parallel cost [threads] */
|
||||
};
|
||||
|
||||
/** PBKDF2 for LUKS1 and LUKS2 */
|
||||
#define CRYPT_KDF_PBKDF2 "pbkdf2"
|
||||
/** Argon2i according to RFC */
|
||||
#define CRYPT_KDF_ARGON2I "argon2i"
|
||||
/** Argon2id according to RFC */
|
||||
#define CRYPT_KDF_ARGON2ID "argon2id"
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param pbkdf PBKDF parameters
|
||||
*
|
||||
* @return 0 on success or negative errno value otherwise.
|
||||
*
|
||||
*/
|
||||
int crypt_set_pbkdf_type(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf);
|
||||
|
||||
/**
|
||||
* Get current default PBKDF (Password-Based Key Derivation Algorithm) for keyslots.
|
||||
* Works only with LUKS device handles (both versions).
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
*
|
||||
* @return struct on success or NULL value otherwise.
|
||||
*
|
||||
*/
|
||||
const struct crypt_pbkdf_type *crypt_get_pbkdf_type(struct crypt_device *cd);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@@ -1092,27 +1135,29 @@ int crypt_benchmark(struct crypt_device *cd,
|
||||
double *decryption_mbs);
|
||||
|
||||
/**
|
||||
* Informational benchmark for KDF.
|
||||
* Informational benchmark for PBKDF.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param kdf Key derivation function (e.g. "pbkdf2")
|
||||
* @param hash Hash algorithm used in KDF (e.g. "sha256")
|
||||
* @param pbkdf PBKDF parameters
|
||||
* @param password password for benchmark
|
||||
* @param password_size size of password
|
||||
* @param salt salt for benchmark
|
||||
* @param salt_size size of salt
|
||||
* @param iterations_sec returns measured KDF iterations per second
|
||||
* @param volume_key_size output volume key size
|
||||
* @param iterations_sec returns measured PBKDF iterations per second
|
||||
*
|
||||
* @return @e 0 on success or negative errno value otherwise.
|
||||
*/
|
||||
int crypt_benchmark_kdf(struct crypt_device *cd,
|
||||
const char *kdf,
|
||||
const char *hash,
|
||||
int crypt_benchmark_pbkdf(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf,
|
||||
const char *password,
|
||||
size_t password_size,
|
||||
const char *salt,
|
||||
size_t salt_size,
|
||||
uint64_t *iterations_sec);
|
||||
size_t volume_key_size,
|
||||
uint32_t *iterations,
|
||||
uint32_t *memory);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,7 @@ CRYPTSETUP_2.0 {
|
||||
crypt_init;
|
||||
crypt_init_by_name;
|
||||
crypt_init_by_name_and_header;
|
||||
|
||||
crypt_set_log_callback;
|
||||
crypt_set_confirm_callback;
|
||||
crypt_set_iteration_time;
|
||||
@@ -37,7 +38,7 @@ CRYPTSETUP_2.0 {
|
||||
crypt_status;
|
||||
crypt_dump;
|
||||
crypt_benchmark;
|
||||
crypt_benchmark_kdf;
|
||||
crypt_benchmark_pbkdf;
|
||||
crypt_get_cipher;
|
||||
crypt_get_cipher_mode;
|
||||
crypt_get_integrity;
|
||||
@@ -58,6 +59,8 @@ CRYPTSETUP_2.0 {
|
||||
|
||||
crypt_set_rng_type;
|
||||
crypt_get_rng_type;
|
||||
crypt_set_pbkdf_type;
|
||||
crypt_get_pbkdf_type;
|
||||
|
||||
crypt_keyslot_max;
|
||||
crypt_keyslot_area;
|
||||
|
||||
@@ -386,7 +386,7 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
|
||||
struct luks_phdr temp_phdr;
|
||||
const unsigned char *sector = (const unsigned char*)phdr;
|
||||
struct volume_key *vk;
|
||||
uint64_t PBKDF2_per_sec = 1;
|
||||
uint32_t PBKDF2_per_sec = 1;
|
||||
int i, bad, r, need_write = 0;
|
||||
|
||||
if (phdr->keyBytes != 16 && phdr->keyBytes != 32 && phdr->keyBytes != 64) {
|
||||
@@ -719,7 +719,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
unsigned int alignPayload,
|
||||
unsigned int alignOffset,
|
||||
uint32_t iteration_time_ms,
|
||||
uint64_t *PBKDF2_per_sec,
|
||||
uint32_t *PBKDF2_per_sec,
|
||||
int detached_metadata_device,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
@@ -727,6 +727,11 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
size_t blocksPerStripeSet, currentSector;
|
||||
int r;
|
||||
uuid_t partitionUuid;
|
||||
const struct crypt_pbkdf_type pbkdf = {
|
||||
.type = CRYPT_KDF_PBKDF2,
|
||||
.hash = hashSpec,
|
||||
.time_ms = 1000,
|
||||
};
|
||||
char luksMagic[] = LUKS_MAGIC;
|
||||
|
||||
/* For separate metadata device allow zero alignment */
|
||||
@@ -779,8 +784,8 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
return r;
|
||||
}
|
||||
|
||||
r = crypt_benchmark_kdf(ctx, "pbkdf2", header->hashSpec,
|
||||
"foo", 3, "bar", 3, PBKDF2_per_sec);
|
||||
r = crypt_benchmark_pbkdf(ctx, &pbkdf, "foo", 3, "bar", 3, vk->keylength,
|
||||
PBKDF2_per_sec, NULL);
|
||||
if (r < 0) {
|
||||
log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"),
|
||||
header->hashSpec);
|
||||
@@ -792,7 +797,7 @@ int LUKS_generate_phdr(struct luks_phdr *header,
|
||||
header->mkDigestIterations = at_least((uint32_t)(*PBKDF2_per_sec/1024) * iteration_time_ms,
|
||||
LUKS_MKD_ITERATIONS_MIN);
|
||||
|
||||
r = crypt_pbkdf("pbkdf2", header->hashSpec, vk->key,vk->keylength,
|
||||
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, header->hashSpec, vk->key,vk->keylength,
|
||||
header->mkDigestSalt, LUKS_SALTSIZE,
|
||||
header->mkDigest,LUKS_DIGESTSIZE,
|
||||
header->mkDigestIterations, 0, 0);
|
||||
@@ -852,13 +857,19 @@ int LUKS_set_key(unsigned int keyIndex,
|
||||
const char *password, size_t passwordLen,
|
||||
struct luks_phdr *hdr, struct volume_key *vk,
|
||||
uint32_t iteration_time_ms,
|
||||
uint64_t *PBKDF2_per_sec,
|
||||
uint32_t *PBKDF2_per_sec,
|
||||
struct crypt_device *ctx)
|
||||
{
|
||||
struct volume_key *derived_key;
|
||||
char *AfKey = NULL;
|
||||
size_t AFEKSize;
|
||||
uint64_t PBKDF2_temp;
|
||||
double PBKDF2_temp;
|
||||
const struct crypt_pbkdf_type pbkdf = {
|
||||
.type = CRYPT_KDF_PBKDF2,
|
||||
.hash = hdr->hashSpec,
|
||||
.time_ms = 1000,
|
||||
};
|
||||
|
||||
int r;
|
||||
|
||||
if(hdr->keyblock[keyIndex].active != LUKS_KEY_DISABLED) {
|
||||
@@ -875,8 +886,8 @@ int LUKS_set_key(unsigned int keyIndex,
|
||||
|
||||
log_dbg("Calculating data for key slot %d", keyIndex);
|
||||
|
||||
r = crypt_benchmark_kdf(ctx, "pbkdf2", hdr->hashSpec,
|
||||
"foo", 3, "bar", 3, PBKDF2_per_sec);
|
||||
r = crypt_benchmark_pbkdf(ctx, &pbkdf, "foo", 3, "bar", 3, vk->keylength,
|
||||
PBKDF2_per_sec, NULL);
|
||||
if (r < 0) {
|
||||
log_err(ctx, _("Not compatible PBKDF2 options (using hash algorithm %s).\n"),
|
||||
hdr->hashSpec);
|
||||
@@ -884,13 +895,10 @@ 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 * (uint64_t)iteration_time_ms;
|
||||
PBKDF2_temp /= 1024;
|
||||
if (PBKDF2_temp > UINT32_MAX)
|
||||
PBKDF2_temp = UINT32_MAX;
|
||||
PBKDF2_temp = ((double)*PBKDF2_per_sec * iteration_time_ms / 1000.);
|
||||
assert(PBKDF2_temp < UINT32_MAX);
|
||||
hdr->keyblock[keyIndex].passwordIterations = at_least((uint32_t)PBKDF2_temp,
|
||||
LUKS_SLOT_ITERATIONS_MIN);
|
||||
|
||||
@@ -905,7 +913,7 @@ int LUKS_set_key(unsigned int keyIndex,
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = crypt_pbkdf("pbkdf2", hdr->hashSpec, password, passwordLen,
|
||||
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen,
|
||||
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
|
||||
derived_key->key, hdr->keyBytes,
|
||||
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
|
||||
@@ -963,7 +971,7 @@ int LUKS_verify_volume_key(const struct luks_phdr *hdr,
|
||||
{
|
||||
char checkHashBuf[LUKS_DIGESTSIZE];
|
||||
|
||||
if (crypt_pbkdf("pbkdf2", hdr->hashSpec, vk->key, vk->keylength,
|
||||
if (crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, vk->key, vk->keylength,
|
||||
hdr->mkDigestSalt, LUKS_SALTSIZE,
|
||||
checkHashBuf, LUKS_DIGESTSIZE,
|
||||
hdr->mkDigestIterations, 0, 0) < 0)
|
||||
@@ -1007,7 +1015,7 @@ static int LUKS_open_key(unsigned int keyIndex,
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = crypt_pbkdf("pbkdf2", hdr->hashSpec, password, passwordLen,
|
||||
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen,
|
||||
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
|
||||
derived_key->key, hdr->keyBytes,
|
||||
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
|
||||
|
||||
@@ -107,7 +107,7 @@ int LUKS_generate_phdr(
|
||||
unsigned int alignPayload,
|
||||
unsigned int alignOffset,
|
||||
uint32_t iteration_time_ms,
|
||||
uint64_t *PBKDF2_per_sec,
|
||||
uint32_t *PBKDF2_per_sec,
|
||||
int detached_metadata_device,
|
||||
struct crypt_device *ctx);
|
||||
|
||||
@@ -148,7 +148,7 @@ int LUKS_set_key(
|
||||
struct luks_phdr *hdr,
|
||||
struct volume_key *vk,
|
||||
uint32_t iteration_time_ms,
|
||||
uint64_t *PBKDF2_per_sec,
|
||||
uint32_t *PBKDF2_per_sec,
|
||||
struct crypt_device *ctx);
|
||||
|
||||
int LUKS_open_key_with_hdr(
|
||||
|
||||
189
lib/setup.c
189
lib/setup.c
@@ -44,8 +44,11 @@ struct crypt_device {
|
||||
struct device *metadata_device;
|
||||
|
||||
struct volume_key *volume_key;
|
||||
uint64_t iteration_time;
|
||||
int rng_type;
|
||||
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)
|
||||
@@ -53,7 +56,7 @@ struct crypt_device {
|
||||
union {
|
||||
struct { /* used in CRYPT_LUKS1 */
|
||||
struct luks_phdr hdr;
|
||||
uint64_t PBKDF2_per_sec;
|
||||
uint32_t PBKDF2_per_sec;
|
||||
} luks1;
|
||||
struct { /* used in CRYPT_PLAIN */
|
||||
struct crypt_params_plain hdr;
|
||||
@@ -483,8 +486,8 @@ int crypt_init(struct crypt_device **cd, const char *device)
|
||||
|
||||
dm_backend_init();
|
||||
|
||||
h->iteration_time = DEFAULT_LUKS1_ITER_TIME;
|
||||
h->rng_type = crypt_random_default_key_rng();
|
||||
|
||||
*cd = h;
|
||||
return 0;
|
||||
bad:
|
||||
@@ -544,9 +547,108 @@ int crypt_set_data_device(struct crypt_device *cd, const char *device)
|
||||
return crypt_check_data_device_size(cd);
|
||||
}
|
||||
|
||||
static int verify_pbkdf_params(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (!pbkdf->type || !pbkdf->hash)
|
||||
return -EINVAL;
|
||||
|
||||
/* TODO: initialise crypto and check the hash and pbkdf are both available */
|
||||
r = crypt_parse_pbkdf(pbkdf->type, NULL);
|
||||
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;
|
||||
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
|
||||
};
|
||||
unsigned cpus = crypt_cpusonline();
|
||||
|
||||
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;
|
||||
|
||||
cd->pbkdf.time_ms = pbkdf->time_ms;
|
||||
cd->pbkdf.max_memory_kb = pbkdf->max_memory_kb;
|
||||
|
||||
if (pbkdf->parallel_threads > cpus) {
|
||||
cd->pbkdf.parallel_threads = cpus;
|
||||
log_dbg("Only %u active CPUs detected, PBKDF threads decreased from %d to %d.",
|
||||
cpus, pbkdf->parallel_threads, cpus);
|
||||
} else
|
||||
cd->pbkdf.parallel_threads = pbkdf->parallel_threads;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -557,6 +659,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;
|
||||
|
||||
if (!cd->type && !(cd->type = strdup(CRYPT_LUKS1)))
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1022,6 +1132,17 @@ static int _crypt_format_luks1(struct crypt_device *cd,
|
||||
if(!cd->volume_key)
|
||||
return -ENOMEM;
|
||||
|
||||
r = init_pbkdf_type(cd, NULL);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (params && params->hash && strcmp(params->hash, DEFAULT_LUKS1_HASH)) {
|
||||
free(CONST_CAST(void*)cd->pbkdf.hash);
|
||||
cd->pbkdf.hash = strdup(params->hash);
|
||||
if (!cd->pbkdf.hash)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (params && params->data_device) {
|
||||
cd->metadata_device = cd->device;
|
||||
cd->device = NULL;
|
||||
@@ -1036,11 +1157,10 @@ static int _crypt_format_luks1(struct crypt_device *cd,
|
||||
&alignment_offset, DEFAULT_DISK_ALIGNMENT);
|
||||
|
||||
r = LUKS_generate_phdr(&cd->u.luks1.hdr, cd->volume_key, cipher, cipher_mode,
|
||||
(params && params->hash) ? params->hash : DEFAULT_LUKS1_HASH,
|
||||
uuid, LUKS_STRIPES,
|
||||
cd->pbkdf.hash, uuid, LUKS_STRIPES,
|
||||
required_alignment / SECTOR_SIZE,
|
||||
alignment_offset / SECTOR_SIZE,
|
||||
cd->iteration_time, &cd->u.luks1.PBKDF2_per_sec,
|
||||
cd->pbkdf.time_ms, &cd->u.luks1.PBKDF2_per_sec,
|
||||
cd->metadata_device ? 1 : 0, cd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1603,6 +1723,9 @@ void crypt_free(struct crypt_device *cd)
|
||||
free(cd->u.none.active_name);
|
||||
}
|
||||
|
||||
free(CONST_CAST(void*)cd->pbkdf.type);
|
||||
free(CONST_CAST(void*)cd->pbkdf.hash);
|
||||
|
||||
free(cd->type);
|
||||
/* Some structures can contain keys (TCRYPT), wipe it */
|
||||
crypt_memzero(cd, sizeof(*cd));
|
||||
@@ -1812,7 +1935,7 @@ int crypt_keyslot_add_by_passphrase(struct crypt_device *cd,
|
||||
goto out;
|
||||
|
||||
r = LUKS_set_key(keyslot, CONST_CAST(char*)new_passphrase, new_passphrase_size,
|
||||
&cd->u.luks1.hdr, vk, cd->iteration_time, &cd->u.luks1.PBKDF2_per_sec, cd);
|
||||
&cd->u.luks1.hdr, vk, cd->pbkdf.time_ms, &cd->u.luks1.PBKDF2_per_sec, cd);
|
||||
if(r < 0)
|
||||
goto out;
|
||||
|
||||
@@ -1863,7 +1986,7 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
|
||||
}
|
||||
|
||||
r = LUKS_set_key(keyslot_new, new_passphrase, new_passphrase_size,
|
||||
&cd->u.luks1.hdr, vk, cd->iteration_time,
|
||||
&cd->u.luks1.hdr, vk, cd->pbkdf.time_ms,
|
||||
&cd->u.luks1.PBKDF2_per_sec, cd);
|
||||
|
||||
if (keyslot_old == keyslot_new) {
|
||||
@@ -1940,7 +2063,7 @@ int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd,
|
||||
goto out;
|
||||
|
||||
r = LUKS_set_key(keyslot, new_password, new_passwordLen,
|
||||
&cd->u.luks1.hdr, vk, cd->iteration_time, &cd->u.luks1.PBKDF2_per_sec, cd);
|
||||
&cd->u.luks1.hdr, vk, cd->pbkdf.time_ms, &cd->u.luks1.PBKDF2_per_sec, cd);
|
||||
out:
|
||||
crypt_safe_free(password);
|
||||
crypt_safe_free(new_password);
|
||||
@@ -1998,7 +2121,7 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
|
||||
goto out;
|
||||
|
||||
r = LUKS_set_key(keyslot, passphrase, passphrase_size,
|
||||
&cd->u.luks1.hdr, vk, cd->iteration_time, &cd->u.luks1.PBKDF2_per_sec, cd);
|
||||
&cd->u.luks1.hdr, vk, cd->pbkdf.time_ms, &cd->u.luks1.PBKDF2_per_sec, cd);
|
||||
out:
|
||||
crypt_free_volume_key(vk);
|
||||
return (r < 0) ? r : keyslot;
|
||||
@@ -2411,8 +2534,18 @@ int crypt_volume_key_verify(struct crypt_device *cd,
|
||||
|
||||
void crypt_set_iteration_time(struct crypt_device *cd, uint64_t iteration_time_ms)
|
||||
{
|
||||
log_dbg("Iteration time set to %" PRIu64 " milliseconds.", iteration_time_ms);
|
||||
cd->iteration_time = 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);
|
||||
}
|
||||
|
||||
void crypt_set_rng_type(struct crypt_device *cd, int rng_type)
|
||||
@@ -2433,6 +2566,38 @@ int crypt_get_rng_type(struct crypt_device *cd)
|
||||
return cd->rng_type;
|
||||
}
|
||||
|
||||
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 : NULL;
|
||||
}
|
||||
|
||||
int crypt_memory_lock(struct crypt_device *cd, int lock)
|
||||
{
|
||||
return lock ? crypt_memlock_inc(cd) : crypt_memlock_dec(cd);
|
||||
|
||||
@@ -36,6 +36,12 @@ size_t crypt_getpagesize(void)
|
||||
return r <= 0 ? DEFAULT_MEM_ALIGNMENT : (size_t)r;
|
||||
}
|
||||
|
||||
unsigned crypt_cpusonline(void)
|
||||
{
|
||||
long r = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return r < 0 ? 1 : r;
|
||||
}
|
||||
|
||||
ssize_t read_buffer(int fd, void *buf, size_t count)
|
||||
{
|
||||
size_t read_size = 0;
|
||||
|
||||
@@ -231,39 +231,36 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_benchmark_kdf(struct crypt_device *cd,
|
||||
const char *kdf,
|
||||
const char *hash,
|
||||
int crypt_benchmark_pbkdf(struct crypt_device *cd,
|
||||
const struct crypt_pbkdf_type *pbkdf,
|
||||
const char *password,
|
||||
size_t password_size,
|
||||
const char *salt,
|
||||
size_t salt_size,
|
||||
uint64_t *iterations_sec)
|
||||
size_t volume_key_size,
|
||||
uint32_t *iterations,
|
||||
uint32_t *memory)
|
||||
{
|
||||
int r, key_length = 0;
|
||||
|
||||
if (!iterations_sec)
|
||||
return -EINVAL;
|
||||
uint32_t iterations_sec;
|
||||
int r;
|
||||
|
||||
r = init_crypto(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 (!strcmp(pbkdf->type, CRYPT_KDF_PBKDF2)) {
|
||||
if (!iterations || memory)
|
||||
return -EINVAL;
|
||||
|
||||
if (key_length == 0)
|
||||
key_length = DEFAULT_LUKS1_KEYBITS / 8;
|
||||
r = crypt_pbkdf_check(pbkdf->type, pbkdf->hash, password, password_size,
|
||||
salt, salt_size, volume_key_size, &iterations_sec);
|
||||
|
||||
if (!strncmp(kdf, "pbkdf2", 6))
|
||||
r = crypt_pbkdf_check(kdf, hash, password, password_size,
|
||||
salt, salt_size, key_length, iterations_sec);
|
||||
else
|
||||
*iterations = (uint32_t)((uint64_t)iterations_sec * (uint64_t)pbkdf->time_ms / 1000);
|
||||
if (!r)
|
||||
log_dbg("PBKDF2 benchmark, hash %s: %u iterations per second (%zu-bits key).",
|
||||
pbkdf->hash, iterations_sec, volume_key_size * 8);
|
||||
} else
|
||||
r = -EINVAL;
|
||||
|
||||
if (!r)
|
||||
log_dbg("KDF %s, hash %s: %" PRIu64 " iterations per second (%d-bits key).",
|
||||
kdf, hash, *iterations_sec, key_length * 8);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -106,6 +106,29 @@ int crypt_parse_hash_integrity_mode(const char *s, char *integrity)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_parse_pbkdf(const char *s, const char **pbkdf)
|
||||
{
|
||||
const char *tmp = NULL;
|
||||
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
if (!strcasecmp(s, CRYPT_KDF_PBKDF2))
|
||||
tmp = CRYPT_KDF_PBKDF2;
|
||||
else if (!strcasecmp(s, CRYPT_KDF_ARGON2I))
|
||||
tmp = CRYPT_KDF_ARGON2I;
|
||||
else if (!strcasecmp(s, CRYPT_KDF_ARGON2ID))
|
||||
tmp = CRYPT_KDF_ARGON2ID;
|
||||
|
||||
if (!tmp)
|
||||
return -EINVAL;
|
||||
|
||||
if (pbkdf)
|
||||
*pbkdf = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replacement for memset(s, 0, n) on stack that can be optimized out
|
||||
* Also used in safe allocations for explicit memory wipe.
|
||||
|
||||
@@ -34,6 +34,7 @@ struct crypt_device;
|
||||
int crypt_parse_name_and_mode(const char *s, char *cipher,
|
||||
int *key_nums, char *cipher_mode);
|
||||
int crypt_parse_hash_integrity_mode(const char *s, char *integrity);
|
||||
int crypt_parse_pbkdf(const char *s, const char **pbkdf);
|
||||
|
||||
void *crypt_safe_alloc(size_t size);
|
||||
void crypt_safe_free(void *data);
|
||||
|
||||
@@ -529,18 +529,28 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int action_benchmark_kdf(const char *hash)
|
||||
static int action_benchmark_kdf(const char *kdf, const char *hash, size_t key_size)
|
||||
{
|
||||
uint64_t kdf_iters;
|
||||
int r;
|
||||
if (!strcmp(kdf, CRYPT_KDF_PBKDF2)) {
|
||||
const struct crypt_pbkdf_type pbkdf = {
|
||||
.type = CRYPT_KDF_PBKDF2,
|
||||
.hash = hash,
|
||||
.time_ms = 1000,
|
||||
};
|
||||
uint32_t kdf_iters;
|
||||
|
||||
r = crypt_benchmark_kdf(NULL, "pbkdf2", hash, "foo", 3, "bar", 3,
|
||||
&kdf_iters);
|
||||
if (r < 0)
|
||||
log_std("PBKDF2-%-9s N/A\n", hash);
|
||||
else
|
||||
log_std("PBKDF2-%-9s %7" PRIu64 " iterations per second for %d-bit key\n",
|
||||
hash, kdf_iters, DEFAULT_LUKS1_KEYBITS);
|
||||
r = crypt_benchmark_pbkdf(NULL, &pbkdf, "foo", 3, "bar", 3, key_size,
|
||||
&kdf_iters, NULL);
|
||||
if (r < 0)
|
||||
log_std("PBKDF2-%-9s N/A\n", hash);
|
||||
else
|
||||
log_std("PBKDF2-%-9s %7u iterations per second for %zu-bit key\n",
|
||||
hash, kdf_iters, key_size * 8);
|
||||
} else {
|
||||
log_err("Unknown PBKDF '%s'\n", kdf);
|
||||
r = -EINVAL;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -594,15 +604,13 @@ static int action_benchmark(void)
|
||||
};
|
||||
char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
|
||||
double enc_mbr = 0, dec_mbr = 0;
|
||||
int key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS);
|
||||
int key_size = (opt_key_size ?: DEFAULT_PLAIN_KEYBITS) / 8;
|
||||
int iv_size = 16, skipped = 0;
|
||||
char *c;
|
||||
int i, r;
|
||||
|
||||
log_std(_("# Tests are approximate using memory only (no storage IO).\n"));
|
||||
if (opt_hash) {
|
||||
r = action_benchmark_kdf(opt_hash);
|
||||
} else if (opt_cipher) {
|
||||
if (opt_cipher) {
|
||||
r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
|
||||
if (r < 0) {
|
||||
log_err(_("No known cipher specification pattern detected.\n"));
|
||||
@@ -621,17 +629,17 @@ static int action_benchmark(void)
|
||||
iv_size = 0;
|
||||
|
||||
r = benchmark_cipher_loop(cipher, cipher_mode,
|
||||
key_size / 8, iv_size,
|
||||
key_size, iv_size,
|
||||
&enc_mbr, &dec_mbr);
|
||||
if (!r) {
|
||||
log_std(N_("# Algorithm | Key | Encryption | Decryption\n"));
|
||||
log_std("%11s-%s %4db %6.1f MiB/s %6.1f MiB/s\n",
|
||||
cipher, cipher_mode, key_size, enc_mbr, dec_mbr);
|
||||
cipher, cipher_mode, key_size*8, enc_mbr, dec_mbr);
|
||||
} else if (r == -ENOENT)
|
||||
log_err(_("Cipher %s is not available.\n"), opt_cipher);
|
||||
} else {
|
||||
for (i = 0; bkdfs[i]; i++) {
|
||||
r = action_benchmark_kdf(bkdfs[i]);
|
||||
r = action_benchmark_kdf(CRYPT_KDF_PBKDF2, bkdfs[i], key_size);
|
||||
check_signal(&r);
|
||||
if (r == -EINTR)
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user