mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-11 19:00:02 +01:00
Add support for Argon2 from libgcrypt.
Argon2 is available since version 1.10, but we need version that allows empty passwords (1.11).
This commit is contained in:
39
configure.ac
39
configure.ac
@@ -267,6 +267,9 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
GCRYPT_REQ_VERSION=1.1.42
|
||||
fi
|
||||
|
||||
use_internal_pbkdf2=0
|
||||
use_internal_argon2=1
|
||||
|
||||
dnl libgcrypt rejects to use pkgconfig, use AM_PATH_LIBGCRYPT from gcrypt-devel here.
|
||||
dnl Do not require gcrypt-devel if other crypto backend is used.
|
||||
m4_ifdef([AM_PATH_LIBGCRYPT],[
|
||||
@@ -290,7 +293,24 @@ AC_DEFUN([CONFIGURE_GCRYPT], [
|
||||
NO_FIPS([])
|
||||
fi
|
||||
|
||||
m4_ifdef([AM_PATH_LIBGCRYPT],[
|
||||
AC_ARG_ENABLE([gcrypt-argon2],
|
||||
dnl Check if we can use gcrypt Argon2 (1.11.0 supports empty password)
|
||||
AS_HELP_STRING([--disable-gcrypt-argon2], [force disable internal gcrypt Argon2]),
|
||||
[],
|
||||
[AM_PATH_LIBGCRYPT([1.11.0], [use_internal_argon2=0], [use_internal_argon2=1])])
|
||||
AM_PATH_LIBGCRYPT($GCRYPT_REQ_VERSION,,[AC_MSG_ERROR([You need the gcrypt library.])])],
|
||||
AC_MSG_ERROR([Missing support for gcrypt: install gcrypt and regenerate configure.]))
|
||||
|
||||
AC_MSG_CHECKING([if internal cryptsetup Argon2 is compiled-in])
|
||||
if test $use_internal_argon2 = 0; then
|
||||
AC_MSG_RESULT([no])
|
||||
else
|
||||
AC_MSG_RESULT([yes])
|
||||
fi
|
||||
|
||||
AC_CHECK_DECLS([GCRY_CIPHER_MODE_XTS], [], [], [#include <gcrypt.h>])
|
||||
AC_CHECK_DECLS([GCRY_KDF_ARGON2], [], [], [#include <gcrypt.h>])
|
||||
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_LIBS=$LIBS
|
||||
@@ -315,6 +335,7 @@ AC_DEFUN([CONFIGURE_OPENSSL], [
|
||||
CRYPTO_CFLAGS=$LIBCRYPTO_CFLAGS
|
||||
CRYPTO_LIBS=$LIBCRYPTO_LIBS
|
||||
use_internal_pbkdf2=0
|
||||
use_internal_argon2=1
|
||||
|
||||
if test "x$enable_static_cryptsetup" = "xyes"; then
|
||||
saved_PKG_CONFIG=$PKG_CONFIG
|
||||
@@ -343,6 +364,7 @@ AC_DEFUN([CONFIGURE_NSS], [
|
||||
CRYPTO_CFLAGS=$NSS_CFLAGS
|
||||
CRYPTO_LIBS=$NSS_LIBS
|
||||
use_internal_pbkdf2=1
|
||||
use_internal_argon2=1
|
||||
NO_FIPS([])
|
||||
])
|
||||
|
||||
@@ -353,6 +375,7 @@ AC_DEFUN([CONFIGURE_KERNEL], [
|
||||
# [AC_MSG_ERROR([You need Linux kernel with userspace crypto interface.])],
|
||||
# [#include <sys/socket.h>])
|
||||
use_internal_pbkdf2=1
|
||||
use_internal_argon2=1
|
||||
NO_FIPS([])
|
||||
])
|
||||
|
||||
@@ -369,6 +392,7 @@ AC_DEFUN([CONFIGURE_NETTLE], [
|
||||
|
||||
CRYPTO_STATIC_LIBS=$CRYPTO_LIBS
|
||||
use_internal_pbkdf2=0
|
||||
use_internal_argon2=1
|
||||
NO_FIPS([])
|
||||
])
|
||||
|
||||
@@ -493,7 +517,15 @@ AC_ARG_ENABLE([internal-argon2],
|
||||
AC_ARG_ENABLE([libargon2],
|
||||
AS_HELP_STRING([--enable-libargon2], [enable external libargon2 (PHC) library (disables internal bundled version)]))
|
||||
|
||||
if test "x$enable_libargon2" = "xyes" ; then
|
||||
if test $use_internal_argon2 = 0 -o "x$enable_internal_argon2" = "xno" ; then
|
||||
if test "x$enable_internal_argon2" = "xyes" -o "x$enable_libargon" = "xyes"; then
|
||||
AC_MSG_WARN([Argon2 in $with_crypto_backend lib is used; internal Argon2 options are ignored.])
|
||||
fi
|
||||
enable_internal_argon2=no
|
||||
enable_internal_sse_argon2=no
|
||||
enable_libargon2=no
|
||||
use_internal_argon2=0
|
||||
elif test "x$enable_libargon2" = "xyes" ; then
|
||||
AC_CHECK_HEADERS(argon2.h,,
|
||||
[AC_MSG_ERROR([You need libargon2 development library installed.])])
|
||||
AC_CHECK_DECL(Argon2_id,,[AC_MSG_ERROR([You need more recent Argon2 library with support for Argon2id.])], [#include <argon2.h>])
|
||||
@@ -517,11 +549,10 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$enable_internal_argon2" = "xyes"; then
|
||||
AC_DEFINE(USE_INTERNAL_ARGON2, 1, [Use internal Argon2])
|
||||
fi
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_ARGON2, test "x$enable_internal_argon2" = "xyes")
|
||||
AM_CONDITIONAL(CRYPTO_INTERNAL_SSE_ARGON2, test "x$enable_internal_sse_argon2" = "xyes")
|
||||
dnl If libargon is in use, we have defined HAVE_ARGON2_H
|
||||
AC_DEFINE_UNQUOTED(USE_INTERNAL_ARGON2, [$use_internal_argon2], [Use internal Argon2])
|
||||
|
||||
dnl Link with blkid to check for other device types
|
||||
AC_ARG_ENABLE([blkid],
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <gcrypt.h>
|
||||
#include <pthread.h>
|
||||
#include "crypto_backend_internal.h"
|
||||
|
||||
static int crypto_backend_initialised = 0;
|
||||
@@ -386,6 +387,130 @@ static int pbkdf2(const char *hash,
|
||||
#endif /* USE_INTERNAL_PBKDF2 */
|
||||
}
|
||||
|
||||
#if HAVE_DECL_GCRY_KDF_ARGON2 && !USE_INTERNAL_ARGON2
|
||||
struct gcrypt_thread_job
|
||||
{
|
||||
pthread_t thread;
|
||||
struct job_thread_param {
|
||||
gcry_kdf_job_fn_t job;
|
||||
void *p;
|
||||
} work;
|
||||
};
|
||||
|
||||
struct gcrypt_threads
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
unsigned int num_threads;
|
||||
unsigned int max_threads;
|
||||
struct gcrypt_thread_job *jobs_ctx;
|
||||
};
|
||||
|
||||
static void *gcrypt_job_thread(void *p)
|
||||
{
|
||||
struct job_thread_param *param = p;
|
||||
param->job(param->p);
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
static int gcrypt_wait_all_jobs(void *ctx)
|
||||
{
|
||||
int i;
|
||||
struct gcrypt_threads *threads = ctx;
|
||||
|
||||
for (i = 0; i < threads->num_threads; i++) {
|
||||
pthread_join(threads->jobs_ctx[i].thread, NULL);
|
||||
threads->jobs_ctx[i].thread = 0;
|
||||
}
|
||||
|
||||
threads->num_threads = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gcrypt_dispatch_job(void *ctx, gcry_kdf_job_fn_t job, void *p)
|
||||
{
|
||||
struct gcrypt_threads *threads = ctx;
|
||||
|
||||
if (threads->num_threads >= threads->max_threads)
|
||||
return -1;
|
||||
|
||||
threads->jobs_ctx[threads->num_threads].work.job = job;
|
||||
threads->jobs_ctx[threads->num_threads].work.p = p;
|
||||
|
||||
if (pthread_create(&threads->jobs_ctx[threads->num_threads].thread, &threads->attr,
|
||||
gcrypt_job_thread, &threads->jobs_ctx[threads->num_threads].work))
|
||||
return -1;
|
||||
|
||||
threads->num_threads++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gcrypt_argon2(const char *type,
|
||||
const char *password, size_t password_length,
|
||||
const char *salt, size_t salt_length,
|
||||
char *key, size_t key_length,
|
||||
uint32_t iterations, uint32_t memory, uint32_t parallel)
|
||||
{
|
||||
gcry_kdf_hd_t hd;
|
||||
int atype, r = -EINVAL;
|
||||
unsigned long param[4];
|
||||
struct gcrypt_threads threads = {
|
||||
.max_threads = parallel,
|
||||
.num_threads = 0
|
||||
};
|
||||
const gcry_kdf_thread_ops_t ops = {
|
||||
.jobs_context = &threads,
|
||||
.dispatch_job = gcrypt_dispatch_job,
|
||||
.wait_all_jobs = gcrypt_wait_all_jobs
|
||||
};
|
||||
|
||||
if (!strcmp(type, "argon2i"))
|
||||
atype = GCRY_KDF_ARGON2I;
|
||||
else if (!strcmp(type, "argon2id"))
|
||||
atype = GCRY_KDF_ARGON2ID;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
param[0] = key_length;
|
||||
param[1] = iterations;
|
||||
param[2] = memory;
|
||||
param[3] = parallel;
|
||||
|
||||
if (gcry_kdf_open(&hd, GCRY_KDF_ARGON2, atype, param, 4,
|
||||
password, password_length, salt, salt_length,
|
||||
NULL, 0, NULL, 0)) {
|
||||
free(threads.jobs_ctx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (parallel == 1) {
|
||||
/* Do not use threads here */
|
||||
if (gcry_kdf_compute(hd, NULL))
|
||||
goto out;
|
||||
} else {
|
||||
threads.jobs_ctx = calloc(threads.max_threads,
|
||||
sizeof(struct gcrypt_thread_job));
|
||||
if (!threads.jobs_ctx)
|
||||
goto out;
|
||||
|
||||
if (pthread_attr_init(&threads.attr))
|
||||
goto out;
|
||||
|
||||
if (gcry_kdf_compute(hd, &ops))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gcry_kdf_final(hd, key_length, key))
|
||||
goto out;
|
||||
r = 0;
|
||||
out:
|
||||
gcry_kdf_close(hd);
|
||||
pthread_attr_destroy(&threads.attr);
|
||||
free(threads.jobs_ctx);
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* PBKDF */
|
||||
int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
const char *password, size_t password_length,
|
||||
@@ -400,8 +525,13 @@ int crypt_pbkdf(const char *kdf, const char *hash,
|
||||
return pbkdf2(hash, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations);
|
||||
else if (!strncmp(kdf, "argon2", 6))
|
||||
#if HAVE_DECL_GCRY_KDF_ARGON2 && !USE_INTERNAL_ARGON2
|
||||
return gcrypt_argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#else
|
||||
return argon2(kdf, password, password_length, salt, salt_length,
|
||||
key, key_length, iterations, memory, parallel);
|
||||
#endif
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
subdir('argon2')
|
||||
if use_internal_argon2
|
||||
subdir('argon2')
|
||||
endif
|
||||
|
||||
libcrypto_backend_dependencies = [
|
||||
crypto_backend_library,
|
||||
@@ -25,7 +27,7 @@ if use_internal_pbkdf2
|
||||
libcrypto_backend_sources += files('pbkdf2_generic.c')
|
||||
endif
|
||||
|
||||
if get_option('argon-implementation') == 'internal'
|
||||
if use_internal_argon2 and get_option('argon-implementation') == 'internal'
|
||||
libcrypto_backend_link_with += libargon2
|
||||
elif get_option('argon-implementation') == 'libargon2'
|
||||
libcrypto_backend_dependencies += libargon2_external
|
||||
|
||||
32
meson.build
32
meson.build
@@ -444,6 +444,7 @@ endif
|
||||
|
||||
crypto_backend_library = []
|
||||
use_internal_pbkdf2 = false
|
||||
use_internal_argon2 = true
|
||||
|
||||
if get_option('crypto-backend') == 'gcrypt'
|
||||
req_version = '1.1.42'
|
||||
@@ -471,16 +472,36 @@ if get_option('crypto-backend') == 'gcrypt'
|
||||
error('Using internal cryptsetup PBKDF2 is not compatible with FIPS.')
|
||||
endif
|
||||
|
||||
if get_option('gcrypt-argon2').auto()
|
||||
# Check if we can use gcrypt Argon2 (1.11.0 supports empty password)
|
||||
gcrypt_with_empty_password = dependency('libgcrypt',
|
||||
version: '>=1.11.0',
|
||||
required: false,
|
||||
static: enable_static)
|
||||
if gcrypt_with_empty_password.found()
|
||||
req_version = '1.11.0'
|
||||
use_internal_argon2 = false
|
||||
else
|
||||
use_internal_argon2 = true
|
||||
endif
|
||||
else
|
||||
use_internal_argon2 = get_option('gcrypt-argon2').disabled()
|
||||
endif
|
||||
|
||||
crypto_backend_library = dependency('libgcrypt',
|
||||
version: '>=@0@'.format(req_version),
|
||||
static: enable_static)
|
||||
conf.set10('HAVE_DECL_GCRY_CIPHER_MODE_XTS',
|
||||
cc.has_header_symbol('gcrypt.h', 'GCRY_CIPHER_MODE_XTS',
|
||||
dependencies: crypto_backend_library))
|
||||
conf.set10('HAVE_DECL_GCRY_KDF_ARGON2',
|
||||
cc.has_header_symbol('gcrypt.h', 'GCRY_KDF_ARGON2',
|
||||
dependencies: crypto_backend_library))
|
||||
conf.set_quoted('GCRYPT_REQ_VERSION', req_version,
|
||||
description: 'Requested gcrypt version')
|
||||
elif get_option('crypto-backend') == 'openssl'
|
||||
use_internal_pbkdf2 = false
|
||||
use_internal_argon2 = true
|
||||
crypto_backend_library = dependency('libcrypto',
|
||||
version: '>=0.9.8',
|
||||
static: enable_static)
|
||||
@@ -494,6 +515,7 @@ elif get_option('crypto-backend') == 'nss'
|
||||
|
||||
warning('NSS backend does NOT provide backward compatibility (missing ripemd160 hash).')
|
||||
use_internal_pbkdf2 = true
|
||||
use_internal_argon2 = true
|
||||
|
||||
crypto_backend_library = dependency('nss',
|
||||
static: enable_static)
|
||||
@@ -505,6 +527,7 @@ elif get_option('crypto-backend') == 'kernel'
|
||||
error('kernel crypto backend is not supported with FIPS enabled')
|
||||
endif
|
||||
use_internal_pbkdf2 = true
|
||||
use_internal_argon2 = true
|
||||
assert(cc.has_header('linux/if_alg.h'),
|
||||
'You need Linux kernel headers with userspace crypto interface.')
|
||||
elif get_option('crypto-backend') == 'nettle'
|
||||
@@ -518,6 +541,7 @@ elif get_option('crypto-backend') == 'nettle'
|
||||
crypto_backend_library = dependency('nettle',
|
||||
static: enable_static)
|
||||
use_internal_pbkdf2 = false
|
||||
use_internal_argon2 = true
|
||||
assert(cc.has_function('nettle_pbkdf2_hmac_sha256',
|
||||
dependencies: crypto_backend_library),
|
||||
'You need Nettle library version 2.6 or more recent.')
|
||||
@@ -527,7 +551,13 @@ conf.set10('USE_INTERNAL_PBKDF2', use_internal_pbkdf2)
|
||||
libargon2_external = []
|
||||
threads = []
|
||||
use_internal_sse_argon2 = false
|
||||
if get_option('argon-implementation') == 'internal'
|
||||
if not use_internal_argon2 or get_option('argon-implementation') == 'none'
|
||||
if get_option('argon-implementation') == 'internal' or get_option('argon-implementation') == 'libargon2'
|
||||
warning('Argon2 in crypto library is used; internal Argon2 options are ignored.')
|
||||
endif
|
||||
conf.set10('USE_INTERNAL_ARGON2', false,
|
||||
description: 'Use internal Argon2.')
|
||||
elif get_option('argon-implementation') == 'internal'
|
||||
warning('Argon2 bundled (slow) reference implementation will be used, please consider using system library with -Dargon-implementation=libargon2')
|
||||
|
||||
if get_option('internal-sse-argon2')
|
||||
|
||||
@@ -39,6 +39,7 @@ option('fips', type : 'boolean', description : 'enable FIPS mode restrictions',
|
||||
option('fuzzing-engine', type : 'string', description : 'specify LDFLAGS for linking with fuzzing engine (in OSS-Fuzz, LIB_FUZZING_ENGINE variable should be passed via this argument)')
|
||||
option('fuzz-targets', type : 'boolean', description : 'enable building fuzz targets', value : false)
|
||||
option('gcrypt-pbkdf2', type : 'feature', description : 'enable internal gcrypt PBKDF2', value : 'auto')
|
||||
option('gcrypt-argon2', type : 'feature', description : 'enable internal gcrypt Argon2', value : 'auto')
|
||||
option('integritysetup', type : 'boolean', description : 'integritysetup Support', value : true)
|
||||
option('internal-sse-argon2', type : 'boolean', description : 'use internal SSE implementation of Argon2 PBKDF', value : false)
|
||||
option('kernel_crypto', type : 'boolean', description : 'kernel userspace crypto (no benchmark and tcrypt)', value : true)
|
||||
|
||||
@@ -1029,7 +1029,10 @@ static int pbkdf_test_vectors(void)
|
||||
for (i = 0; i < ARRAY_SIZE(kdf_test_vectors); i++) {
|
||||
crypt_backend_memzero(result, sizeof(result));
|
||||
vec = &kdf_test_vectors[i];
|
||||
printf("PBKDF vector %02d %s ", i, vec->type);
|
||||
if (vec->hash)
|
||||
printf("PBKDF vector %02d %s-%s ", i, vec->type, vec->hash);
|
||||
else
|
||||
printf("PBKDF vector %02d %s ", i, vec->type);
|
||||
if (vec->hash && crypt_hmac_size(vec->hash) < 0) {
|
||||
printf("[%s N/A]\n", vec->hash);
|
||||
continue;
|
||||
@@ -1039,8 +1042,8 @@ static int pbkdf_test_vectors(void)
|
||||
vec->salt, vec->salt_length,
|
||||
result, vec->output_length,
|
||||
vec->iterations, vec->memory, vec->parallelism) < 0) {
|
||||
printf("[%s-%s N/A]\n", vec->type, vec->hash);
|
||||
continue;
|
||||
printf("[API FAILED]\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (memcmp(result, vec->output, vec->output_length)) {
|
||||
printf("[FAILED]\n");
|
||||
|
||||
Reference in New Issue
Block a user