Commit 0abf57be authored by Milan Broz's avatar Milan Broz

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's avatarMilan Broz <gmazyland@gmail.com>
parent 09d14a0b
......@@ -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(
......
......@@ -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);
......@@ -2509,7 +2674,7 @@ static int _luks_dump(struct crypt_device *cd)
log_std(cd, "\tAF stripes: \t%" PRIu32 "\n",
cd->u.luks1.hdr.keyblock[i].stripes);
}
else
else
log_std(cd, "Key Slot %d: DISABLED\n", i);
}
return 0;
......
......@@ -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;
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);
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_pbkdf(NULL, &pbkdf, "foo", 3, "bar", 3, key_size,