This commit introduces grub_crypto_argon2() by refactoring the Argon2 implementation from libgcrypt.
In GRUB's libgcrypt build, the hash_buffer() function is disabled. To work around this, a new 'argon2_blake2b_512_hash_buffers()' function was implemented to replace '_gcry_digest_spec_blake2b_512.hash_buffers()'. Signed-off-by: Gary Lin <g...@suse.com> --- Makefile.util.def | 37 +++++-- grub-core/Makefile.core.def | 8 ++ grub-core/lib/argon2.c | 190 ++++++++++++++++++++++++++---------- include/grub/crypto.h | 18 ++++ 4 files changed, 191 insertions(+), 62 deletions(-) diff --git a/Makefile.util.def b/Makefile.util.def index 038253b37..4ba2b5596 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -181,6 +181,14 @@ library = { common = grub-core/lib/zstd/zstd_decompress.c; }; +library = { + name = libgrubargon2.a; + common = grub-core/lib/argon2.c; + + cflags = '$(CFLAGS_GCRY)'; + cppflags = '$(CPPFLAGS_GCRY)'; +}; + program = { name = grub-mkimage; mansection = 1; @@ -225,8 +233,9 @@ program = { cflags = '-I$(srcdir)/grub-core/lib/tss2 -I$(srcdir)/grub-core/commands/tpm2_key_protector'; ldadd = libgrubmods.a; - ldadd = libgrubgcry.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; + ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBTASN1)'; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -323,8 +332,9 @@ program = { common = grub-core/osdep/init.c; ldadd = libgrubmods.a; - ldadd = libgrubgcry.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; + ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; @@ -378,8 +388,9 @@ program = { common = grub-core/osdep/init.c; ldadd = libgrubmods.a; - ldadd = libgrubgcry.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; + ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; @@ -401,6 +412,7 @@ program = { ldadd = libgrubmods.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -421,6 +433,7 @@ program = { ldadd = libgrubmods.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -466,8 +479,9 @@ program = { common = grub-core/kern/emu/argp_common.c; ldadd = libgrubmods.a; - ldadd = libgrubgcry.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; + ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; @@ -605,8 +619,9 @@ program = { ldadd = '$(LIBLZMA)'; ldadd = libgrubmods.a; - ldadd = libgrubgcry.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; + ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -691,8 +706,9 @@ program = { ldadd = '$(LIBLZMA)'; ldadd = libgrubmods.a; - ldadd = libgrubgcry.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; + ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; @@ -1400,8 +1416,9 @@ program = { common = grub-core/kern/emu/argp_common.c; ldadd = libgrubmods.a; - ldadd = libgrubgcry.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; + ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; @@ -1434,8 +1451,9 @@ program = { common = grub-core/osdep/init.c; ldadd = libgrubmods.a; - ldadd = libgrubgcry.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; + ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; @@ -1463,8 +1481,9 @@ program = { common = grub-core/osdep/init.c; ldadd = libgrubmods.a; - ldadd = libgrubgcry.a; ldadd = libgrubkern.a; + ldadd = libgrubargon2.a; + ldadd = libgrubgcry.a; ldadd = grub-core/lib/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; }; diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index b3f71196a..5e740a48c 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1694,6 +1694,14 @@ module = { common = lib/pbkdf2.c; }; +module = { + name = argon2; + common = lib/argon2.c; + + cflags = '$(CFLAGS_GCRY)'; + cppflags = '$(CPPFLAGS_GCRY)'; +}; + module = { name = relocator; common = lib/relocator.c; diff --git a/grub-core/lib/argon2.c b/grub-core/lib/argon2.c index b1b67ffec..f2b33c009 100644 --- a/grub-core/lib/argon2.c +++ b/grub-core/lib/argon2.c @@ -1,3 +1,31 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2025 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +/* Imported from libgcrypt */ + +#include <grub/crypto.h> +#include <grub/dl.h> + +#include <grub/gcrypt/g10lib.h> +#include <grub/gcrypt/gcrypt.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + typedef struct argon2_context *argon2_ctx_t; /* Per thread data for Argon2. */ @@ -16,16 +44,16 @@ struct argon2_context { unsigned int outlen; const unsigned char *password; - size_t passwordlen; + grub_size_t passwordlen; const unsigned char *salt; - size_t saltlen; + grub_size_t saltlen; const unsigned char *key; - size_t keylen; + grub_size_t keylen; const unsigned char *ad; - size_t adlen; + grub_size_t adlen; unsigned int m_cost; @@ -35,7 +63,7 @@ struct argon2_context { unsigned int lane_length; unsigned int lanes; - u64 *block; + grub_uint64_t *block; struct argon2_thread_data *thread_data; unsigned char out[1]; /* In future, we may use flexible array member. */ @@ -46,7 +74,7 @@ struct argon2_context { #define ARGON2_WORDS_IN_BLOCK (1024/8) static void -xor_block (u64 *dst, const u64 *src) +xor_block (grub_uint64_t *dst, const grub_uint64_t *src) { int i; @@ -55,7 +83,7 @@ xor_block (u64 *dst, const u64 *src) } static void -beswap64_block (u64 *dst) +beswap64_block (grub_uint64_t *dst) { #ifdef WORDS_BIGENDIAN int i; @@ -70,6 +98,33 @@ beswap64_block (u64 *dst) #endif } +/* Implementation of _gcry_blake2b_512_hash_buffers */ +static void +argon2_blake2b_512_hash_buffers (void *outbuf, const gcry_buffer_t *iov, int iovcnt) +{ + void *hd; + + hd = xtrymalloc (_gcry_digest_spec_blake2b_512.contextsize); + if (!hd) + return; + + _gcry_digest_spec_blake2b_512.init (hd, 0); + for (;iovcnt > 0; iov++, iovcnt--) + _gcry_digest_spec_blake2b_512.write (hd, (const char*)iov[0].data + iov[0].off, iov[0].len); + _gcry_digest_spec_blake2b_512.final (hd); + grub_memcpy (outbuf, _gcry_digest_spec_blake2b_512.read (hd), 512 / 8); + + xfree (hd); +} + +static inline void buf_put_le32(void *_buf, u32 val) +{ + byte *out = _buf; + out[3] = val >> 24; + out[2] = val >> 16; + out[1] = val >> 8; + out[0] = val; +} static gpg_err_code_t argon2_fill_first_blocks (argon2_ctx_t a) @@ -136,11 +191,11 @@ argon2_fill_first_blocks (argon2_ctx_t a) iov_count++; } - _gcry_digest_spec_blake2b_512.hash_buffers (h0_01_i, 64, iov, iov_count); + argon2_blake2b_512_hash_buffers (h0_01_i, iov, iov_count); for (i = 0; i < a->lanes; i++) { - memset (h0_01_i+64, 0, 4); + grub_memset (h0_01_i+64, 0, 4); buf_put_le32 (h0_01_i+64+4, i); blake2b_vl_hash (h0_01_i, 72, 1024, &a->block[i*a->lane_length*ARGON2_WORDS_IN_BLOCK]); @@ -183,20 +238,20 @@ argon2_init (argon2_ctx_t a, unsigned int parallelism, block = xtrymalloc (1024 * memory_blocks); if (!block) { - ec = gpg_err_code_from_errno (errno); + ec = GPG_ERR_OUT_OF_MEMORY; return ec; } - memset (block, 0, 1024 * memory_blocks); + grub_memset (block, 0, 1024 * memory_blocks); thread_data = xtrymalloc (a->lanes * sizeof (struct argon2_thread_data)); if (!thread_data) { - ec = gpg_err_code_from_errno (errno); + ec = GPG_ERR_OUT_OF_MEMORY; xfree (block); return ec; } - memset (thread_data, 0, a->lanes * sizeof (struct argon2_thread_data)); + grub_memset (thread_data, 0, a->lanes * sizeof (struct argon2_thread_data)); a->block = block; a->thread_data = thread_data; @@ -204,13 +259,13 @@ argon2_init (argon2_ctx_t a, unsigned int parallelism, } -static u64 fBlaMka (u64 x, u64 y) +static grub_uint64_t fBlaMka (grub_uint64_t x, grub_uint64_t y) { - const u64 m = U64_C(0xFFFFFFFF); + const grub_uint64_t m = 0xFFFFFFFFULL; return x + y + 2 * (x & m) * (y & m); } -static u64 rotr64 (u64 w, unsigned int c) +static grub_uint64_t rotr64 (grub_uint64_t w, unsigned int c) { return (w >> c) | (w << (64 - c)); } @@ -241,17 +296,17 @@ static u64 rotr64 (u64 w, unsigned int c) } while ((void)0, 0) static void -fill_block (const u64 *prev_block, const u64 *ref_block, u64 *curr_block, +fill_block (const grub_uint64_t *prev_block, const grub_uint64_t *ref_block, grub_uint64_t *curr_block, int with_xor) { - u64 block_r[ARGON2_WORDS_IN_BLOCK]; - u64 block_tmp[ARGON2_WORDS_IN_BLOCK]; + grub_uint64_t block_r[ARGON2_WORDS_IN_BLOCK]; + grub_uint64_t block_tmp[ARGON2_WORDS_IN_BLOCK]; int i; - memcpy (block_r, ref_block, 1024); + grub_memcpy (block_r, ref_block, 1024); if (prev_block) xor_block (block_r, prev_block); - memcpy (block_tmp, block_r, 1024); + grub_memcpy (block_tmp, block_r, 1024); if (with_xor) xor_block (block_tmp, curr_block); @@ -274,25 +329,25 @@ fill_block (const u64 *prev_block, const u64 *ref_block, u64 *curr_block, block_r[2 * i + 96], block_r[2 * i + 97], block_r[2 * i + 112], block_r[2 * i + 113]); - memcpy (curr_block, block_tmp, 1024); + grub_memcpy (curr_block, block_tmp, 1024); xor_block (curr_block, block_r); } static void -pseudo_random_generate (u64 *random_block, u64 *input_block) +pseudo_random_generate (grub_uint64_t *random_block, grub_uint64_t *input_block) { input_block[6]++; fill_block (NULL, input_block, random_block, 0); fill_block (NULL, random_block, random_block, 0); } -static u32 +static grub_uint32_t index_alpha (argon2_ctx_t a, const struct argon2_thread_data *t, - int segment_index, u32 random, int same_lane) + int segment_index, grub_uint32_t random, int same_lane) { - u32 reference_area_size; - u64 relative_position; - u32 start_position; + grub_uint32_t reference_area_size; + grub_uint64_t relative_position; + grub_uint32_t start_position; if (t->pass == 0) { @@ -318,7 +373,7 @@ index_alpha (argon2_ctx_t a, const struct argon2_thread_data *t, - a->segment_length + ((segment_index == 0) ? -1 : 0); } - relative_position = (random * (u64)random) >> 32; + relative_position = (random * (grub_uint64_t)random) >> 32; relative_position = reference_area_size - 1 - ((reference_area_size * relative_position) >> 32); @@ -339,15 +394,15 @@ argon2_compute_segment (void *priv) argon2_ctx_t a = t->a; int i; int prev_offset, curr_offset; - u32 ref_index, ref_lane; - u64 input_block[1024/sizeof (u64)]; - u64 address_block[1024/sizeof (u64)]; - u64 *random_block = NULL; + grub_uint32_t ref_index, ref_lane; + grub_uint64_t input_block[1024/sizeof (grub_uint64_t)]; + grub_uint64_t address_block[1024/sizeof (grub_uint64_t)]; + grub_uint64_t *random_block = NULL; - if (a->hash_type == GCRY_KDF_ARGON2I - || (a->hash_type == GCRY_KDF_ARGON2ID && t->pass == 0 && t->slice < 2)) + if (a->hash_type == GRUB_GCRY_KDF_ARGON2I + || (a->hash_type == GRUB_GCRY_KDF_ARGON2ID && t->pass == 0 && t->slice < 2)) { - memset (input_block, 0, 1024); + grub_memset (input_block, 0, 1024); input_block[0] = t->pass; input_block[1] = t->lane; input_block[2] = t->slice; @@ -374,18 +429,18 @@ argon2_compute_segment (void *priv) for (; i < a->segment_length; i++, curr_offset++, prev_offset++) { - u64 *ref_block, *curr_block; - u64 rand64; + grub_uint64_t *ref_block, *curr_block; + grub_uint64_t rand64; if ((curr_offset % a->lane_length) == 1) prev_offset = curr_offset - 1; if (random_block) { - if ((i % (1024/sizeof (u64))) == 0) + if ((i % (1024/sizeof (grub_uint64_t))) == 0) pseudo_random_generate (random_block, input_block); - rand64 = random_block[(i% (1024/sizeof (u64)))]; + rand64 = random_block[(i% (1024/sizeof (grub_uint64_t)))]; } else rand64 = a->block[prev_offset*ARGON2_WORDS_IN_BLOCK]; @@ -458,17 +513,17 @@ argon2_compute (argon2_ctx_t a, const struct gcry_kdf_thread_ops *ops) static gpg_err_code_t -argon2_final (argon2_ctx_t a, size_t resultlen, void *result) +argon2_final (argon2_ctx_t a, grub_size_t resultlen, void *result) { int i; if (resultlen != a->outlen) return GPG_ERR_INV_VALUE; - memset (a->block, 0, 1024); + grub_memset (a->block, 0, 1024); for (i = 0; i < a->lanes; i++) { - u64 *last_block; + grub_uint64_t *last_block; last_block = &a->block[(a->lane_length * i + (a->lane_length - 1)) * ARGON2_WORDS_IN_BLOCK]; @@ -483,7 +538,7 @@ argon2_final (argon2_ctx_t a, size_t resultlen, void *result) static void argon2_close (argon2_ctx_t a) { - size_t n; + grub_size_t n; n = offsetof (struct argon2_context, out) + a->outlen; @@ -503,10 +558,10 @@ argon2_close (argon2_ctx_t a) static gpg_err_code_t argon2_open (gcry_kdf_hd_t *hd, int subalgo, const unsigned long *param, unsigned int paramlen, - const void *password, size_t passwordlen, - const void *salt, size_t saltlen, - const void *key, size_t keylen, - const void *ad, size_t adlen) + const void *password, grub_size_t passwordlen, + const void *salt, grub_size_t saltlen, + const void *key, grub_size_t keylen, + const void *ad, grub_size_t adlen) { int hash_type; unsigned int taglen; @@ -515,11 +570,11 @@ argon2_open (gcry_kdf_hd_t *hd, int subalgo, unsigned int parallelism = 1; argon2_ctx_t a; gpg_err_code_t ec; - size_t n; + grub_size_t n; - if (subalgo != GCRY_KDF_ARGON2D - && subalgo != GCRY_KDF_ARGON2I - && subalgo != GCRY_KDF_ARGON2ID) + if (subalgo != GRUB_GCRY_KDF_ARGON2D + && subalgo != GRUB_GCRY_KDF_ARGON2I + && subalgo != GRUB_GCRY_KDF_ARGON2ID) return GPG_ERR_INV_VALUE; else hash_type = subalgo; @@ -542,7 +597,7 @@ argon2_open (gcry_kdf_hd_t *hd, int subalgo, n = offsetof (struct argon2_context, out) + taglen; a = xtrymalloc (n); if (!a) - return gpg_err_code_from_errno (errno); + return GPG_ERR_OUT_OF_MEMORY; a->algo = GCRY_KDF_ARGON2; a->hash_type = hash_type; @@ -573,3 +628,32 @@ argon2_open (gcry_kdf_hd_t *hd, int subalgo, *hd = (void *)a; return 0; } + +gcry_err_code_t +grub_crypto_argon2 (int subalgo, + const unsigned long *param, unsigned int paramlen, + const void *password, grub_size_t passwordlen, + const void *salt, grub_size_t saltlen, + const void *key, grub_size_t keylen, + const void *ad, grub_size_t adlen, + grub_size_t resultlen, void *result) +{ + gcry_kdf_hd_t hd = {0}; + gpg_err_code_t err; + + if (saltlen == 0) + return GPG_ERR_INV_VALUE; + + err = argon2_open (&hd, subalgo, param, paramlen, password, passwordlen, + salt, saltlen, key, keylen, ad, adlen); + if (err != GPG_ERR_NO_ERROR) + return err; + + err = argon2_compute ((argon2_ctx_t)(void *)hd, NULL); + if (err == GPG_ERR_NO_ERROR) + err = argon2_final ((argon2_ctx_t)(void *)hd, resultlen, result); + + argon2_close ((argon2_ctx_t)(void *)hd); + + return err; +} diff --git a/include/grub/crypto.h b/include/grub/crypto.h index b0d7add1d..cea82c3ce 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -34,6 +34,7 @@ typedef enum GPG_ERR_BAD_MPI, GPG_ERR_BAD_SECKEY, GPG_ERR_BAD_SIGNATURE, + GPG_ERR_CANCELED, GPG_ERR_CIPHER_ALGO, GPG_ERR_CONFLICT, GPG_ERR_DECRYPT_FAILED, @@ -512,6 +513,7 @@ extern gcry_md_spec_t _gcry_digest_spec_sha1; extern gcry_md_spec_t _gcry_digest_spec_sha256; extern gcry_md_spec_t _gcry_digest_spec_sha512; extern gcry_md_spec_t _gcry_digest_spec_crc32; +extern gcry_md_spec_t _gcry_digest_spec_blake2b_512; extern gcry_cipher_spec_t _gcry_cipher_spec_aes; #define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) #define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1) @@ -533,6 +535,22 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md, unsigned int c, grub_uint8_t *DK, grub_size_t dkLen); +enum grub_gcry_kdf_subalgo_argon2 + { + GRUB_GCRY_KDF_ARGON2D = 0, + GRUB_GCRY_KDF_ARGON2I = 1, + GRUB_GCRY_KDF_ARGON2ID = 2 + }; + +gcry_err_code_t +grub_crypto_argon2 (int subalgo, + const unsigned long *param, unsigned int paramlen, + const void *password, grub_size_t passwordlen, + const void *salt, grub_size_t saltlen, + const void *key, grub_size_t keylen, + const void *ad, grub_size_t adlen, + grub_size_t resultlen, void *result); + int grub_crypto_memcmp (const void *a, const void *b, grub_size_t n); -- 2.43.0 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel