diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 08:35:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 08:35:41 +0000 |
commit | f7458043ae6a2d2d54b911fac52e50341646bef2 (patch) | |
tree | 6c58e084cd8728490fd5bb8eead07db0be0038f4 /lib/crypto_backend/crypto_gcrypt.c | |
parent | Adding upstream version 2:2.6.1. (diff) | |
download | cryptsetup-upstream/2%2.7.0.tar.xz cryptsetup-upstream/2%2.7.0.zip |
Adding upstream version 2:2.7.0.upstream/2%2.7.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/crypto_backend/crypto_gcrypt.c')
-rw-r--r-- | lib/crypto_backend/crypto_gcrypt.c | 150 |
1 files changed, 143 insertions, 7 deletions
diff --git a/lib/crypto_backend/crypto_gcrypt.c b/lib/crypto_backend/crypto_gcrypt.c index e974aa8..8e3f14e 100644 --- a/lib/crypto_backend/crypto_gcrypt.c +++ b/lib/crypto_backend/crypto_gcrypt.c @@ -1,8 +1,8 @@ /* * GCRYPT crypto backend implementation * - * Copyright (C) 2010-2023 Red Hat, Inc. All rights reserved. - * Copyright (C) 2010-2023 Milan Broz + * Copyright (C) 2010-2024 Red Hat, Inc. All rights reserved. + * Copyright (C) 2010-2024 Milan Broz * * This file is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -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; @@ -126,10 +127,11 @@ int crypt_backend_init(bool fips __attribute__((unused))) crypto_backend_initialised = 1; crypt_hash_test_whirlpool_bug(); - r = snprintf(version, sizeof(version), "gcrypt %s%s%s", + r = snprintf(version, sizeof(version), "gcrypt %s%s%s%s", gcry_check_version(NULL), crypto_backend_secmem ? "" : ", secmem disabled", - crypto_backend_whirlpool_bug > 0 ? ", flawed whirlpool" : ""); + crypto_backend_whirlpool_bug > 0 ? ", flawed whirlpool" : "", + crypt_backend_flags() & CRYPT_BACKEND_ARGON2 ? ", argon2" : ""); if (r < 0 || (size_t)r >= sizeof(version)) return -EINVAL; @@ -151,7 +153,11 @@ const char *crypt_backend_version(void) uint32_t crypt_backend_flags(void) { - return 0; + uint32_t flags = 0; +#if HAVE_DECL_GCRY_KDF_ARGON2 && !USE_INTERNAL_ARGON2 + flags |= CRYPT_BACKEND_ARGON2; +#endif + return flags; } static const char *crypt_hash_compat_name(const char *name, unsigned int *flags) @@ -266,7 +272,6 @@ int crypt_hash_final(struct crypt_hash *ctx, char *buffer, size_t length) void crypt_hash_destroy(struct crypt_hash *ctx) { gcry_md_close(ctx->hd); - memset(ctx, 0, sizeof(*ctx)); free(ctx); } @@ -341,7 +346,6 @@ int crypt_hmac_final(struct crypt_hmac *ctx, char *buffer, size_t length) void crypt_hmac_destroy(struct crypt_hmac *ctx) { gcry_md_close(ctx->hd); - memset(ctx, 0, sizeof(*ctx)); free(ctx); } @@ -386,6 +390,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) +{ + unsigned 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 +528,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; } @@ -565,6 +698,9 @@ bool crypt_fips_mode(void) if (fips_checked) return fips_mode; + if (crypt_backend_init(false /* ignored */)) + return false; + fips_mode = gcry_fips_mode_active(); fips_checked = true; |