All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/5] Support Argon2 KDF in LUKS2
@ 2020-03-10 18:58 Patrick Steinhardt
  2020-03-10 18:58 ` [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB Patrick Steinhardt
                   ` (5 more replies)
  0 siblings, 6 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-10 18:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, Leif Lindholm, agraf, pjones,
	mjg59, phcoder, Milan Broz

Hi,

this is the third version of my patchset to support the Argon2 KDF in
LUKS2. The following things have changed in comparison to v2:

    - Improved the GRUB_UINT_C macros to not use `elif 1` and fixed
      indentation.

    - Dropped the upstreamed patch to fix a missing newline.

    - Reworked how we allocate memory on EFI. Previously, we always
      targeted to acquire 1/4 of available memory. Now we're always
      trying to allocate MAX_HEAP_SIZE (1.6GB) but clamp it to at most
      1/2 of available memory and at least MIN_HEAP_SIZE (100MB).

So especially the last part is the interesting one. I _think_ that it's
roughly what Leif had in mind, but please do correct me if I'm wrong.

Regards
Patrick

Patrick Steinhardt (5):
  efi: Always try to allocate heap size of 1.6GB
  types.h: add UINT-related macros needed for Argon2
  argon2: Import Argon2 from cryptsetup
  luks2: Discern Argon2i and Argon2id
  luks2: Support key derival via Argon2

 Makefile.util.def                             |   6 +-
 docs/grub-dev.texi                            |  64 +++
 grub-core/Makefile.core.def                   |  10 +-
 grub-core/disk/luks2.c                        |  26 +-
 grub-core/kern/efi/mm.c                       |  21 +-
 grub-core/lib/argon2/argon2.c                 | 232 ++++++++
 grub-core/lib/argon2/argon2.h                 | 264 +++++++++
 grub-core/lib/argon2/blake2/blake2-impl.h     | 151 +++++
 grub-core/lib/argon2/blake2/blake2.h          |  89 +++
 grub-core/lib/argon2/blake2/blake2b.c         | 388 +++++++++++++
 .../lib/argon2/blake2/blamka-round-ref.h      |  56 ++
 grub-core/lib/argon2/core.c                   | 525 ++++++++++++++++++
 grub-core/lib/argon2/core.h                   | 228 ++++++++
 grub-core/lib/argon2/ref.c                    | 190 +++++++
 include/grub/types.h                          |   8 +
 15 files changed, 2239 insertions(+), 19 deletions(-)
 create mode 100644 grub-core/lib/argon2/argon2.c
 create mode 100644 grub-core/lib/argon2/argon2.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2-impl.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2b.c
 create mode 100644 grub-core/lib/argon2/blake2/blamka-round-ref.h
 create mode 100644 grub-core/lib/argon2/core.c
 create mode 100644 grub-core/lib/argon2/core.h
 create mode 100644 grub-core/lib/argon2/ref.c

Range-diff against v2:
1:  15bdf830e < -:  --------- efi: Allocate half of available memory by default
-:  --------- > 1:  c783f34d7 efi: Always try to allocate heap size of 1.6GB
2:  e81db7d95 ! 2:  724713a8b types.h: add UINT-related macros needed for Argon2
    @@ include/grub/types.h: typedef grub_int32_t	grub_ssize_t;
      #endif
      # define GRUB_LONG_MIN (-GRUB_LONG_MAX - 1)
      
    -+# define GRUB_UINT32_C(x) x ## U
    -+# if GRUB_ULONG_MAX >> 31 >> 31 >> 1 == 1
    -+#  define GRUB_UINT64_C(x) x##UL
    -+# elif 1
    -+#  define GRUB_UINT64_C(x) x##ULL
    -+# endif
    ++#define GRUB_UINT32_C(x) x ## U
    ++#if GRUB_ULONG_MAX >> 31 >> 31 >> 1 == 1
    ++# define GRUB_UINT64_C(x) x##UL
    ++#else
    ++# define GRUB_UINT64_C(x) x##ULL
    ++#endif
     +
      typedef grub_uint64_t grub_properly_aligned_t;
      
3:  50aff9670 ! 3:  eadc4bcd8 argon2: Import Argon2 from cryptsetup
    @@ docs/grub-dev.texi: GRUB includes some code from other projects, and it is somet
     +* Argon2::
      * Gnulib::
      * jsmn::
    + * minilzo::
      @end menu
      
     +@node Argon2
4:  af3f85665 < -:  --------- luks2: Add missing newline to debug message
5:  89abe827b ! 4:  61bc6c0e5 luks2: Discern Argon2i and Argon2id
    @@ Commit message
         accordingly.
     
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
    +    Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
     
      ## grub-core/disk/luks2.c ##
     @@ grub-core/disk/luks2.c: GRUB_MOD_LICENSE ("GPLv3+");
6:  70a354e0b ! 5:  012e3d442 luks2: Support key derival via Argon2
    @@ Commit message
         now trivial.
     
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
    +    Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
     
      ## Makefile.util.def ##
     @@ Makefile.util.def: AutoGen definitions Makefile.tpl;
-- 
2.25.1



^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB
  2020-03-10 18:58 [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
@ 2020-03-10 18:58 ` Patrick Steinhardt
  2020-03-13 12:42   ` Daniel Kiper
  2020-03-13 12:55   ` Leif Lindholm
  2020-03-10 18:58 ` [PATCH v3 2/5] types.h: add UINT-related macros needed for Argon2 Patrick Steinhardt
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-10 18:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, Leif Lindholm, agraf, pjones,
	mjg59, phcoder, Milan Broz

By default, GRUB will allocate a quarter of the pages it got available
in the EFI subsystem. On many current systems, this will amount to
roughly 800MB of RAM assuming an address space of 32 bits. This is
plenty for most use cases, but it doesn't suffice when using full disk
encryption with a key derival function based on Argon2.

Besides the usual iteration count known from PBKDF2, Argon2 introduces
two additional parameters "memory" and "parallelism". While the latter
doesn't really matter to us, the memory parameter is quite interesting.
If encrypting a partition with LUKS2 using Argon2 as KDF, then
cryptsetup will default to a memory parameter of 1GB. Meaning we need to
allocate a buffer of 1GB in size in order to be able to derive the key,
which definitely won't squeeze into the limit of 800MB.

To prepare for Argon2, this commit reworks the memory allocation
algorithm for EFI platforms. Instead of trying to allocate a quarter of
memory available, let's instead introduce a constant target amount of
bytes that we try to allocate. The target is set to the previous value
of MAX_HEAP_SIZE, which amounts to 1.6GB and thus sufficiently high to
accomodate for both Argon2 as well as other functionality. The value is
then clamped to at most half of available memory but at least 100MB.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 grub-core/kern/efi/mm.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index b02fab1b1..367a726c6 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -39,8 +39,8 @@
 #define MEMORY_MAP_SIZE	0x3000
 
 /* The minimum and maximum heap size for GRUB itself.  */
-#define MIN_HEAP_SIZE	0x100000
-#define MAX_HEAP_SIZE	(1600 * 0x100000)
+#define MIN_HEAP_PAGES		BYTES_TO_PAGES(       0x100000)
+#define TARGET_HEAP_PAGES	BYTES_TO_PAGES(1600 * 0x100000)
 
 static void *finish_mmap_buf = 0;
 static grub_efi_uintn_t finish_mmap_size = 0;
@@ -559,7 +559,7 @@ grub_efi_mm_init (void)
   grub_efi_uintn_t map_size;
   grub_efi_uintn_t desc_size;
   grub_efi_uint64_t total_pages;
-  grub_efi_uint64_t required_pages;
+  grub_efi_uint64_t target_heap_pages;
   int mm_status;
 
   /* Prepare a memory region to store two memory maps.  */
@@ -599,14 +599,15 @@ grub_efi_mm_init (void)
   filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
 					       desc_size, memory_map_end);
 
-  /* By default, request a quarter of the available memory.  */
+  /* By default, request TARGET_HEAP_PAGES pages. If that exceeds half of meory
+   * available, clamp it, but request at least MIN_HEAP_PAGES. */
   total_pages = get_total_pages (filtered_memory_map, desc_size,
 				 filtered_memory_map_end);
-  required_pages = (total_pages >> 2);
-  if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
-    required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
-  else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))
-    required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE);
+  target_heap_pages = TARGET_HEAP_PAGES;
+  if (target_heap_pages > (total_pages / 2))
+    target_heap_pages = total_pages / 2;
+  if (target_heap_pages < MIN_HEAP_PAGES)
+    target_heap_pages = MIN_HEAP_PAGES;
 
   /* Sort the filtered descriptors, so that GRUB can allocate pages
      from smaller regions.  */
@@ -614,7 +615,7 @@ grub_efi_mm_init (void)
 
   /* Allocate memory regions for GRUB's memory management.  */
   add_memory_regions (filtered_memory_map, desc_size,
-		      filtered_memory_map_end, required_pages);
+		      filtered_memory_map_end, target_heap_pages);
 
 #if 0
   /* For debug.  */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 2/5] types.h: add UINT-related macros needed for Argon2
  2020-03-10 18:58 [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
  2020-03-10 18:58 ` [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB Patrick Steinhardt
@ 2020-03-10 18:58 ` Patrick Steinhardt
  2020-03-13 12:49   ` Daniel Kiper
  2020-03-10 18:58 ` [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-10 18:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, Leif Lindholm, agraf, pjones,
	mjg59, phcoder, Milan Broz

For the upcoming import of the Argon2 library, we need the macros
GRUB_UINT32_MAX, GRUB_UINT32_C and GRUB_UINT64_C. Add them as a
preparatory step.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 include/grub/types.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/grub/types.h b/include/grub/types.h
index 035a4b528..1e1463bea 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -137,6 +137,7 @@ typedef grub_int32_t	grub_ssize_t;
 #define GRUB_SHRT_MAX 0x7fff
 #define GRUB_SHRT_MIN (-GRUB_SHRT_MAX - 1)
 #define GRUB_UINT_MAX 4294967295U
+#define GRUB_UINT32_MAX 4294967295U
 #define GRUB_INT_MAX 0x7fffffff
 #define GRUB_INT_MIN (-GRUB_INT_MAX - 1)
 #define GRUB_INT32_MAX 2147483647
@@ -151,6 +152,13 @@ typedef grub_int32_t	grub_ssize_t;
 #endif
 # define GRUB_LONG_MIN (-GRUB_LONG_MAX - 1)
 
+#define GRUB_UINT32_C(x) x ## U
+#if GRUB_ULONG_MAX >> 31 >> 31 >> 1 == 1
+# define GRUB_UINT64_C(x) x##UL
+#else
+# define GRUB_UINT64_C(x) x##ULL
+#endif
+
 typedef grub_uint64_t grub_properly_aligned_t;
 
 #define GRUB_PROPERLY_ALIGNED_ARRAY(name, size) grub_properly_aligned_t name[((size) + sizeof (grub_properly_aligned_t) - 1) / sizeof (grub_properly_aligned_t)]
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-10 18:58 [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
  2020-03-10 18:58 ` [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB Patrick Steinhardt
  2020-03-10 18:58 ` [PATCH v3 2/5] types.h: add UINT-related macros needed for Argon2 Patrick Steinhardt
@ 2020-03-10 18:58 ` Patrick Steinhardt
  2020-03-10 20:44   ` Eli Schwartz
                     ` (3 more replies)
  2020-03-10 18:58 ` [PATCH v3 4/5] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
                   ` (2 subsequent siblings)
  5 siblings, 4 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-10 18:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, Leif Lindholm, agraf, pjones,
	mjg59, phcoder, Milan Broz

In order to support the Argon2 key derival function for LUKS2, we
obviously need to implement Argon2. It doesn't make a lot of sense to
hand-code any crypto, which is why this commit instead imports Argon2
from the cryptsetup project. This commit thus imports the code from the
official reference implementation located at [1]. The code is licensed
under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
2.0 are compatible with GPLv3, it should be fine to import that code.

The code is imported from commit 62358ba (Merge pull request #270 from
bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
several adjustments were required that have beed documented in
"grub-dev.texi".

[1]: https://github.com/P-H-C/phc-winner-argon2

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 docs/grub-dev.texi                            |  64 +++
 grub-core/Makefile.core.def                   |   8 +
 grub-core/lib/argon2/argon2.c                 | 232 ++++++++
 grub-core/lib/argon2/argon2.h                 | 264 +++++++++
 grub-core/lib/argon2/blake2/blake2-impl.h     | 151 +++++
 grub-core/lib/argon2/blake2/blake2.h          |  89 +++
 grub-core/lib/argon2/blake2/blake2b.c         | 388 +++++++++++++
 .../lib/argon2/blake2/blamka-round-ref.h      |  56 ++
 grub-core/lib/argon2/core.c                   | 525 ++++++++++++++++++
 grub-core/lib/argon2/core.h                   | 228 ++++++++
 grub-core/lib/argon2/ref.c                    | 190 +++++++
 11 files changed, 2195 insertions(+)
 create mode 100644 grub-core/lib/argon2/argon2.c
 create mode 100644 grub-core/lib/argon2/argon2.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2-impl.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2b.c
 create mode 100644 grub-core/lib/argon2/blake2/blamka-round-ref.h
 create mode 100644 grub-core/lib/argon2/core.c
 create mode 100644 grub-core/lib/argon2/core.h
 create mode 100644 grub-core/lib/argon2/ref.c

diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index 837873094..4af07f11a 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -489,11 +489,75 @@ GRUB includes some code from other projects, and it is sometimes necessary
 to update it.
 
 @menu
+* Argon2::
 * Gnulib::
 * jsmn::
 * minilzo::
 @end menu
 
+@node Argon2
+@section Argon2
+
+Argon2 is a key derivation function used by LUKS2 in order to derive encryption
+keys from a user-provided password. GRUB imports the official reference
+implementation of Argon2 from @url{https://github.com/P-H-C/phc-winner-argon2}.
+In order to make the library usable for GRUB, we need to perform various
+conversions. This is mainly due to the fact that the imported code makes use of
+types and functions defined in the C standard library, which isn't available.
+Furthermore, using the POSIX wrapper library is not possible as the code needs
+to be part of the kernel.
+
+Updating the code can thus be performed like following:
+
+@example
+$ git clone https://github.com/P-H-C/phc-winner-argon2 argon2
+$ cp argon2/include/argon2.h argon2/src/@{argon2.c,core.c,core.h,ref.c@} \
+    grub-core/lib/argon2/
+$ cp argon2/src/blake2/@{blake2-impl.h,blake2.h,blake2b.c,blamka-round-ref.h@} \
+    grub-core/lib/argon2/blake2/
+$ sed -e 's/UINT32_C/GRUB_UINT32_C/g' \
+      -e 's/UINT64_C/GRUB_UINT64_C/g' \
+      -e 's/UINT32_MAX/GRUB_UINT32_MAX/g' \
+      -e 's/CHAR_BIT/GRUB_CHAR_BIT/g' \
+      -e 's/UINT_MAX/GRUB_UINT_MAX/g' \
+      -e 's/uintptr_t/grub_addr_t/g' \
+      -e 's/size_t/grub_size_t/g' \
+      -e 's/uint32_t/grub_uint32_t/g' \
+      -e 's/uint64_t/grub_uint64_t/g' \
+      -e 's/uint8_t/grub_uint8_t/g' \
+      -e 's/memset/grub_memset/g' \
+      -e 's/memcpy/grub_memcpy/g' \
+      -e 's/malloc/grub_malloc/g' \
+      -e 's/free/grub_free/g' \
+      -e 's/#elif _MSC_VER/#elif defined(_MSC_VER)/' \
+      grub-core/lib/argon2/@{*,blake2/*@}.@{c,h@} -i
+@end example
+
+Afterwards, you need to perform the following manual steps:
+
+@enumerate
+@item Remove all includes of standard library headers, "encoding.h" and
+      "thread.h".
+@item Add includes <grub/mm.h> and <grub/misc.h> to "argon2.h".
+@item Add include <grub/dl.h> and module license declaration to "argon2.c".
+@item Remove the following declarations and functions from "argon2.h" and
+     "argon2.c": argon2_type2string, argon2i_hash_encoded, argon2i_hash_raw,
+     argon2d_hash_encoded, argon2d_hash_raw, argon2id_hash_encoded,
+     argon2id_hash_raw, argon2_compare, argon2_verify, argon2i_verify,
+     argon2d_verify, argon2id_verify, argon2d_ctx, argon2i_ctx, argon2id_ctx,
+     argon2_verify_ctx, argon2d_verify_ctx, argon2i_verify_ctx,
+     argon2id_verify_ctx, argon2_encodedlen.
+@item Move the declaration of `clear_internal_memory()` in "blake2-impl.h" to
+      "blake2b.c".
+@item Remove code guarded by the ARGON2_NO_THREADS macro.
+@item Remove parameters `encoded` and `encodedlen` from `argon2_hash` and remove
+      the encoding block in that function.
+@item Remove parameter verifications in `validate_inputs()` for
+      ARGON2_MIN_PWD_LENGTH, ARGON2_MIN_SECRET, ARGON2_MIN_AD_LENGTH and
+      ARGON2_MAX_MEMORY to fix compiler warnings.
+@item Mark the function argon2_ctx as static.
+@end enumerate
+
 @node Gnulib
 @section Gnulib
 
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 91297e4eb..30147a899 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1181,6 +1181,14 @@ module = {
   common = lib/json/json.c;
 };
 
+module = {
+  name = argon2;
+  common = lib/argon2/argon2.c;
+  common = lib/argon2/core.c;
+  common = lib/argon2/ref.c;
+  common = lib/argon2/blake2/blake2b.c;
+};
+
 module = {
   name = afsplitter;
   common = disk/AFSplitter.c;
diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
new file mode 100644
index 000000000..c77f7f6ff
--- /dev/null
+++ b/grub-core/lib/argon2/argon2.c
@@ -0,0 +1,232 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#include <grub/dl.h>
+
+#include "argon2.h"
+#include "core.h"
+
+GRUB_MOD_LICENSE ("GPLv3");
+
+static int argon2_ctx(argon2_context *context, argon2_type type) {
+    /* 1. Validate all inputs */
+    int result = validate_inputs(context);
+    grub_uint32_t memory_blocks, segment_length;
+    argon2_instance_t instance;
+
+    if (ARGON2_OK != result) {
+        return result;
+    }
+
+    if (Argon2_d != type && Argon2_i != type && Argon2_id != type) {
+        return ARGON2_INCORRECT_TYPE;
+    }
+
+    /* 2. Align memory size */
+    /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
+    memory_blocks = context->m_cost;
+
+    if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) {
+        memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes;
+    }
+
+    segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS);
+    /* Ensure that all segments have equal length */
+    memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS);
+
+    instance.version = context->version;
+    instance.memory = NULL;
+    instance.passes = context->t_cost;
+    instance.memory_blocks = memory_blocks;
+    instance.segment_length = segment_length;
+    instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
+    instance.lanes = context->lanes;
+    instance.threads = context->threads;
+    instance.type = type;
+
+    if (instance.threads > instance.lanes) {
+        instance.threads = instance.lanes;
+    }
+
+    /* 3. Initialization: Hashing inputs, allocating memory, filling first
+     * blocks
+     */
+    result = initialize(&instance, context);
+
+    if (ARGON2_OK != result) {
+        return result;
+    }
+
+    /* 4. Filling memory */
+    result = fill_memory_blocks(&instance);
+
+    if (ARGON2_OK != result) {
+        return result;
+    }
+    /* 5. Finalization */
+    finalize(context, &instance);
+
+    return ARGON2_OK;
+}
+
+int argon2_hash(const grub_uint32_t t_cost, const grub_uint32_t m_cost,
+                const grub_uint32_t parallelism, const void *pwd,
+                const grub_size_t pwdlen, const void *salt, const grub_size_t saltlen,
+                void *hash, const grub_size_t hashlen, argon2_type type,
+                const grub_uint32_t version){
+
+    argon2_context context;
+    int result;
+    grub_uint8_t *out;
+
+    if (pwdlen > ARGON2_MAX_PWD_LENGTH) {
+        return ARGON2_PWD_TOO_LONG;
+    }
+
+    if (saltlen > ARGON2_MAX_SALT_LENGTH) {
+        return ARGON2_SALT_TOO_LONG;
+    }
+
+    if (hashlen > ARGON2_MAX_OUTLEN) {
+        return ARGON2_OUTPUT_TOO_LONG;
+    }
+
+    if (hashlen < ARGON2_MIN_OUTLEN) {
+        return ARGON2_OUTPUT_TOO_SHORT;
+    }
+
+    out = grub_malloc(hashlen);
+    if (!out) {
+        return ARGON2_MEMORY_ALLOCATION_ERROR;
+    }
+
+    context.out = (grub_uint8_t *)out;
+    context.outlen = (grub_uint32_t)hashlen;
+    context.pwd = CONST_CAST(grub_uint8_t *)pwd;
+    context.pwdlen = (grub_uint32_t)pwdlen;
+    context.salt = CONST_CAST(grub_uint8_t *)salt;
+    context.saltlen = (grub_uint32_t)saltlen;
+    context.secret = NULL;
+    context.secretlen = 0;
+    context.ad = NULL;
+    context.adlen = 0;
+    context.t_cost = t_cost;
+    context.m_cost = m_cost;
+    context.lanes = parallelism;
+    context.threads = parallelism;
+    context.allocate_cbk = NULL;
+    context.grub_free_cbk = NULL;
+    context.flags = ARGON2_DEFAULT_FLAGS;
+    context.version = version;
+
+    result = argon2_ctx(&context, type);
+
+    if (result != ARGON2_OK) {
+        clear_internal_memory(out, hashlen);
+        grub_free(out);
+        return result;
+    }
+
+    /* if raw hash requested, write it */
+    if (hash) {
+        grub_memcpy(hash, out, hashlen);
+    }
+
+    clear_internal_memory(out, hashlen);
+    grub_free(out);
+
+    return ARGON2_OK;
+}
+
+const char *argon2_error_message(int error_code) {
+    switch (error_code) {
+    case ARGON2_OK:
+        return "OK";
+    case ARGON2_OUTPUT_PTR_NULL:
+        return "Output pointer is NULL";
+    case ARGON2_OUTPUT_TOO_SHORT:
+        return "Output is too short";
+    case ARGON2_OUTPUT_TOO_LONG:
+        return "Output is too long";
+    case ARGON2_PWD_TOO_SHORT:
+        return "Password is too short";
+    case ARGON2_PWD_TOO_LONG:
+        return "Password is too long";
+    case ARGON2_SALT_TOO_SHORT:
+        return "Salt is too short";
+    case ARGON2_SALT_TOO_LONG:
+        return "Salt is too long";
+    case ARGON2_AD_TOO_SHORT:
+        return "Associated data is too short";
+    case ARGON2_AD_TOO_LONG:
+        return "Associated data is too long";
+    case ARGON2_SECRET_TOO_SHORT:
+        return "Secret is too short";
+    case ARGON2_SECRET_TOO_LONG:
+        return "Secret is too long";
+    case ARGON2_TIME_TOO_SMALL:
+        return "Time cost is too small";
+    case ARGON2_TIME_TOO_LARGE:
+        return "Time cost is too large";
+    case ARGON2_MEMORY_TOO_LITTLE:
+        return "Memory cost is too small";
+    case ARGON2_MEMORY_TOO_MUCH:
+        return "Memory cost is too large";
+    case ARGON2_LANES_TOO_FEW:
+        return "Too few lanes";
+    case ARGON2_LANES_TOO_MANY:
+        return "Too many lanes";
+    case ARGON2_PWD_PTR_MISMATCH:
+        return "Password pointer is NULL, but password length is not 0";
+    case ARGON2_SALT_PTR_MISMATCH:
+        return "Salt pointer is NULL, but salt length is not 0";
+    case ARGON2_SECRET_PTR_MISMATCH:
+        return "Secret pointer is NULL, but secret length is not 0";
+    case ARGON2_AD_PTR_MISMATCH:
+        return "Associated data pointer is NULL, but ad length is not 0";
+    case ARGON2_MEMORY_ALLOCATION_ERROR:
+        return "Memory allocation error";
+    case ARGON2_FREE_MEMORY_CBK_NULL:
+        return "The grub_free memory callback is NULL";
+    case ARGON2_ALLOCATE_MEMORY_CBK_NULL:
+        return "The allocate memory callback is NULL";
+    case ARGON2_INCORRECT_PARAMETER:
+        return "Argon2_Context context is NULL";
+    case ARGON2_INCORRECT_TYPE:
+        return "There is no such version of Argon2";
+    case ARGON2_OUT_PTR_MISMATCH:
+        return "Output pointer mismatch";
+    case ARGON2_THREADS_TOO_FEW:
+        return "Not enough threads";
+    case ARGON2_THREADS_TOO_MANY:
+        return "Too many threads";
+    case ARGON2_MISSING_ARGS:
+        return "Missing arguments";
+    case ARGON2_ENCODING_FAIL:
+        return "Encoding failed";
+    case ARGON2_DECODING_FAIL:
+        return "Decoding failed";
+    case ARGON2_THREAD_FAIL:
+        return "Threading failure";
+    case ARGON2_DECODING_LENGTH_FAIL:
+        return "Some of encoded parameters are too long or too short";
+    case ARGON2_VERIFY_MISMATCH:
+        return "The password does not match the supplied hash";
+    default:
+        return "Unknown error code";
+    }
+}
diff --git a/grub-core/lib/argon2/argon2.h b/grub-core/lib/argon2/argon2.h
new file mode 100644
index 000000000..129f7efbd
--- /dev/null
+++ b/grub-core/lib/argon2/argon2.h
@@ -0,0 +1,264 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef ARGON2_H
+#define ARGON2_H
+
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Symbols visibility control */
+#ifdef A2_VISCTL
+#define ARGON2_PUBLIC __attribute__((visibility("default")))
+#define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
+#elif defined(_MSC_VER)
+#define ARGON2_PUBLIC __declspec(dllexport)
+#define ARGON2_LOCAL
+#else
+#define ARGON2_PUBLIC
+#define ARGON2_LOCAL
+#endif
+
+/*
+ * Argon2 input parameter restrictions
+ */
+
+/* Minimum and maximum number of lanes (degree of parallelism) */
+#define ARGON2_MIN_LANES GRUB_UINT32_C(1)
+#define ARGON2_MAX_LANES GRUB_UINT32_C(0xFFFFFF)
+
+/* Minimum and maximum number of threads */
+#define ARGON2_MIN_THREADS GRUB_UINT32_C(1)
+#define ARGON2_MAX_THREADS GRUB_UINT32_C(0xFFFFFF)
+
+/* Number of synchronization points between lanes per pass */
+#define ARGON2_SYNC_POINTS GRUB_UINT32_C(4)
+
+/* Minimum and maximum digest size in bytes */
+#define ARGON2_MIN_OUTLEN GRUB_UINT32_C(4)
+#define ARGON2_MAX_OUTLEN GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */
+#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */
+
+#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b))
+/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */
+#define ARGON2_MAX_MEMORY_BITS                                                 \
+    ARGON2_MIN(GRUB_UINT32_C(32), (sizeof(void *) * GRUB_CHAR_BIT - 10 - 1))
+#define ARGON2_MAX_MEMORY                                                      \
+    ARGON2_MIN(GRUB_UINT32_C(0xFFFFFFFF), GRUB_UINT64_C(1) << ARGON2_MAX_MEMORY_BITS)
+
+/* Minimum and maximum number of passes */
+#define ARGON2_MIN_TIME GRUB_UINT32_C(1)
+#define ARGON2_MAX_TIME GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum password length in bytes */
+#define ARGON2_MIN_PWD_LENGTH GRUB_UINT32_C(0)
+#define ARGON2_MAX_PWD_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum associated data length in bytes */
+#define ARGON2_MIN_AD_LENGTH GRUB_UINT32_C(0)
+#define ARGON2_MAX_AD_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum salt length in bytes */
+#define ARGON2_MIN_SALT_LENGTH GRUB_UINT32_C(8)
+#define ARGON2_MAX_SALT_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum key length in bytes */
+#define ARGON2_MIN_SECRET GRUB_UINT32_C(0)
+#define ARGON2_MAX_SECRET GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Flags to determine which fields are securely wiped (default = no wipe). */
+#define ARGON2_DEFAULT_FLAGS GRUB_UINT32_C(0)
+#define ARGON2_FLAG_CLEAR_PASSWORD (GRUB_UINT32_C(1) << 0)
+#define ARGON2_FLAG_CLEAR_SECRET (GRUB_UINT32_C(1) << 1)
+
+/* Global flag to determine if we are wiping internal memory buffers. This flag
+ * is defined in core.c and defaults to 1 (wipe internal memory). */
+extern int FLAG_clear_internal_memory;
+
+/* Error codes */
+typedef enum Argon2_ErrorCodes {
+    ARGON2_OK = 0,
+
+    ARGON2_OUTPUT_PTR_NULL = -1,
+
+    ARGON2_OUTPUT_TOO_SHORT = -2,
+    ARGON2_OUTPUT_TOO_LONG = -3,
+
+    ARGON2_PWD_TOO_SHORT = -4,
+    ARGON2_PWD_TOO_LONG = -5,
+
+    ARGON2_SALT_TOO_SHORT = -6,
+    ARGON2_SALT_TOO_LONG = -7,
+
+    ARGON2_AD_TOO_SHORT = -8,
+    ARGON2_AD_TOO_LONG = -9,
+
+    ARGON2_SECRET_TOO_SHORT = -10,
+    ARGON2_SECRET_TOO_LONG = -11,
+
+    ARGON2_TIME_TOO_SMALL = -12,
+    ARGON2_TIME_TOO_LARGE = -13,
+
+    ARGON2_MEMORY_TOO_LITTLE = -14,
+    ARGON2_MEMORY_TOO_MUCH = -15,
+
+    ARGON2_LANES_TOO_FEW = -16,
+    ARGON2_LANES_TOO_MANY = -17,
+
+    ARGON2_PWD_PTR_MISMATCH = -18,    /* NULL ptr with non-zero length */
+    ARGON2_SALT_PTR_MISMATCH = -19,   /* NULL ptr with non-zero length */
+    ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */
+    ARGON2_AD_PTR_MISMATCH = -21,     /* NULL ptr with non-zero length */
+
+    ARGON2_MEMORY_ALLOCATION_ERROR = -22,
+
+    ARGON2_FREE_MEMORY_CBK_NULL = -23,
+    ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24,
+
+    ARGON2_INCORRECT_PARAMETER = -25,
+    ARGON2_INCORRECT_TYPE = -26,
+
+    ARGON2_OUT_PTR_MISMATCH = -27,
+
+    ARGON2_THREADS_TOO_FEW = -28,
+    ARGON2_THREADS_TOO_MANY = -29,
+
+    ARGON2_MISSING_ARGS = -30,
+
+    ARGON2_ENCODING_FAIL = -31,
+
+    ARGON2_DECODING_FAIL = -32,
+
+    ARGON2_THREAD_FAIL = -33,
+
+    ARGON2_DECODING_LENGTH_FAIL = -34,
+
+    ARGON2_VERIFY_MISMATCH = -35
+} argon2_error_codes;
+
+/* Memory allocator types --- for external allocation */
+typedef int (*allocate_fptr)(grub_uint8_t **memory, grub_size_t bytes_to_allocate);
+typedef void (*deallocate_fptr)(grub_uint8_t *memory, grub_size_t bytes_to_allocate);
+
+/* Argon2 external data structures */
+
+/*
+ *****
+ * Context: structure to hold Argon2 inputs:
+ *  output array and its length,
+ *  password and its length,
+ *  salt and its length,
+ *  secret and its length,
+ *  associated data and its length,
+ *  number of passes, amount of used memory (in KBytes, can be rounded up a bit)
+ *  number of parallel threads that will be run.
+ * All the parameters above affect the output hash value.
+ * Additionally, two function pointers can be provided to allocate and
+ * deallocate the memory (if NULL, memory will be allocated internally).
+ * Also, three flags indicate whether to erase password, secret as soon as they
+ * are pre-hashed (and thus not needed anymore), and the entire memory
+ *****
+ * Simplest situation: you have output array out[8], password is stored in
+ * pwd[32], salt is stored in salt[16], you do not have keys nor associated
+ * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with
+ * 4 parallel lanes.
+ * You want to erase the password, but you're OK with last pass not being
+ * erased. You want to use the default memory allocator.
+ * Then you initialize:
+ Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false)
+ */
+typedef struct Argon2_Context {
+    grub_uint8_t *out;    /* output array */
+    grub_uint32_t outlen; /* digest length */
+
+    grub_uint8_t *pwd;    /* password array */
+    grub_uint32_t pwdlen; /* password length */
+
+    grub_uint8_t *salt;    /* salt array */
+    grub_uint32_t saltlen; /* salt length */
+
+    grub_uint8_t *secret;    /* key array */
+    grub_uint32_t secretlen; /* key length */
+
+    grub_uint8_t *ad;    /* associated data array */
+    grub_uint32_t adlen; /* associated data length */
+
+    grub_uint32_t t_cost;  /* number of passes */
+    grub_uint32_t m_cost;  /* amount of memory requested (KB) */
+    grub_uint32_t lanes;   /* number of lanes */
+    grub_uint32_t threads; /* maximum number of threads */
+
+    grub_uint32_t version; /* version number */
+
+    allocate_fptr allocate_cbk; /* pointer to memory allocator */
+    deallocate_fptr grub_free_cbk;   /* pointer to memory deallocator */
+
+    grub_uint32_t flags; /* array of bool options */
+} argon2_context;
+
+/* Argon2 primitive type */
+typedef enum Argon2_type {
+  Argon2_d = 0,
+  Argon2_i = 1,
+  Argon2_id = 2
+} argon2_type;
+
+/* Version of the algorithm */
+typedef enum Argon2_version {
+    ARGON2_VERSION_10 = 0x10,
+    ARGON2_VERSION_13 = 0x13,
+    ARGON2_VERSION_NUMBER = ARGON2_VERSION_13
+} argon2_version;
+
+/**
+ * Hashes a password with Argon2, producing a raw hash at @hash
+ * @param t_cost Number of iterations
+ * @param m_cost Sets memory usage to m_cost kibibytes
+ * @param parallelism Number of threads and compute lanes
+ * @param pwd Pointer to password
+ * @param pwdlen Password size in bytes
+ * @param salt Pointer to salt
+ * @param saltlen Salt size in bytes
+ * @param hash Buffer where to write the raw hash - updated by the function
+ * @param hashlen Desired length of the hash in bytes
+ * @pre   Different parallelism levels will give different results
+ * @pre   Returns ARGON2_OK if successful
+ */
+ARGON2_PUBLIC int argon2_hash(const grub_uint32_t t_cost, const grub_uint32_t m_cost,
+                              const grub_uint32_t parallelism, const void *pwd,
+                              const grub_size_t pwdlen, const void *salt,
+                              const grub_size_t saltlen, void *hash,
+                              const grub_size_t hashlen, argon2_type type,
+                              const grub_uint32_t version);
+
+/**
+ * Get the associated error message for given error code
+ * @return  The error message associated with the given error code
+ */
+ARGON2_PUBLIC const char *argon2_error_message(int error_code);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/grub-core/lib/argon2/blake2/blake2-impl.h b/grub-core/lib/argon2/blake2/blake2-impl.h
new file mode 100644
index 000000000..3a795680b
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blake2-impl.h
@@ -0,0 +1,151 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef PORTABLE_BLAKE2_IMPL_H
+#define PORTABLE_BLAKE2_IMPL_H
+
+#if defined(_MSC_VER)
+#define BLAKE2_INLINE __inline
+#elif defined(__GNUC__) || defined(__clang__)
+#define BLAKE2_INLINE __inline__
+#else
+#define BLAKE2_INLINE
+#endif
+
+/* Argon2 Team - Begin Code */
+/*
+   Not an exhaustive list, but should cover the majority of modern platforms
+   Additionally, the code will always be correct---this is only a performance
+   tweak.
+*/
+#if (defined(__BYTE_ORDER__) &&                                                \
+     (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) ||                           \
+    defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \
+    defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) ||       \
+    defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) ||                \
+    defined(_M_ARM)
+#define NATIVE_LITTLE_ENDIAN
+#endif
+/* Argon2 Team - End Code */
+
+static BLAKE2_INLINE grub_uint32_t load32(const void *src) {
+#if defined(NATIVE_LITTLE_ENDIAN)
+    grub_uint32_t w;
+    grub_memcpy(&w, src, sizeof w);
+    return w;
+#else
+    const grub_uint8_t *p = (const grub_uint8_t *)src;
+    grub_uint32_t w = *p++;
+    w |= (grub_uint32_t)(*p++) << 8;
+    w |= (grub_uint32_t)(*p++) << 16;
+    w |= (grub_uint32_t)(*p++) << 24;
+    return w;
+#endif
+}
+
+static BLAKE2_INLINE grub_uint64_t load64(const void *src) {
+#if defined(NATIVE_LITTLE_ENDIAN)
+    grub_uint64_t w;
+    grub_memcpy(&w, src, sizeof w);
+    return w;
+#else
+    const grub_uint8_t *p = (const grub_uint8_t *)src;
+    grub_uint64_t w = *p++;
+    w |= (grub_uint64_t)(*p++) << 8;
+    w |= (grub_uint64_t)(*p++) << 16;
+    w |= (grub_uint64_t)(*p++) << 24;
+    w |= (grub_uint64_t)(*p++) << 32;
+    w |= (grub_uint64_t)(*p++) << 40;
+    w |= (grub_uint64_t)(*p++) << 48;
+    w |= (grub_uint64_t)(*p++) << 56;
+    return w;
+#endif
+}
+
+static BLAKE2_INLINE void store32(void *dst, grub_uint32_t w) {
+#if defined(NATIVE_LITTLE_ENDIAN)
+    grub_memcpy(dst, &w, sizeof w);
+#else
+    grub_uint8_t *p = (grub_uint8_t *)dst;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+#endif
+}
+
+static BLAKE2_INLINE void store64(void *dst, grub_uint64_t w) {
+#if defined(NATIVE_LITTLE_ENDIAN)
+    grub_memcpy(dst, &w, sizeof w);
+#else
+    grub_uint8_t *p = (grub_uint8_t *)dst;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+#endif
+}
+
+static BLAKE2_INLINE grub_uint64_t load48(const void *src) {
+    const grub_uint8_t *p = (const grub_uint8_t *)src;
+    grub_uint64_t w = *p++;
+    w |= (grub_uint64_t)(*p++) << 8;
+    w |= (grub_uint64_t)(*p++) << 16;
+    w |= (grub_uint64_t)(*p++) << 24;
+    w |= (grub_uint64_t)(*p++) << 32;
+    w |= (grub_uint64_t)(*p++) << 40;
+    return w;
+}
+
+static BLAKE2_INLINE void store48(void *dst, grub_uint64_t w) {
+    grub_uint8_t *p = (grub_uint8_t *)dst;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+}
+
+static BLAKE2_INLINE grub_uint32_t rotr32(const grub_uint32_t w, const unsigned c) {
+    return (w >> c) | (w << (32 - c));
+}
+
+static BLAKE2_INLINE grub_uint64_t rotr64(const grub_uint64_t w, const unsigned c) {
+    return (w >> c) | (w << (64 - c));
+}
+
+#endif
diff --git a/grub-core/lib/argon2/blake2/blake2.h b/grub-core/lib/argon2/blake2/blake2.h
new file mode 100644
index 000000000..4e8efeb22
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blake2.h
@@ -0,0 +1,89 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef PORTABLE_BLAKE2_H
+#define PORTABLE_BLAKE2_H
+
+#include "../argon2.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+enum blake2b_constant {
+    BLAKE2B_BLOCKBYTES = 128,
+    BLAKE2B_OUTBYTES = 64,
+    BLAKE2B_KEYBYTES = 64,
+    BLAKE2B_SALTBYTES = 16,
+    BLAKE2B_PERSONALBYTES = 16
+};
+
+#pragma pack(push, 1)
+typedef struct __blake2b_param {
+    grub_uint8_t digest_length;                   /* 1 */
+    grub_uint8_t key_length;                      /* 2 */
+    grub_uint8_t fanout;                          /* 3 */
+    grub_uint8_t depth;                           /* 4 */
+    grub_uint32_t leaf_length;                    /* 8 */
+    grub_uint64_t node_offset;                    /* 16 */
+    grub_uint8_t node_depth;                      /* 17 */
+    grub_uint8_t inner_length;                    /* 18 */
+    grub_uint8_t reserved[14];                    /* 32 */
+    grub_uint8_t salt[BLAKE2B_SALTBYTES];         /* 48 */
+    grub_uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
+} blake2b_param;
+#pragma pack(pop)
+
+typedef struct __blake2b_state {
+    grub_uint64_t h[8];
+    grub_uint64_t t[2];
+    grub_uint64_t f[2];
+    grub_uint8_t buf[BLAKE2B_BLOCKBYTES];
+    unsigned buflen;
+    unsigned outlen;
+    grub_uint8_t last_node;
+} blake2b_state;
+
+/* Ensure param structs have not been wrongly padded */
+/* Poor man's static_assert */
+enum {
+    blake2_size_check_0 = 1 / !!(GRUB_CHAR_BIT == 8),
+    blake2_size_check_2 =
+        1 / !!(sizeof(blake2b_param) == sizeof(grub_uint64_t) * GRUB_CHAR_BIT)
+};
+
+/* Streaming API */
+ARGON2_LOCAL int blake2b_init(blake2b_state *S, grub_size_t outlen);
+ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, grub_size_t outlen, const void *key,
+                     grub_size_t keylen);
+ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
+ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, grub_size_t inlen);
+ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, grub_size_t outlen);
+
+/* Simple API */
+ARGON2_LOCAL int blake2b(void *out, grub_size_t outlen, const void *in, grub_size_t inlen,
+                         const void *key, grub_size_t keylen);
+
+/* Argon2 Team - Begin Code */
+ARGON2_LOCAL int blake2b_long(void *out, grub_size_t outlen, const void *in, grub_size_t inlen);
+/* Argon2 Team - End Code */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/grub-core/lib/argon2/blake2/blake2b.c b/grub-core/lib/argon2/blake2/blake2b.c
new file mode 100644
index 000000000..53abd7bef
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blake2b.c
@@ -0,0 +1,388 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#include "blake2.h"
+#include "blake2-impl.h"
+
+static const grub_uint64_t blake2b_IV[8] = {
+    GRUB_UINT64_C(0x6a09e667f3bcc908), GRUB_UINT64_C(0xbb67ae8584caa73b),
+    GRUB_UINT64_C(0x3c6ef372fe94f82b), GRUB_UINT64_C(0xa54ff53a5f1d36f1),
+    GRUB_UINT64_C(0x510e527fade682d1), GRUB_UINT64_C(0x9b05688c2b3e6c1f),
+    GRUB_UINT64_C(0x1f83d9abfb41bd6b), GRUB_UINT64_C(0x5be0cd19137e2179)};
+
+static const unsigned int blake2b_sigma[12][16] = {
+    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
+    {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
+    {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
+    {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
+    {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
+    {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
+    {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
+    {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
+    {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
+    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
+};
+
+void clear_internal_memory(void *v, grub_size_t n);
+
+static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S) {
+    S->f[1] = (grub_uint64_t)-1;
+}
+
+static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S) {
+    if (S->last_node) {
+        blake2b_set_lastnode(S);
+    }
+    S->f[0] = (grub_uint64_t)-1;
+}
+
+static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S,
+                                                    grub_uint64_t inc) {
+    S->t[0] += inc;
+    S->t[1] += (S->t[0] < inc);
+}
+
+static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) {
+    clear_internal_memory(S, sizeof(*S));      /* wipe */
+    blake2b_set_lastblock(S); /* invalidate for further use */
+}
+
+static BLAKE2_INLINE void blake2b_init0(blake2b_state *S) {
+    grub_memset(S, 0, sizeof(*S));
+    grub_memcpy(S->h, blake2b_IV, sizeof(S->h));
+}
+
+int blake2b_init_param(blake2b_state *S, const blake2b_param *P) {
+    const unsigned char *p = (const unsigned char *)P;
+    unsigned int i;
+
+    if (NULL == P || NULL == S) {
+        return -1;
+    }
+
+    blake2b_init0(S);
+    /* IV XOR Parameter Block */
+    for (i = 0; i < 8; ++i) {
+        S->h[i] ^= load64(&p[i * sizeof(S->h[i])]);
+    }
+    S->outlen = P->digest_length;
+    return 0;
+}
+
+/* Sequential blake2b initialization */
+int blake2b_init(blake2b_state *S, grub_size_t outlen) {
+    blake2b_param P;
+
+    if (S == NULL) {
+        return -1;
+    }
+
+    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
+        blake2b_invalidate_state(S);
+        return -1;
+    }
+
+    /* Setup Parameter Block for unkeyed BLAKE2 */
+    P.digest_length = (grub_uint8_t)outlen;
+    P.key_length = 0;
+    P.fanout = 1;
+    P.depth = 1;
+    P.leaf_length = 0;
+    P.node_offset = 0;
+    P.node_depth = 0;
+    P.inner_length = 0;
+    grub_memset(P.reserved, 0, sizeof(P.reserved));
+    grub_memset(P.salt, 0, sizeof(P.salt));
+    grub_memset(P.personal, 0, sizeof(P.personal));
+
+    return blake2b_init_param(S, &P);
+}
+
+int blake2b_init_key(blake2b_state *S, grub_size_t outlen, const void *key,
+                     grub_size_t keylen) {
+    blake2b_param P;
+
+    if (S == NULL) {
+        return -1;
+    }
+
+    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
+        blake2b_invalidate_state(S);
+        return -1;
+    }
+
+    if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) {
+        blake2b_invalidate_state(S);
+        return -1;
+    }
+
+    /* Setup Parameter Block for keyed BLAKE2 */
+    P.digest_length = (grub_uint8_t)outlen;
+    P.key_length = (grub_uint8_t)keylen;
+    P.fanout = 1;
+    P.depth = 1;
+    P.leaf_length = 0;
+    P.node_offset = 0;
+    P.node_depth = 0;
+    P.inner_length = 0;
+    grub_memset(P.reserved, 0, sizeof(P.reserved));
+    grub_memset(P.salt, 0, sizeof(P.salt));
+    grub_memset(P.personal, 0, sizeof(P.personal));
+
+    if (blake2b_init_param(S, &P) < 0) {
+        blake2b_invalidate_state(S);
+        return -1;
+    }
+
+    {
+        grub_uint8_t block[BLAKE2B_BLOCKBYTES];
+        grub_memset(block, 0, BLAKE2B_BLOCKBYTES);
+        grub_memcpy(block, key, keylen);
+        blake2b_update(S, block, BLAKE2B_BLOCKBYTES);
+        /* Burn the key from stack */
+        clear_internal_memory(block, BLAKE2B_BLOCKBYTES);
+    }
+    return 0;
+}
+
+static void blake2b_compress(blake2b_state *S, const grub_uint8_t *block) {
+    grub_uint64_t m[16];
+    grub_uint64_t v[16];
+    unsigned int i, r;
+
+    for (i = 0; i < 16; ++i) {
+        m[i] = load64(block + i * sizeof(m[i]));
+    }
+
+    for (i = 0; i < 8; ++i) {
+        v[i] = S->h[i];
+    }
+
+    v[8] = blake2b_IV[0];
+    v[9] = blake2b_IV[1];
+    v[10] = blake2b_IV[2];
+    v[11] = blake2b_IV[3];
+    v[12] = blake2b_IV[4] ^ S->t[0];
+    v[13] = blake2b_IV[5] ^ S->t[1];
+    v[14] = blake2b_IV[6] ^ S->f[0];
+    v[15] = blake2b_IV[7] ^ S->f[1];
+
+#define G(r, i, a, b, c, d)                                                    \
+    do {                                                                       \
+        a = a + b + m[blake2b_sigma[r][2 * i + 0]];                            \
+        d = rotr64(d ^ a, 32);                                                 \
+        c = c + d;                                                             \
+        b = rotr64(b ^ c, 24);                                                 \
+        a = a + b + m[blake2b_sigma[r][2 * i + 1]];                            \
+        d = rotr64(d ^ a, 16);                                                 \
+        c = c + d;                                                             \
+        b = rotr64(b ^ c, 63);                                                 \
+    } while ((void)0, 0)
+
+#define ROUND(r)                                                               \
+    do {                                                                       \
+        G(r, 0, v[0], v[4], v[8], v[12]);                                      \
+        G(r, 1, v[1], v[5], v[9], v[13]);                                      \
+        G(r, 2, v[2], v[6], v[10], v[14]);                                     \
+        G(r, 3, v[3], v[7], v[11], v[15]);                                     \
+        G(r, 4, v[0], v[5], v[10], v[15]);                                     \
+        G(r, 5, v[1], v[6], v[11], v[12]);                                     \
+        G(r, 6, v[2], v[7], v[8], v[13]);                                      \
+        G(r, 7, v[3], v[4], v[9], v[14]);                                      \
+    } while ((void)0, 0)
+
+    for (r = 0; r < 12; ++r) {
+        ROUND(r);
+    }
+
+    for (i = 0; i < 8; ++i) {
+        S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
+    }
+
+#undef G
+#undef ROUND
+}
+
+int blake2b_update(blake2b_state *S, const void *in, grub_size_t inlen) {
+    const grub_uint8_t *pin = (const grub_uint8_t *)in;
+
+    if (inlen == 0) {
+        return 0;
+    }
+
+    /* Sanity check */
+    if (S == NULL || in == NULL) {
+        return -1;
+    }
+
+    /* Is this a reused state? */
+    if (S->f[0] != 0) {
+        return -1;
+    }
+
+    if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) {
+        /* Complete current block */
+        grub_size_t left = S->buflen;
+        grub_size_t fill = BLAKE2B_BLOCKBYTES - left;
+        grub_memcpy(&S->buf[left], pin, fill);
+        blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
+        blake2b_compress(S, S->buf);
+        S->buflen = 0;
+        inlen -= fill;
+        pin += fill;
+        /* Avoid buffer copies when possible */
+        while (inlen > BLAKE2B_BLOCKBYTES) {
+            blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
+            blake2b_compress(S, pin);
+            inlen -= BLAKE2B_BLOCKBYTES;
+            pin += BLAKE2B_BLOCKBYTES;
+        }
+    }
+    grub_memcpy(&S->buf[S->buflen], pin, inlen);
+    S->buflen += (unsigned int)inlen;
+    return 0;
+}
+
+int blake2b_final(blake2b_state *S, void *out, grub_size_t outlen) {
+    grub_uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
+    unsigned int i;
+
+    /* Sanity checks */
+    if (S == NULL || out == NULL || outlen < S->outlen) {
+        return -1;
+    }
+
+    /* Is this a reused state? */
+    if (S->f[0] != 0) {
+        return -1;
+    }
+
+    blake2b_increment_counter(S, S->buflen);
+    blake2b_set_lastblock(S);
+    grub_memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */
+    blake2b_compress(S, S->buf);
+
+    for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */
+        store64(buffer + sizeof(S->h[i]) * i, S->h[i]);
+    }
+
+    grub_memcpy(out, buffer, S->outlen);
+    clear_internal_memory(buffer, sizeof(buffer));
+    clear_internal_memory(S->buf, sizeof(S->buf));
+    clear_internal_memory(S->h, sizeof(S->h));
+    return 0;
+}
+
+int blake2b(void *out, grub_size_t outlen, const void *in, grub_size_t inlen,
+            const void *key, grub_size_t keylen) {
+    blake2b_state S;
+    int ret = -1;
+
+    /* Verify parameters */
+    if (NULL == in && inlen > 0) {
+        goto fail;
+    }
+
+    if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) {
+        goto fail;
+    }
+
+    if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) {
+        goto fail;
+    }
+
+    if (keylen > 0) {
+        if (blake2b_init_key(&S, outlen, key, keylen) < 0) {
+            goto fail;
+        }
+    } else {
+        if (blake2b_init(&S, outlen) < 0) {
+            goto fail;
+        }
+    }
+
+    if (blake2b_update(&S, in, inlen) < 0) {
+        goto fail;
+    }
+    ret = blake2b_final(&S, out, outlen);
+
+fail:
+    clear_internal_memory(&S, sizeof(S));
+    return ret;
+}
+
+/* Argon2 Team - Begin Code */
+int blake2b_long(void *pout, grub_size_t outlen, const void *in, grub_size_t inlen) {
+    grub_uint8_t *out = (grub_uint8_t *)pout;
+    blake2b_state blake_state;
+    grub_uint8_t outlen_bytes[sizeof(grub_uint32_t)] = {0};
+    int ret = -1;
+
+    if (outlen > GRUB_UINT32_MAX) {
+        goto fail;
+    }
+
+    /* Ensure little-endian byte order! */
+    store32(outlen_bytes, (grub_uint32_t)outlen);
+
+#define TRY(statement)                                                         \
+    do {                                                                       \
+        ret = statement;                                                       \
+        if (ret < 0) {                                                         \
+            goto fail;                                                         \
+        }                                                                      \
+    } while ((void)0, 0)
+
+    if (outlen <= BLAKE2B_OUTBYTES) {
+        TRY(blake2b_init(&blake_state, outlen));
+        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
+        TRY(blake2b_update(&blake_state, in, inlen));
+        TRY(blake2b_final(&blake_state, out, outlen));
+    } else {
+        grub_uint32_t toproduce;
+        grub_uint8_t out_buffer[BLAKE2B_OUTBYTES];
+        grub_uint8_t in_buffer[BLAKE2B_OUTBYTES];
+        TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES));
+        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
+        TRY(blake2b_update(&blake_state, in, inlen));
+        TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES));
+        grub_memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
+        out += BLAKE2B_OUTBYTES / 2;
+        toproduce = (grub_uint32_t)outlen - BLAKE2B_OUTBYTES / 2;
+
+        while (toproduce > BLAKE2B_OUTBYTES) {
+            grub_memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
+            TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer,
+                        BLAKE2B_OUTBYTES, NULL, 0));
+            grub_memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
+            out += BLAKE2B_OUTBYTES / 2;
+            toproduce -= BLAKE2B_OUTBYTES / 2;
+        }
+
+        grub_memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
+        TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL,
+                    0));
+        grub_memcpy(out, out_buffer, toproduce);
+    }
+fail:
+    clear_internal_memory(&blake_state, sizeof(blake_state));
+    return ret;
+#undef TRY
+}
+/* Argon2 Team - End Code */
diff --git a/grub-core/lib/argon2/blake2/blamka-round-ref.h b/grub-core/lib/argon2/blake2/blamka-round-ref.h
new file mode 100644
index 000000000..7f0071ada
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blamka-round-ref.h
@@ -0,0 +1,56 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef BLAKE_ROUND_MKA_H
+#define BLAKE_ROUND_MKA_H
+
+#include "blake2.h"
+#include "blake2-impl.h"
+
+/* designed by the Lyra PHC team */
+static BLAKE2_INLINE grub_uint64_t fBlaMka(grub_uint64_t x, grub_uint64_t y) {
+    const grub_uint64_t m = GRUB_UINT64_C(0xFFFFFFFF);
+    const grub_uint64_t xy = (x & m) * (y & m);
+    return x + y + 2 * xy;
+}
+
+#define G(a, b, c, d)                                                          \
+    do {                                                                       \
+        a = fBlaMka(a, b);                                                     \
+        d = rotr64(d ^ a, 32);                                                 \
+        c = fBlaMka(c, d);                                                     \
+        b = rotr64(b ^ c, 24);                                                 \
+        a = fBlaMka(a, b);                                                     \
+        d = rotr64(d ^ a, 16);                                                 \
+        c = fBlaMka(c, d);                                                     \
+        b = rotr64(b ^ c, 63);                                                 \
+    } while ((void)0, 0)
+
+#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,   \
+                           v12, v13, v14, v15)                                 \
+    do {                                                                       \
+        G(v0, v4, v8, v12);                                                    \
+        G(v1, v5, v9, v13);                                                    \
+        G(v2, v6, v10, v14);                                                   \
+        G(v3, v7, v11, v15);                                                   \
+        G(v0, v5, v10, v15);                                                   \
+        G(v1, v6, v11, v12);                                                   \
+        G(v2, v7, v8, v13);                                                    \
+        G(v3, v4, v9, v14);                                                    \
+    } while ((void)0, 0)
+
+#endif
diff --git a/grub-core/lib/argon2/core.c b/grub-core/lib/argon2/core.c
new file mode 100644
index 000000000..1bb8e22e2
--- /dev/null
+++ b/grub-core/lib/argon2/core.c
@@ -0,0 +1,525 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+/*For memory wiping*/
+#ifdef _MSC_VER
+#include <windows.h>
+#include <winbase.h> /* For SecureZeroMemory */
+#endif
+#if defined __STDC_LIB_EXT1__
+#define __STDC_WANT_LIB_EXT1__ 1
+#endif
+#define VC_GE_2005(version) (version >= 1400)
+
+/* for explicit_bzero() on glibc */
+#define _DEFAULT_SOURCE
+
+#include "core.h"
+#include "blake2/blake2.h"
+#include "blake2/blake2-impl.h"
+
+#ifdef GENKAT
+#include "genkat.h"
+#endif
+
+#if defined(__clang__)
+#if __has_attribute(optnone)
+#define NOT_OPTIMIZED __attribute__((optnone))
+#endif
+#elif defined(__GNUC__)
+#define GCC_VERSION                                                            \
+    (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#if GCC_VERSION >= 40400
+#define NOT_OPTIMIZED __attribute__((optimize("O0")))
+#endif
+#endif
+#ifndef NOT_OPTIMIZED
+#define NOT_OPTIMIZED
+#endif
+
+/***************Instance and Position constructors**********/
+void init_block_value(block *b, grub_uint8_t in) { grub_memset(b->v, in, sizeof(b->v)); }
+
+void copy_block(block *dst, const block *src) {
+    grub_memcpy(dst->v, src->v, sizeof(grub_uint64_t) * ARGON2_QWORDS_IN_BLOCK);
+}
+
+void xor_block(block *dst, const block *src) {
+    int i;
+    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
+        dst->v[i] ^= src->v[i];
+    }
+}
+
+static void load_block(block *dst, const void *input) {
+    unsigned i;
+    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
+        dst->v[i] = load64((const grub_uint8_t *)input + i * sizeof(dst->v[i]));
+    }
+}
+
+static void store_block(void *output, const block *src) {
+    unsigned i;
+    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
+        store64((grub_uint8_t *)output + i * sizeof(src->v[i]), src->v[i]);
+    }
+}
+
+/***************Memory functions*****************/
+
+int allocate_memory(const argon2_context *context, grub_uint8_t **memory,
+                    grub_size_t num, grub_size_t size) {
+    grub_size_t memory_size = num*size;
+    if (memory == NULL) {
+        return ARGON2_MEMORY_ALLOCATION_ERROR;
+    }
+
+    /* 1. Check for multiplication overflow */
+    if (size != 0 && memory_size / size != num) {
+        return ARGON2_MEMORY_ALLOCATION_ERROR;
+    }
+
+    /* 2. Try to allocate with appropriate allocator */
+    if (context->allocate_cbk) {
+        (context->allocate_cbk)(memory, memory_size);
+    } else {
+        *memory = grub_malloc(memory_size);
+    }
+
+    if (*memory == NULL) {
+        return ARGON2_MEMORY_ALLOCATION_ERROR;
+    }
+
+    return ARGON2_OK;
+}
+
+void grub_free_memory(const argon2_context *context, grub_uint8_t *memory,
+                 grub_size_t num, grub_size_t size) {
+    grub_size_t memory_size = num*size;
+    clear_internal_memory(memory, memory_size);
+    if (context->grub_free_cbk) {
+        (context->grub_free_cbk)(memory, memory_size);
+    } else {
+        grub_free(memory);
+    }
+}
+
+#if defined(__OpenBSD__)
+#define HAVE_EXPLICIT_BZERO 1
+#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
+#if __GLIBC_PREREQ(2,25)
+#define HAVE_EXPLICIT_BZERO 1
+#endif
+#endif
+
+void NOT_OPTIMIZED secure_wipe_memory(void *v, grub_size_t n) {
+#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER)
+    SecureZeroMemory(v, n);
+#elif defined grub_memset_s
+    grub_memset_s(v, n, 0, n);
+#elif defined(HAVE_EXPLICIT_BZERO)
+    explicit_bzero(v, n);
+#else
+    static void *(*const volatile grub_memset_sec)(void *, int, grub_size_t) = &grub_memset;
+    grub_memset_sec(v, 0, n);
+#endif
+}
+
+/* Memory clear flag defaults to true. */
+int FLAG_clear_internal_memory = 1;
+void clear_internal_memory(void *v, grub_size_t n) {
+  if (FLAG_clear_internal_memory && v) {
+    secure_wipe_memory(v, n);
+  }
+}
+
+void finalize(const argon2_context *context, argon2_instance_t *instance) {
+    if (context != NULL && instance != NULL) {
+        block blockhash;
+        grub_uint32_t l;
+
+        copy_block(&blockhash, instance->memory + instance->lane_length - 1);
+
+        /* XOR the last blocks */
+        for (l = 1; l < instance->lanes; ++l) {
+            grub_uint32_t last_block_in_lane =
+                l * instance->lane_length + (instance->lane_length - 1);
+            xor_block(&blockhash, instance->memory + last_block_in_lane);
+        }
+
+        /* Hash the result */
+        {
+            grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
+            store_block(blockhash_bytes, &blockhash);
+            blake2b_long(context->out, context->outlen, blockhash_bytes,
+                         ARGON2_BLOCK_SIZE);
+            /* clear blockhash and blockhash_bytes */
+            clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE);
+            clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
+        }
+
+#ifdef GENKAT
+        print_tag(context->out, context->outlen);
+#endif
+
+        grub_free_memory(context, (grub_uint8_t *)instance->memory,
+                    instance->memory_blocks, sizeof(block));
+    }
+}
+
+grub_uint32_t index_alpha(const argon2_instance_t *instance,
+                     const argon2_position_t *position, grub_uint32_t pseudo_rand,
+                     int same_lane) {
+    /*
+     * Pass 0:
+     *      This lane : all already finished segments plus already constructed
+     * blocks in this segment
+     *      Other lanes : all already finished segments
+     * Pass 1+:
+     *      This lane : (SYNC_POINTS - 1) last segments plus already constructed
+     * blocks in this segment
+     *      Other lanes : (SYNC_POINTS - 1) last segments
+     */
+    grub_uint32_t reference_area_size;
+    grub_uint64_t relative_position;
+    grub_uint32_t start_position, absolute_position;
+
+    if (0 == position->pass) {
+        /* First pass */
+        if (0 == position->slice) {
+            /* First slice */
+            reference_area_size =
+                position->index - 1; /* all but the previous */
+        } else {
+            if (same_lane) {
+                /* The same lane => add current segment */
+                reference_area_size =
+                    position->slice * instance->segment_length +
+                    position->index - 1;
+            } else {
+                reference_area_size =
+                    position->slice * instance->segment_length +
+                    ((position->index == 0) ? (-1) : 0);
+            }
+        }
+    } else {
+        /* Second pass */
+        if (same_lane) {
+            reference_area_size = instance->lane_length -
+                                  instance->segment_length + position->index -
+                                  1;
+        } else {
+            reference_area_size = instance->lane_length -
+                                  instance->segment_length +
+                                  ((position->index == 0) ? (-1) : 0);
+        }
+    }
+
+    /* 1.2.4. Mapping pseudo_rand to 0..<reference_area_size-1> and produce
+     * relative position */
+    relative_position = pseudo_rand;
+    relative_position = relative_position * relative_position >> 32;
+    relative_position = reference_area_size - 1 -
+                        (reference_area_size * relative_position >> 32);
+
+    /* 1.2.5 Computing starting position */
+    start_position = 0;
+
+    if (0 != position->pass) {
+        start_position = (position->slice == ARGON2_SYNC_POINTS - 1)
+                             ? 0
+                             : (position->slice + 1) * instance->segment_length;
+    }
+
+    /* 1.2.6. Computing absolute position */
+    absolute_position = (start_position + relative_position) %
+                        instance->lane_length; /* absolute position */
+    return absolute_position;
+}
+
+/* Single-threaded version for p=1 case */
+static int fill_memory_blocks_st(argon2_instance_t *instance) {
+    grub_uint32_t r, s, l;
+
+    for (r = 0; r < instance->passes; ++r) {
+        for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
+            for (l = 0; l < instance->lanes; ++l) {
+                argon2_position_t position = {r, l, (grub_uint8_t)s, 0};
+                fill_segment(instance, position);
+            }
+        }
+#ifdef GENKAT
+        internal_kat(instance, r); /* Print all memory blocks */
+#endif
+    }
+    return ARGON2_OK;
+}
+
+int fill_memory_blocks(argon2_instance_t *instance) {
+	if (instance == NULL || instance->lanes == 0) {
+	    return ARGON2_INCORRECT_PARAMETER;
+    }
+    return fill_memory_blocks_st(instance);
+}
+
+int validate_inputs(const argon2_context *context) {
+    if (NULL == context) {
+        return ARGON2_INCORRECT_PARAMETER;
+    }
+
+    if (NULL == context->out) {
+        return ARGON2_OUTPUT_PTR_NULL;
+    }
+
+    /* Validate output length */
+    if (ARGON2_MIN_OUTLEN > context->outlen) {
+        return ARGON2_OUTPUT_TOO_SHORT;
+    }
+
+    if (ARGON2_MAX_OUTLEN < context->outlen) {
+        return ARGON2_OUTPUT_TOO_LONG;
+    }
+
+    /* Validate password (required param) */
+    if (NULL == context->pwd) {
+        if (0 != context->pwdlen) {
+            return ARGON2_PWD_PTR_MISMATCH;
+        }
+    }
+
+    if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {
+        return ARGON2_PWD_TOO_LONG;
+    }
+
+    /* Validate salt (required param) */
+    if (NULL == context->salt) {
+        if (0 != context->saltlen) {
+            return ARGON2_SALT_PTR_MISMATCH;
+        }
+    }
+
+    if (ARGON2_MIN_SALT_LENGTH > context->saltlen) {
+        return ARGON2_SALT_TOO_SHORT;
+    }
+
+    if (ARGON2_MAX_SALT_LENGTH < context->saltlen) {
+        return ARGON2_SALT_TOO_LONG;
+    }
+
+    /* Validate secret (optional param) */
+    if (NULL == context->secret) {
+        if (0 != context->secretlen) {
+            return ARGON2_SECRET_PTR_MISMATCH;
+        }
+    } else {
+        if (ARGON2_MAX_SECRET < context->secretlen) {
+            return ARGON2_SECRET_TOO_LONG;
+        }
+    }
+
+    /* Validate associated data (optional param) */
+    if (NULL == context->ad) {
+        if (0 != context->adlen) {
+            return ARGON2_AD_PTR_MISMATCH;
+        }
+    } else {
+        if (ARGON2_MAX_AD_LENGTH < context->adlen) {
+            return ARGON2_AD_TOO_LONG;
+        }
+    }
+
+    /* Validate memory cost */
+    if (ARGON2_MIN_MEMORY > context->m_cost) {
+        return ARGON2_MEMORY_TOO_LITTLE;
+    }
+
+    if (context->m_cost < 8 * context->lanes) {
+        return ARGON2_MEMORY_TOO_LITTLE;
+    }
+
+    /* Validate time cost */
+    if (ARGON2_MIN_TIME > context->t_cost) {
+        return ARGON2_TIME_TOO_SMALL;
+    }
+
+    if (ARGON2_MAX_TIME < context->t_cost) {
+        return ARGON2_TIME_TOO_LARGE;
+    }
+
+    /* Validate lanes */
+    if (ARGON2_MIN_LANES > context->lanes) {
+        return ARGON2_LANES_TOO_FEW;
+    }
+
+    if (ARGON2_MAX_LANES < context->lanes) {
+        return ARGON2_LANES_TOO_MANY;
+    }
+
+    /* Validate threads */
+    if (ARGON2_MIN_THREADS > context->threads) {
+        return ARGON2_THREADS_TOO_FEW;
+    }
+
+    if (ARGON2_MAX_THREADS < context->threads) {
+        return ARGON2_THREADS_TOO_MANY;
+    }
+
+    if (NULL != context->allocate_cbk && NULL == context->grub_free_cbk) {
+        return ARGON2_FREE_MEMORY_CBK_NULL;
+    }
+
+    if (NULL == context->allocate_cbk && NULL != context->grub_free_cbk) {
+        return ARGON2_ALLOCATE_MEMORY_CBK_NULL;
+    }
+
+    return ARGON2_OK;
+}
+
+void fill_first_blocks(grub_uint8_t *blockhash, const argon2_instance_t *instance) {
+    grub_uint32_t l;
+    /* Make the first and second block in each lane as G(H0||0||i) or
+       G(H0||1||i) */
+    grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
+    for (l = 0; l < instance->lanes; ++l) {
+
+        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0);
+        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l);
+        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
+                     ARGON2_PREHASH_SEED_LENGTH);
+        load_block(&instance->memory[l * instance->lane_length + 0],
+                   blockhash_bytes);
+
+        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1);
+        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
+                     ARGON2_PREHASH_SEED_LENGTH);
+        load_block(&instance->memory[l * instance->lane_length + 1],
+                   blockhash_bytes);
+    }
+    clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
+}
+
+void initial_hash(grub_uint8_t *blockhash, argon2_context *context,
+                  argon2_type type) {
+    blake2b_state BlakeHash;
+    grub_uint8_t value[sizeof(grub_uint32_t)];
+
+    if (NULL == context || NULL == blockhash) {
+        return;
+    }
+
+    blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH);
+
+    store32(&value, context->lanes);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->outlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->m_cost);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->t_cost);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->version);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, (grub_uint32_t)type);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->pwdlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    if (context->pwd != NULL) {
+        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->pwd,
+                       context->pwdlen);
+
+        if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) {
+            secure_wipe_memory(context->pwd, context->pwdlen);
+            context->pwdlen = 0;
+        }
+    }
+
+    store32(&value, context->saltlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    if (context->salt != NULL) {
+        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->salt,
+                       context->saltlen);
+    }
+
+    store32(&value, context->secretlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    if (context->secret != NULL) {
+        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->secret,
+                       context->secretlen);
+
+        if (context->flags & ARGON2_FLAG_CLEAR_SECRET) {
+            secure_wipe_memory(context->secret, context->secretlen);
+            context->secretlen = 0;
+        }
+    }
+
+    store32(&value, context->adlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    if (context->ad != NULL) {
+        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->ad,
+                       context->adlen);
+    }
+
+    blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH);
+}
+
+int initialize(argon2_instance_t *instance, argon2_context *context) {
+    grub_uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH];
+    int result = ARGON2_OK;
+
+    if (instance == NULL || context == NULL)
+        return ARGON2_INCORRECT_PARAMETER;
+    instance->context_ptr = context;
+
+    /* 1. Memory allocation */
+    result = allocate_memory(context, (grub_uint8_t **)&(instance->memory),
+                             instance->memory_blocks, sizeof(block));
+    if (result != ARGON2_OK) {
+        return result;
+    }
+
+    /* 2. Initial hashing */
+    /* H_0 + 8 extra bytes to produce the first blocks */
+    /* grub_uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */
+    /* Hashing all inputs */
+    initial_hash(blockhash, context, instance->type);
+    /* Zeroing 8 extra bytes */
+    clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH,
+                          ARGON2_PREHASH_SEED_LENGTH -
+                              ARGON2_PREHASH_DIGEST_LENGTH);
+
+#ifdef GENKAT
+    initial_kat(blockhash, context, instance->type);
+#endif
+
+    /* 3. Creating first blocks, we always have at least two blocks in a slice
+     */
+    fill_first_blocks(blockhash, instance);
+    /* Clearing the hash */
+    clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH);
+
+    return ARGON2_OK;
+}
diff --git a/grub-core/lib/argon2/core.h b/grub-core/lib/argon2/core.h
new file mode 100644
index 000000000..bbcd56998
--- /dev/null
+++ b/grub-core/lib/argon2/core.h
@@ -0,0 +1,228 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef ARGON2_CORE_H
+#define ARGON2_CORE_H
+
+#include "argon2.h"
+
+#define CONST_CAST(x) (x)(grub_addr_t)
+
+/**********************Argon2 internal constants*******************************/
+
+enum argon2_core_constants {
+    /* Memory block size in bytes */
+    ARGON2_BLOCK_SIZE = 1024,
+    ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
+    ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
+    ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
+    ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
+
+    /* Number of pseudo-random values generated by one call to Blake in Argon2i
+       to
+       generate reference block positions */
+    ARGON2_ADDRESSES_IN_BLOCK = 128,
+
+    /* Pre-hashing digest length and its extension*/
+    ARGON2_PREHASH_DIGEST_LENGTH = 64,
+    ARGON2_PREHASH_SEED_LENGTH = 72
+};
+
+/*************************Argon2 internal data types***********************/
+
+/*
+ * Structure for the (1KB) memory block implemented as 128 64-bit words.
+ * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no
+ * bounds checking).
+ */
+typedef struct block_ { grub_uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block;
+
+/*****************Functions that work with the block******************/
+
+/* Initialize each byte of the block with @in */
+void init_block_value(block *b, grub_uint8_t in);
+
+/* Copy block @src to block @dst */
+void copy_block(block *dst, const block *src);
+
+/* XOR @src onto @dst bytewise */
+void xor_block(block *dst, const block *src);
+
+/*
+ * Argon2 instance: memory pointer, number of passes, amount of memory, type,
+ * and derived values.
+ * Used to evaluate the number and location of blocks to construct in each
+ * thread
+ */
+typedef struct Argon2_instance_t {
+    block *memory;          /* Memory pointer */
+    grub_uint32_t version;
+    grub_uint32_t passes;        /* Number of passes */
+    grub_uint32_t memory_blocks; /* Number of blocks in memory */
+    grub_uint32_t segment_length;
+    grub_uint32_t lane_length;
+    grub_uint32_t lanes;
+    grub_uint32_t threads;
+    argon2_type type;
+    int print_internals; /* whether to print the memory blocks */
+    argon2_context *context_ptr; /* points back to original context */
+} argon2_instance_t;
+
+/*
+ * Argon2 position: where we construct the block right now. Used to distribute
+ * work between threads.
+ */
+typedef struct Argon2_position_t {
+    grub_uint32_t pass;
+    grub_uint32_t lane;
+    grub_uint8_t slice;
+    grub_uint32_t index;
+} argon2_position_t;
+
+/*Struct that holds the inputs for thread handling FillSegment*/
+typedef struct Argon2_thread_data {
+    argon2_instance_t *instance_ptr;
+    argon2_position_t pos;
+} argon2_thread_data;
+
+/*************************Argon2 core functions********************************/
+
+/* Allocates memory to the given pointer, uses the appropriate allocator as
+ * specified in the context. Total allocated memory is num*size.
+ * @param context argon2_context which specifies the allocator
+ * @param memory pointer to the pointer to the memory
+ * @param size the size in bytes for each element to be allocated
+ * @param num the number of elements to be allocated
+ * @return ARGON2_OK if @memory is a valid pointer and memory is allocated
+ */
+int allocate_memory(const argon2_context *context, grub_uint8_t **memory,
+                    grub_size_t num, grub_size_t size);
+
+/*
+ * Frees memory at the given pointer, uses the appropriate deallocator as
+ * specified in the context. Also cleans the memory using clear_internal_memory.
+ * @param context argon2_context which specifies the deallocator
+ * @param memory pointer to buffer to be grub_freed
+ * @param size the size in bytes for each element to be deallocated
+ * @param num the number of elements to be deallocated
+ */
+void grub_free_memory(const argon2_context *context, grub_uint8_t *memory,
+                 grub_size_t num, grub_size_t size);
+
+/* Function that securely cleans the memory. This ignores any flags set
+ * regarding clearing memory. Usually one just calls clear_internal_memory.
+ * @param mem Pointer to the memory
+ * @param s Memory size in bytes
+ */
+void secure_wipe_memory(void *v, grub_size_t n);
+
+/* Function that securely clears the memory if FLAG_clear_internal_memory is
+ * set. If the flag isn't set, this function does nothing.
+ * @param mem Pointer to the memory
+ * @param s Memory size in bytes
+ */
+void clear_internal_memory(void *v, grub_size_t n);
+
+/*
+ * Computes absolute position of reference block in the lane following a skewed
+ * distribution and using a pseudo-random value as input
+ * @param instance Pointer to the current instance
+ * @param position Pointer to the current position
+ * @param pseudo_rand 32-bit pseudo-random value used to determine the position
+ * @param same_lane Indicates if the block will be taken from the current lane.
+ * If so we can reference the current segment
+ * @pre All pointers must be valid
+ */
+grub_uint32_t index_alpha(const argon2_instance_t *instance,
+                     const argon2_position_t *position, grub_uint32_t pseudo_rand,
+                     int same_lane);
+
+/*
+ * Function that validates all inputs against predefined restrictions and return
+ * an error code
+ * @param context Pointer to current Argon2 context
+ * @return ARGON2_OK if everything is all right, otherwise one of error codes
+ * (all defined in <argon2.h>
+ */
+int validate_inputs(const argon2_context *context);
+
+/*
+ * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears
+ * password and secret if needed
+ * @param  context  Pointer to the Argon2 internal structure containing memory
+ * pointer, and parameters for time and space requirements.
+ * @param  blockhash Buffer for pre-hashing digest
+ * @param  type Argon2 type
+ * @pre    @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes
+ * allocated
+ */
+void initial_hash(grub_uint8_t *blockhash, argon2_context *context,
+                  argon2_type type);
+
+/*
+ * Function creates first 2 blocks per lane
+ * @param instance Pointer to the current instance
+ * @param blockhash Pointer to the pre-hashing digest
+ * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values
+ */
+void fill_first_blocks(grub_uint8_t *blockhash, const argon2_instance_t *instance);
+
+/*
+ * Function allocates memory, hashes the inputs with Blake,  and creates first
+ * two blocks. Returns the pointer to the main memory with 2 blocks per lane
+ * initialized
+ * @param  context  Pointer to the Argon2 internal structure containing memory
+ * pointer, and parameters for time and space requirements.
+ * @param  instance Current Argon2 instance
+ * @return Zero if successful, -1 if memory failed to allocate. @context->state
+ * will be modified if successful.
+ */
+int initialize(argon2_instance_t *instance, argon2_context *context);
+
+/*
+ * XORing the last block of each lane, hashing it, making the tag. Deallocates
+ * the memory.
+ * @param context Pointer to current Argon2 context (use only the out parameters
+ * from it)
+ * @param instance Pointer to current instance of Argon2
+ * @pre instance->state must point to necessary amount of memory
+ * @pre context->out must point to outlen bytes of memory
+ * @pre if context->grub_free_cbk is not NULL, it should point to a function that
+ * deallocates memory
+ */
+void finalize(const argon2_context *context, argon2_instance_t *instance);
+
+/*
+ * Function that fills the segment using previous segments also from other
+ * threads
+ * @param context current context
+ * @param instance Pointer to the current instance
+ * @param position Current position
+ * @pre all block pointers must be valid
+ */
+void fill_segment(const argon2_instance_t *instance,
+                  argon2_position_t position);
+
+/*
+ * Function that fills the entire memory t_cost times based on the first two
+ * blocks in each lane
+ * @param instance Pointer to the current instance
+ * @return ARGON2_OK if successful, @context->state
+ */
+int fill_memory_blocks(argon2_instance_t *instance);
+
+#endif
diff --git a/grub-core/lib/argon2/ref.c b/grub-core/lib/argon2/ref.c
new file mode 100644
index 000000000..d1f4134b3
--- /dev/null
+++ b/grub-core/lib/argon2/ref.c
@@ -0,0 +1,190 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#include "argon2.h"
+#include "core.h"
+
+#include "blake2/blamka-round-ref.h"
+#include "blake2/blake2-impl.h"
+#include "blake2/blake2.h"
+
+
+/*
+ * Function fills a new memory block and optionally XORs the old block over the new one.
+ * @next_block must be initialized.
+ * @param prev_block Pointer to the previous block
+ * @param ref_block Pointer to the reference block
+ * @param next_block Pointer to the block to be constructed
+ * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
+ * @pre all block pointers must be valid
+ */
+static void fill_block(const block *prev_block, const block *ref_block,
+                       block *next_block, int with_xor) {
+    block blockR, block_tmp;
+    unsigned i;
+
+    copy_block(&blockR, ref_block);
+    xor_block(&blockR, prev_block);
+    copy_block(&block_tmp, &blockR);
+    /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */
+    if (with_xor) {
+        /* Saving the next block contents for XOR over: */
+        xor_block(&block_tmp, next_block);
+        /* Now blockR = ref_block + prev_block and
+           block_tmp = ref_block + prev_block + next_block */
+    }
+
+    /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
+       (16,17,..31)... finally (112,113,...127) */
+    for (i = 0; i < 8; ++i) {
+        BLAKE2_ROUND_NOMSG(
+            blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],
+            blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],
+            blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],
+            blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],
+            blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],
+            blockR.v[16 * i + 15]);
+    }
+
+    /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then
+       (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */
+    for (i = 0; i < 8; i++) {
+        BLAKE2_ROUND_NOMSG(
+            blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],
+            blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],
+            blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],
+            blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],
+            blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],
+            blockR.v[2 * i + 113]);
+    }
+
+    copy_block(next_block, &block_tmp);
+    xor_block(next_block, &blockR);
+}
+
+static void next_addresses(block *address_block, block *input_block,
+                           const block *zero_block) {
+    input_block->v[6]++;
+    fill_block(zero_block, input_block, address_block, 0);
+    fill_block(zero_block, address_block, address_block, 0);
+}
+
+void fill_segment(const argon2_instance_t *instance,
+                  argon2_position_t position) {
+    block *ref_block = NULL, *curr_block = NULL;
+    block address_block, input_block, zero_block;
+    grub_uint64_t pseudo_rand, ref_index, ref_lane;
+    grub_uint32_t prev_offset, curr_offset;
+    grub_uint32_t starting_index;
+    grub_uint32_t i;
+    int data_independent_addressing;
+
+    if (instance == NULL) {
+        return;
+    }
+
+    data_independent_addressing =
+        (instance->type == Argon2_i) ||
+        (instance->type == Argon2_id && (position.pass == 0) &&
+         (position.slice < ARGON2_SYNC_POINTS / 2));
+
+    if (data_independent_addressing) {
+        init_block_value(&zero_block, 0);
+        init_block_value(&input_block, 0);
+
+        input_block.v[0] = position.pass;
+        input_block.v[1] = position.lane;
+        input_block.v[2] = position.slice;
+        input_block.v[3] = instance->memory_blocks;
+        input_block.v[4] = instance->passes;
+        input_block.v[5] = instance->type;
+    }
+
+    starting_index = 0;
+
+    if ((0 == position.pass) && (0 == position.slice)) {
+        starting_index = 2; /* we have already generated the first two blocks */
+
+        /* Don't forget to generate the first block of addresses: */
+        if (data_independent_addressing) {
+            next_addresses(&address_block, &input_block, &zero_block);
+        }
+    }
+
+    /* Offset of the current block */
+    curr_offset = position.lane * instance->lane_length +
+                  position.slice * instance->segment_length + starting_index;
+
+    if (0 == curr_offset % instance->lane_length) {
+        /* Last block in this lane */
+        prev_offset = curr_offset + instance->lane_length - 1;
+    } else {
+        /* Previous block */
+        prev_offset = curr_offset - 1;
+    }
+
+    for (i = starting_index; i < instance->segment_length;
+         ++i, ++curr_offset, ++prev_offset) {
+        /*1.1 Rotating prev_offset if needed */
+        if (curr_offset % instance->lane_length == 1) {
+            prev_offset = curr_offset - 1;
+        }
+
+        /* 1.2 Computing the index of the reference block */
+        /* 1.2.1 Taking pseudo-random value from the previous block */
+        if (data_independent_addressing) {
+            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
+                next_addresses(&address_block, &input_block, &zero_block);
+            }
+            pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
+        } else {
+            pseudo_rand = instance->memory[prev_offset].v[0];
+        }
+
+        /* 1.2.2 Computing the lane of the reference block */
+        ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
+
+        if ((position.pass == 0) && (position.slice == 0)) {
+            /* Can not reference other lanes yet */
+            ref_lane = position.lane;
+        }
+
+        /* 1.2.3 Computing the number of possible reference block within the
+         * lane.
+         */
+        position.index = i;
+        ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
+                                ref_lane == position.lane);
+
+        /* 2 Creating a new block */
+        ref_block =
+            instance->memory + instance->lane_length * ref_lane + ref_index;
+        curr_block = instance->memory + curr_offset;
+        if (ARGON2_VERSION_10 == instance->version) {
+            /* version 1.2.1 and earlier: overwrite, not XOR */
+            fill_block(instance->memory + prev_offset, ref_block, curr_block, 0);
+        } else {
+            if(0 == position.pass) {
+                fill_block(instance->memory + prev_offset, ref_block,
+                           curr_block, 0);
+            } else {
+                fill_block(instance->memory + prev_offset, ref_block,
+                           curr_block, 1);
+            }
+        }
+    }
+}
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 4/5] luks2: Discern Argon2i and Argon2id
  2020-03-10 18:58 [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
                   ` (2 preceding siblings ...)
  2020-03-10 18:58 ` [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
@ 2020-03-10 18:58 ` Patrick Steinhardt
  2020-03-10 18:58 ` [PATCH v3 5/5] luks2: Support key derival via Argon2 Patrick Steinhardt
  2020-03-25 17:12 ` [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Daniel Kiper
  5 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-10 18:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, Leif Lindholm, agraf, pjones,
	mjg59, phcoder, Milan Broz, Daniel Kiper

While GRUB is already able to parse both Argon2i and Argon2id parameters
from the LUKS2 header, it doesn't discern both types. This commit
introduces a new KDF type for Argon2id and sets up the parsed KDF's type
accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 grub-core/disk/luks2.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 65c4f0aac..767631198 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -40,6 +40,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
 enum grub_luks2_kdf_type
 {
   LUKS2_KDF_TYPE_ARGON2I,
+  LUKS2_KDF_TYPE_ARGON2ID,
   LUKS2_KDF_TYPE_PBKDF2
 };
 typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t;
@@ -90,7 +91,7 @@ struct grub_luks2_keyslot
 	grub_int64_t time;
 	grub_int64_t memory;
 	grub_int64_t cpus;
-      } argon2i;
+      } argon2;
       struct
       {
 	const char   *hash;
@@ -158,10 +159,11 @@ luks2_parse_keyslot (grub_luks2_keyslot_t *out, const grub_json_t *keyslot)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing or invalid KDF");
   else if (!grub_strcmp (type, "argon2i") || !grub_strcmp (type, "argon2id"))
     {
-      out->kdf.type = LUKS2_KDF_TYPE_ARGON2I;
-      if (grub_json_getint64 (&out->kdf.u.argon2i.time, &kdf, "time") ||
-	  grub_json_getint64 (&out->kdf.u.argon2i.memory, &kdf, "memory") ||
-	  grub_json_getint64 (&out->kdf.u.argon2i.cpus, &kdf, "cpus"))
+      out->kdf.type = !grub_strcmp (type, "argon2i")
+		      ? LUKS2_KDF_TYPE_ARGON2I : LUKS2_KDF_TYPE_ARGON2ID;
+      if (grub_json_getint64 (&out->kdf.u.argon2.time, &kdf, "time") ||
+	  grub_json_getint64 (&out->kdf.u.argon2.memory, &kdf, "memory") ||
+	  grub_json_getint64 (&out->kdf.u.argon2.cpus, &kdf, "cpus"))
 	return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing Argon2i parameters");
     }
   else if (!grub_strcmp (type, "pbkdf2"))
@@ -432,6 +434,7 @@ luks2_decrypt_key (grub_uint8_t *out_key,
   switch (k->kdf.type)
     {
       case LUKS2_KDF_TYPE_ARGON2I:
+      case LUKS2_KDF_TYPE_ARGON2ID:
 	ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported");
 	goto err;
       case LUKS2_KDF_TYPE_PBKDF2:
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v3 5/5] luks2: Support key derival via Argon2
  2020-03-10 18:58 [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
                   ` (3 preceding siblings ...)
  2020-03-10 18:58 ` [PATCH v3 4/5] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
@ 2020-03-10 18:58 ` Patrick Steinhardt
  2020-03-25 17:12 ` [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Daniel Kiper
  5 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-10 18:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, Leif Lindholm, agraf, pjones,
	mjg59, phcoder, Milan Broz, Daniel Kiper

One addition with LUKS2 was support of the key derival function Argon2
in addition to the previously supported PBKDF2 algortihm. In order to
ease getting in initial support for LUKS2, we only reused infrastructure
to support LUKS2 with PBKDF2, but left out Argon2.

This commit now introduces support for Argon2 to enable decryption of
LUKS2 partitions using this key derival function. As the code for Argon2
has been added in a previous commit in this series, adding support is
now trivial.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 Makefile.util.def           |  6 +++++-
 grub-core/Makefile.core.def |  2 +-
 grub-core/disk/luks2.c      | 13 +++++++++++--
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/Makefile.util.def b/Makefile.util.def
index 1e0799a68..f07cf9deb 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -3,7 +3,7 @@ AutoGen definitions Makefile.tpl;
 library = {
   name = libgrubkern.a;
   cflags = '$(CFLAGS_GNULIB)';
-  cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/grub-core/lib/json';
+  cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/grub-core/lib/json -I$(srcdir)/grub-core/lib/argon2';
 
   common = util/misc.c;
   common = grub-core/kern/command.c;
@@ -36,6 +36,10 @@ library = {
   common = grub-core/kern/misc.c;
   common = grub-core/kern/partition.c;
   common = grub-core/lib/crypto.c;
+  common = grub-core/lib/argon2/argon2.c;
+  common = grub-core/lib/argon2/core.c;
+  common = grub-core/lib/argon2/ref.c;
+  common = grub-core/lib/argon2/blake2/blake2b.c;
   common = grub-core/lib/json/json.c;
   common = grub-core/disk/luks.c;
   common = grub-core/disk/luks2.c;
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 30147a899..9e4c89791 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1204,7 +1204,7 @@ module = {
   common = disk/luks2.c;
   common = lib/gnulib/base64.c;
   cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
-  cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json';
+  cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json -I$(srcdir)/lib/argon2';
 };
 
 module = {
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 767631198..3c79f14aa 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -27,6 +27,7 @@
 #include <grub/partition.h>
 #include <grub/i18n.h>
 
+#include <argon2.h>
 #include <base64.h>
 #include <json.h>
 
@@ -435,8 +436,16 @@ luks2_decrypt_key (grub_uint8_t *out_key,
     {
       case LUKS2_KDF_TYPE_ARGON2I:
       case LUKS2_KDF_TYPE_ARGON2ID:
-	ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported");
-	goto err;
+	ret = argon2_hash (k->kdf.u.argon2.time, k->kdf.u.argon2.memory, k->kdf.u.argon2.cpus,
+			   passphrase, passphraselen, salt, saltlen, area_key, k->area.key_size,
+			   k->kdf.type == LUKS2_KDF_TYPE_ARGON2I ? Argon2_i : Argon2_id,
+			   ARGON2_VERSION_NUMBER);
+        if (ret)
+	  {
+	    grub_dprintf ("luks2", "Argon2 failed: %s\n", argon2_error_message (ret));
+	    goto err;
+	  }
+        break;
       case LUKS2_KDF_TYPE_PBKDF2:
 	hash = grub_crypto_lookup_md_by_name (k->kdf.u.pbkdf2.hash);
 	if (!hash)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-10 18:58 ` [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
@ 2020-03-10 20:44   ` Eli Schwartz
  2020-03-10 21:42     ` Patrick Steinhardt
  2020-03-13 13:13   ` Daniel Kiper
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 41+ messages in thread
From: Eli Schwartz @ 2020-03-10 20:44 UTC (permalink / raw)
  To: grub-devel


[-- Attachment #1.1: Type: text/plain, Size: 88584 bytes --]

On 3/10/20 2:58 PM, Patrick Steinhardt wrote:
> In order to support the Argon2 key derival function for LUKS2, we
> obviously need to implement Argon2. It doesn't make a lot of sense to
> hand-code any crypto, which is why this commit instead imports Argon2
> from the cryptsetup project. This commit thus imports the code from the
> official reference implementation located at [1].

Which one is it? :p

Perhaps, "which is why this commit instead imports the Argon2
implementation used by the cryptsetup project, that is, the official
reference implementation located at [1]."

> The code is licensed
> under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
> 2.0 are compatible with GPLv3, it should be fine to import that code.
> 
> The code is imported from commit 62358ba (Merge pull request #270 from
> bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
> several adjustments were required that have beed documented in
> "grub-dev.texi".

typo:

"beed" -> "been"

> [1]: https://github.com/P-H-C/phc-winner-argon2
> 
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  docs/grub-dev.texi                            |  64 +++
>  grub-core/Makefile.core.def                   |   8 +
>  grub-core/lib/argon2/argon2.c                 | 232 ++++++++
>  grub-core/lib/argon2/argon2.h                 | 264 +++++++++
>  grub-core/lib/argon2/blake2/blake2-impl.h     | 151 +++++
>  grub-core/lib/argon2/blake2/blake2.h          |  89 +++
>  grub-core/lib/argon2/blake2/blake2b.c         | 388 +++++++++++++
>  .../lib/argon2/blake2/blamka-round-ref.h      |  56 ++
>  grub-core/lib/argon2/core.c                   | 525 ++++++++++++++++++
>  grub-core/lib/argon2/core.h                   | 228 ++++++++
>  grub-core/lib/argon2/ref.c                    | 190 +++++++
>  11 files changed, 2195 insertions(+)
>  create mode 100644 grub-core/lib/argon2/argon2.c
>  create mode 100644 grub-core/lib/argon2/argon2.h
>  create mode 100644 grub-core/lib/argon2/blake2/blake2-impl.h
>  create mode 100644 grub-core/lib/argon2/blake2/blake2.h
>  create mode 100644 grub-core/lib/argon2/blake2/blake2b.c
>  create mode 100644 grub-core/lib/argon2/blake2/blamka-round-ref.h
>  create mode 100644 grub-core/lib/argon2/core.c
>  create mode 100644 grub-core/lib/argon2/core.h
>  create mode 100644 grub-core/lib/argon2/ref.c
> 
> diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
> index 837873094..4af07f11a 100644
> --- a/docs/grub-dev.texi
> +++ b/docs/grub-dev.texi
> @@ -489,11 +489,75 @@ GRUB includes some code from other projects, and it is sometimes necessary
>  to update it.
>  
>  @menu
> +* Argon2::
>  * Gnulib::
>  * jsmn::
>  * minilzo::
>  @end menu
>  
> +@node Argon2
> +@section Argon2
> +
> +Argon2 is a key derivation function used by LUKS2 in order to derive encryption
> +keys from a user-provided password. GRUB imports the official reference
> +implementation of Argon2 from @url{https://github.com/P-H-C/phc-winner-argon2}.
> +In order to make the library usable for GRUB, we need to perform various
> +conversions. This is mainly due to the fact that the imported code makes use of
> +types and functions defined in the C standard library, which isn't available.
> +Furthermore, using the POSIX wrapper library is not possible as the code needs
> +to be part of the kernel.
> +
> +Updating the code can thus be performed like following:
> +
> +@example
> +$ git clone https://github.com/P-H-C/phc-winner-argon2 argon2
> +$ cp argon2/include/argon2.h argon2/src/@{argon2.c,core.c,core.h,ref.c@} \
> +    grub-core/lib/argon2/
> +$ cp argon2/src/blake2/@{blake2-impl.h,blake2.h,blake2b.c,blamka-round-ref.h@} \
> +    grub-core/lib/argon2/blake2/
> +$ sed -e 's/UINT32_C/GRUB_UINT32_C/g' \
> +      -e 's/UINT64_C/GRUB_UINT64_C/g' \
> +      -e 's/UINT32_MAX/GRUB_UINT32_MAX/g' \
> +      -e 's/CHAR_BIT/GRUB_CHAR_BIT/g' \
> +      -e 's/UINT_MAX/GRUB_UINT_MAX/g' \
> +      -e 's/uintptr_t/grub_addr_t/g' \
> +      -e 's/size_t/grub_size_t/g' \
> +      -e 's/uint32_t/grub_uint32_t/g' \
> +      -e 's/uint64_t/grub_uint64_t/g' \
> +      -e 's/uint8_t/grub_uint8_t/g' \
> +      -e 's/memset/grub_memset/g' \
> +      -e 's/memcpy/grub_memcpy/g' \
> +      -e 's/malloc/grub_malloc/g' \
> +      -e 's/free/grub_free/g' \
> +      -e 's/#elif _MSC_VER/#elif defined(_MSC_VER)/' \
> +      grub-core/lib/argon2/@{*,blake2/*@}.@{c,h@} -i
> +@end example
> +
> +Afterwards, you need to perform the following manual steps:
> +
> +@enumerate
> +@item Remove all includes of standard library headers, "encoding.h" and
> +      "thread.h".
> +@item Add includes <grub/mm.h> and <grub/misc.h> to "argon2.h".
> +@item Add include <grub/dl.h> and module license declaration to "argon2.c".
> +@item Remove the following declarations and functions from "argon2.h" and
> +     "argon2.c": argon2_type2string, argon2i_hash_encoded, argon2i_hash_raw,
> +     argon2d_hash_encoded, argon2d_hash_raw, argon2id_hash_encoded,
> +     argon2id_hash_raw, argon2_compare, argon2_verify, argon2i_verify,
> +     argon2d_verify, argon2id_verify, argon2d_ctx, argon2i_ctx, argon2id_ctx,
> +     argon2_verify_ctx, argon2d_verify_ctx, argon2i_verify_ctx,
> +     argon2id_verify_ctx, argon2_encodedlen.
> +@item Move the declaration of `clear_internal_memory()` in "blake2-impl.h" to
> +      "blake2b.c".
> +@item Remove code guarded by the ARGON2_NO_THREADS macro.
> +@item Remove parameters `encoded` and `encodedlen` from `argon2_hash` and remove
> +      the encoding block in that function.
> +@item Remove parameter verifications in `validate_inputs()` for
> +      ARGON2_MIN_PWD_LENGTH, ARGON2_MIN_SECRET, ARGON2_MIN_AD_LENGTH and
> +      ARGON2_MAX_MEMORY to fix compiler warnings.
> +@item Mark the function argon2_ctx as static.
> +@end enumerate
> +
>  @node Gnulib
>  @section Gnulib
>  
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index 91297e4eb..30147a899 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -1181,6 +1181,14 @@ module = {
>    common = lib/json/json.c;
>  };
>  
> +module = {
> +  name = argon2;
> +  common = lib/argon2/argon2.c;
> +  common = lib/argon2/core.c;
> +  common = lib/argon2/ref.c;
> +  common = lib/argon2/blake2/blake2b.c;
> +};
> +
>  module = {
>    name = afsplitter;
>    common = disk/AFSplitter.c;
> diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
> new file mode 100644
> index 000000000..c77f7f6ff
> --- /dev/null
> +++ b/grub-core/lib/argon2/argon2.c
> @@ -0,0 +1,232 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +#include <grub/dl.h>
> +
> +#include "argon2.h"
> +#include "core.h"
> +
> +GRUB_MOD_LICENSE ("GPLv3");
> +
> +static int argon2_ctx(argon2_context *context, argon2_type type) {
> +    /* 1. Validate all inputs */
> +    int result = validate_inputs(context);
> +    grub_uint32_t memory_blocks, segment_length;
> +    argon2_instance_t instance;
> +
> +    if (ARGON2_OK != result) {
> +        return result;
> +    }
> +
> +    if (Argon2_d != type && Argon2_i != type && Argon2_id != type) {
> +        return ARGON2_INCORRECT_TYPE;
> +    }
> +
> +    /* 2. Align memory size */
> +    /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
> +    memory_blocks = context->m_cost;
> +
> +    if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) {
> +        memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes;
> +    }
> +
> +    segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS);
> +    /* Ensure that all segments have equal length */
> +    memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS);
> +
> +    instance.version = context->version;
> +    instance.memory = NULL;
> +    instance.passes = context->t_cost;
> +    instance.memory_blocks = memory_blocks;
> +    instance.segment_length = segment_length;
> +    instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
> +    instance.lanes = context->lanes;
> +    instance.threads = context->threads;
> +    instance.type = type;
> +
> +    if (instance.threads > instance.lanes) {
> +        instance.threads = instance.lanes;
> +    }
> +
> +    /* 3. Initialization: Hashing inputs, allocating memory, filling first
> +     * blocks
> +     */
> +    result = initialize(&instance, context);
> +
> +    if (ARGON2_OK != result) {
> +        return result;
> +    }
> +
> +    /* 4. Filling memory */
> +    result = fill_memory_blocks(&instance);
> +
> +    if (ARGON2_OK != result) {
> +        return result;
> +    }
> +    /* 5. Finalization */
> +    finalize(context, &instance);
> +
> +    return ARGON2_OK;
> +}
> +
> +int argon2_hash(const grub_uint32_t t_cost, const grub_uint32_t m_cost,
> +                const grub_uint32_t parallelism, const void *pwd,
> +                const grub_size_t pwdlen, const void *salt, const grub_size_t saltlen,
> +                void *hash, const grub_size_t hashlen, argon2_type type,
> +                const grub_uint32_t version){
> +
> +    argon2_context context;
> +    int result;
> +    grub_uint8_t *out;
> +
> +    if (pwdlen > ARGON2_MAX_PWD_LENGTH) {
> +        return ARGON2_PWD_TOO_LONG;
> +    }
> +
> +    if (saltlen > ARGON2_MAX_SALT_LENGTH) {
> +        return ARGON2_SALT_TOO_LONG;
> +    }
> +
> +    if (hashlen > ARGON2_MAX_OUTLEN) {
> +        return ARGON2_OUTPUT_TOO_LONG;
> +    }
> +
> +    if (hashlen < ARGON2_MIN_OUTLEN) {
> +        return ARGON2_OUTPUT_TOO_SHORT;
> +    }
> +
> +    out = grub_malloc(hashlen);
> +    if (!out) {
> +        return ARGON2_MEMORY_ALLOCATION_ERROR;
> +    }
> +
> +    context.out = (grub_uint8_t *)out;
> +    context.outlen = (grub_uint32_t)hashlen;
> +    context.pwd = CONST_CAST(grub_uint8_t *)pwd;
> +    context.pwdlen = (grub_uint32_t)pwdlen;
> +    context.salt = CONST_CAST(grub_uint8_t *)salt;
> +    context.saltlen = (grub_uint32_t)saltlen;
> +    context.secret = NULL;
> +    context.secretlen = 0;
> +    context.ad = NULL;
> +    context.adlen = 0;
> +    context.t_cost = t_cost;
> +    context.m_cost = m_cost;
> +    context.lanes = parallelism;
> +    context.threads = parallelism;
> +    context.allocate_cbk = NULL;
> +    context.grub_free_cbk = NULL;
> +    context.flags = ARGON2_DEFAULT_FLAGS;
> +    context.version = version;
> +
> +    result = argon2_ctx(&context, type);
> +
> +    if (result != ARGON2_OK) {
> +        clear_internal_memory(out, hashlen);
> +        grub_free(out);
> +        return result;
> +    }
> +
> +    /* if raw hash requested, write it */
> +    if (hash) {
> +        grub_memcpy(hash, out, hashlen);
> +    }
> +
> +    clear_internal_memory(out, hashlen);
> +    grub_free(out);
> +
> +    return ARGON2_OK;
> +}
> +
> +const char *argon2_error_message(int error_code) {
> +    switch (error_code) {
> +    case ARGON2_OK:
> +        return "OK";
> +    case ARGON2_OUTPUT_PTR_NULL:
> +        return "Output pointer is NULL";
> +    case ARGON2_OUTPUT_TOO_SHORT:
> +        return "Output is too short";
> +    case ARGON2_OUTPUT_TOO_LONG:
> +        return "Output is too long";
> +    case ARGON2_PWD_TOO_SHORT:
> +        return "Password is too short";
> +    case ARGON2_PWD_TOO_LONG:
> +        return "Password is too long";
> +    case ARGON2_SALT_TOO_SHORT:
> +        return "Salt is too short";
> +    case ARGON2_SALT_TOO_LONG:
> +        return "Salt is too long";
> +    case ARGON2_AD_TOO_SHORT:
> +        return "Associated data is too short";
> +    case ARGON2_AD_TOO_LONG:
> +        return "Associated data is too long";
> +    case ARGON2_SECRET_TOO_SHORT:
> +        return "Secret is too short";
> +    case ARGON2_SECRET_TOO_LONG:
> +        return "Secret is too long";
> +    case ARGON2_TIME_TOO_SMALL:
> +        return "Time cost is too small";
> +    case ARGON2_TIME_TOO_LARGE:
> +        return "Time cost is too large";
> +    case ARGON2_MEMORY_TOO_LITTLE:
> +        return "Memory cost is too small";
> +    case ARGON2_MEMORY_TOO_MUCH:
> +        return "Memory cost is too large";
> +    case ARGON2_LANES_TOO_FEW:
> +        return "Too few lanes";
> +    case ARGON2_LANES_TOO_MANY:
> +        return "Too many lanes";
> +    case ARGON2_PWD_PTR_MISMATCH:
> +        return "Password pointer is NULL, but password length is not 0";
> +    case ARGON2_SALT_PTR_MISMATCH:
> +        return "Salt pointer is NULL, but salt length is not 0";
> +    case ARGON2_SECRET_PTR_MISMATCH:
> +        return "Secret pointer is NULL, but secret length is not 0";
> +    case ARGON2_AD_PTR_MISMATCH:
> +        return "Associated data pointer is NULL, but ad length is not 0";
> +    case ARGON2_MEMORY_ALLOCATION_ERROR:
> +        return "Memory allocation error";
> +    case ARGON2_FREE_MEMORY_CBK_NULL:
> +        return "The grub_free memory callback is NULL";
> +    case ARGON2_ALLOCATE_MEMORY_CBK_NULL:
> +        return "The allocate memory callback is NULL";
> +    case ARGON2_INCORRECT_PARAMETER:
> +        return "Argon2_Context context is NULL";
> +    case ARGON2_INCORRECT_TYPE:
> +        return "There is no such version of Argon2";
> +    case ARGON2_OUT_PTR_MISMATCH:
> +        return "Output pointer mismatch";
> +    case ARGON2_THREADS_TOO_FEW:
> +        return "Not enough threads";
> +    case ARGON2_THREADS_TOO_MANY:
> +        return "Too many threads";
> +    case ARGON2_MISSING_ARGS:
> +        return "Missing arguments";
> +    case ARGON2_ENCODING_FAIL:
> +        return "Encoding failed";
> +    case ARGON2_DECODING_FAIL:
> +        return "Decoding failed";
> +    case ARGON2_THREAD_FAIL:
> +        return "Threading failure";
> +    case ARGON2_DECODING_LENGTH_FAIL:
> +        return "Some of encoded parameters are too long or too short";
> +    case ARGON2_VERIFY_MISMATCH:
> +        return "The password does not match the supplied hash";
> +    default:
> +        return "Unknown error code";
> +    }
> +}
> diff --git a/grub-core/lib/argon2/argon2.h b/grub-core/lib/argon2/argon2.h
> new file mode 100644
> index 000000000..129f7efbd
> --- /dev/null
> +++ b/grub-core/lib/argon2/argon2.h
> @@ -0,0 +1,264 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +#ifndef ARGON2_H
> +#define ARGON2_H
> +
> +#include <grub/misc.h>
> +#include <grub/mm.h>
> +
> +#if defined(__cplusplus)
> +extern "C" {
> +#endif
> +
> +/* Symbols visibility control */
> +#ifdef A2_VISCTL
> +#define ARGON2_PUBLIC __attribute__((visibility("default")))
> +#define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
> +#elif defined(_MSC_VER)
> +#define ARGON2_PUBLIC __declspec(dllexport)
> +#define ARGON2_LOCAL
> +#else
> +#define ARGON2_PUBLIC
> +#define ARGON2_LOCAL
> +#endif
> +
> +/*
> + * Argon2 input parameter restrictions
> + */
> +
> +/* Minimum and maximum number of lanes (degree of parallelism) */
> +#define ARGON2_MIN_LANES GRUB_UINT32_C(1)
> +#define ARGON2_MAX_LANES GRUB_UINT32_C(0xFFFFFF)
> +
> +/* Minimum and maximum number of threads */
> +#define ARGON2_MIN_THREADS GRUB_UINT32_C(1)
> +#define ARGON2_MAX_THREADS GRUB_UINT32_C(0xFFFFFF)
> +
> +/* Number of synchronization points between lanes per pass */
> +#define ARGON2_SYNC_POINTS GRUB_UINT32_C(4)
> +
> +/* Minimum and maximum digest size in bytes */
> +#define ARGON2_MIN_OUTLEN GRUB_UINT32_C(4)
> +#define ARGON2_MAX_OUTLEN GRUB_UINT32_C(0xFFFFFFFF)
> +
> +/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */
> +#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */
> +
> +#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b))
> +/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */
> +#define ARGON2_MAX_MEMORY_BITS                                                 \
> +    ARGON2_MIN(GRUB_UINT32_C(32), (sizeof(void *) * GRUB_CHAR_BIT - 10 - 1))
> +#define ARGON2_MAX_MEMORY                                                      \
> +    ARGON2_MIN(GRUB_UINT32_C(0xFFFFFFFF), GRUB_UINT64_C(1) << ARGON2_MAX_MEMORY_BITS)
> +
> +/* Minimum and maximum number of passes */
> +#define ARGON2_MIN_TIME GRUB_UINT32_C(1)
> +#define ARGON2_MAX_TIME GRUB_UINT32_C(0xFFFFFFFF)
> +
> +/* Minimum and maximum password length in bytes */
> +#define ARGON2_MIN_PWD_LENGTH GRUB_UINT32_C(0)
> +#define ARGON2_MAX_PWD_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
> +
> +/* Minimum and maximum associated data length in bytes */
> +#define ARGON2_MIN_AD_LENGTH GRUB_UINT32_C(0)
> +#define ARGON2_MAX_AD_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
> +
> +/* Minimum and maximum salt length in bytes */
> +#define ARGON2_MIN_SALT_LENGTH GRUB_UINT32_C(8)
> +#define ARGON2_MAX_SALT_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
> +
> +/* Minimum and maximum key length in bytes */
> +#define ARGON2_MIN_SECRET GRUB_UINT32_C(0)
> +#define ARGON2_MAX_SECRET GRUB_UINT32_C(0xFFFFFFFF)
> +
> +/* Flags to determine which fields are securely wiped (default = no wipe). */
> +#define ARGON2_DEFAULT_FLAGS GRUB_UINT32_C(0)
> +#define ARGON2_FLAG_CLEAR_PASSWORD (GRUB_UINT32_C(1) << 0)
> +#define ARGON2_FLAG_CLEAR_SECRET (GRUB_UINT32_C(1) << 1)
> +
> +/* Global flag to determine if we are wiping internal memory buffers. This flag
> + * is defined in core.c and defaults to 1 (wipe internal memory). */
> +extern int FLAG_clear_internal_memory;
> +
> +/* Error codes */
> +typedef enum Argon2_ErrorCodes {
> +    ARGON2_OK = 0,
> +
> +    ARGON2_OUTPUT_PTR_NULL = -1,
> +
> +    ARGON2_OUTPUT_TOO_SHORT = -2,
> +    ARGON2_OUTPUT_TOO_LONG = -3,
> +
> +    ARGON2_PWD_TOO_SHORT = -4,
> +    ARGON2_PWD_TOO_LONG = -5,
> +
> +    ARGON2_SALT_TOO_SHORT = -6,
> +    ARGON2_SALT_TOO_LONG = -7,
> +
> +    ARGON2_AD_TOO_SHORT = -8,
> +    ARGON2_AD_TOO_LONG = -9,
> +
> +    ARGON2_SECRET_TOO_SHORT = -10,
> +    ARGON2_SECRET_TOO_LONG = -11,
> +
> +    ARGON2_TIME_TOO_SMALL = -12,
> +    ARGON2_TIME_TOO_LARGE = -13,
> +
> +    ARGON2_MEMORY_TOO_LITTLE = -14,
> +    ARGON2_MEMORY_TOO_MUCH = -15,
> +
> +    ARGON2_LANES_TOO_FEW = -16,
> +    ARGON2_LANES_TOO_MANY = -17,
> +
> +    ARGON2_PWD_PTR_MISMATCH = -18,    /* NULL ptr with non-zero length */
> +    ARGON2_SALT_PTR_MISMATCH = -19,   /* NULL ptr with non-zero length */
> +    ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */
> +    ARGON2_AD_PTR_MISMATCH = -21,     /* NULL ptr with non-zero length */
> +
> +    ARGON2_MEMORY_ALLOCATION_ERROR = -22,
> +
> +    ARGON2_FREE_MEMORY_CBK_NULL = -23,
> +    ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24,
> +
> +    ARGON2_INCORRECT_PARAMETER = -25,
> +    ARGON2_INCORRECT_TYPE = -26,
> +
> +    ARGON2_OUT_PTR_MISMATCH = -27,
> +
> +    ARGON2_THREADS_TOO_FEW = -28,
> +    ARGON2_THREADS_TOO_MANY = -29,
> +
> +    ARGON2_MISSING_ARGS = -30,
> +
> +    ARGON2_ENCODING_FAIL = -31,
> +
> +    ARGON2_DECODING_FAIL = -32,
> +
> +    ARGON2_THREAD_FAIL = -33,
> +
> +    ARGON2_DECODING_LENGTH_FAIL = -34,
> +
> +    ARGON2_VERIFY_MISMATCH = -35
> +} argon2_error_codes;
> +
> +/* Memory allocator types --- for external allocation */
> +typedef int (*allocate_fptr)(grub_uint8_t **memory, grub_size_t bytes_to_allocate);
> +typedef void (*deallocate_fptr)(grub_uint8_t *memory, grub_size_t bytes_to_allocate);
> +
> +/* Argon2 external data structures */
> +
> +/*
> + *****
> + * Context: structure to hold Argon2 inputs:
> + *  output array and its length,
> + *  password and its length,
> + *  salt and its length,
> + *  secret and its length,
> + *  associated data and its length,
> + *  number of passes, amount of used memory (in KBytes, can be rounded up a bit)
> + *  number of parallel threads that will be run.
> + * All the parameters above affect the output hash value.
> + * Additionally, two function pointers can be provided to allocate and
> + * deallocate the memory (if NULL, memory will be allocated internally).
> + * Also, three flags indicate whether to erase password, secret as soon as they
> + * are pre-hashed (and thus not needed anymore), and the entire memory
> + *****
> + * Simplest situation: you have output array out[8], password is stored in
> + * pwd[32], salt is stored in salt[16], you do not have keys nor associated
> + * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with
> + * 4 parallel lanes.
> + * You want to erase the password, but you're OK with last pass not being
> + * erased. You want to use the default memory allocator.
> + * Then you initialize:
> + Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false)
> + */
> +typedef struct Argon2_Context {
> +    grub_uint8_t *out;    /* output array */
> +    grub_uint32_t outlen; /* digest length */
> +
> +    grub_uint8_t *pwd;    /* password array */
> +    grub_uint32_t pwdlen; /* password length */
> +
> +    grub_uint8_t *salt;    /* salt array */
> +    grub_uint32_t saltlen; /* salt length */
> +
> +    grub_uint8_t *secret;    /* key array */
> +    grub_uint32_t secretlen; /* key length */
> +
> +    grub_uint8_t *ad;    /* associated data array */
> +    grub_uint32_t adlen; /* associated data length */
> +
> +    grub_uint32_t t_cost;  /* number of passes */
> +    grub_uint32_t m_cost;  /* amount of memory requested (KB) */
> +    grub_uint32_t lanes;   /* number of lanes */
> +    grub_uint32_t threads; /* maximum number of threads */
> +
> +    grub_uint32_t version; /* version number */
> +
> +    allocate_fptr allocate_cbk; /* pointer to memory allocator */
> +    deallocate_fptr grub_free_cbk;   /* pointer to memory deallocator */
> +
> +    grub_uint32_t flags; /* array of bool options */
> +} argon2_context;
> +
> +/* Argon2 primitive type */
> +typedef enum Argon2_type {
> +  Argon2_d = 0,
> +  Argon2_i = 1,
> +  Argon2_id = 2
> +} argon2_type;
> +
> +/* Version of the algorithm */
> +typedef enum Argon2_version {
> +    ARGON2_VERSION_10 = 0x10,
> +    ARGON2_VERSION_13 = 0x13,
> +    ARGON2_VERSION_NUMBER = ARGON2_VERSION_13
> +} argon2_version;
> +
> +/**
> + * Hashes a password with Argon2, producing a raw hash at @hash
> + * @param t_cost Number of iterations
> + * @param m_cost Sets memory usage to m_cost kibibytes
> + * @param parallelism Number of threads and compute lanes
> + * @param pwd Pointer to password
> + * @param pwdlen Password size in bytes
> + * @param salt Pointer to salt
> + * @param saltlen Salt size in bytes
> + * @param hash Buffer where to write the raw hash - updated by the function
> + * @param hashlen Desired length of the hash in bytes
> + * @pre   Different parallelism levels will give different results
> + * @pre   Returns ARGON2_OK if successful
> + */
> +ARGON2_PUBLIC int argon2_hash(const grub_uint32_t t_cost, const grub_uint32_t m_cost,
> +                              const grub_uint32_t parallelism, const void *pwd,
> +                              const grub_size_t pwdlen, const void *salt,
> +                              const grub_size_t saltlen, void *hash,
> +                              const grub_size_t hashlen, argon2_type type,
> +                              const grub_uint32_t version);
> +
> +/**
> + * Get the associated error message for given error code
> + * @return  The error message associated with the given error code
> + */
> +ARGON2_PUBLIC const char *argon2_error_message(int error_code);
> +
> +#if defined(__cplusplus)
> +}
> +#endif
> +
> +#endif
> diff --git a/grub-core/lib/argon2/blake2/blake2-impl.h b/grub-core/lib/argon2/blake2/blake2-impl.h
> new file mode 100644
> index 000000000..3a795680b
> --- /dev/null
> +++ b/grub-core/lib/argon2/blake2/blake2-impl.h
> @@ -0,0 +1,151 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +#ifndef PORTABLE_BLAKE2_IMPL_H
> +#define PORTABLE_BLAKE2_IMPL_H
> +
> +#if defined(_MSC_VER)
> +#define BLAKE2_INLINE __inline
> +#elif defined(__GNUC__) || defined(__clang__)
> +#define BLAKE2_INLINE __inline__
> +#else
> +#define BLAKE2_INLINE
> +#endif
> +
> +/* Argon2 Team - Begin Code */
> +/*
> +   Not an exhaustive list, but should cover the majority of modern platforms
> +   Additionally, the code will always be correct---this is only a performance
> +   tweak.
> +*/
> +#if (defined(__BYTE_ORDER__) &&                                                \
> +     (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) ||                           \
> +    defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \
> +    defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) ||       \
> +    defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) ||                \
> +    defined(_M_ARM)
> +#define NATIVE_LITTLE_ENDIAN
> +#endif
> +/* Argon2 Team - End Code */
> +
> +static BLAKE2_INLINE grub_uint32_t load32(const void *src) {
> +#if defined(NATIVE_LITTLE_ENDIAN)
> +    grub_uint32_t w;
> +    grub_memcpy(&w, src, sizeof w);
> +    return w;
> +#else
> +    const grub_uint8_t *p = (const grub_uint8_t *)src;
> +    grub_uint32_t w = *p++;
> +    w |= (grub_uint32_t)(*p++) << 8;
> +    w |= (grub_uint32_t)(*p++) << 16;
> +    w |= (grub_uint32_t)(*p++) << 24;
> +    return w;
> +#endif
> +}
> +
> +static BLAKE2_INLINE grub_uint64_t load64(const void *src) {
> +#if defined(NATIVE_LITTLE_ENDIAN)
> +    grub_uint64_t w;
> +    grub_memcpy(&w, src, sizeof w);
> +    return w;
> +#else
> +    const grub_uint8_t *p = (const grub_uint8_t *)src;
> +    grub_uint64_t w = *p++;
> +    w |= (grub_uint64_t)(*p++) << 8;
> +    w |= (grub_uint64_t)(*p++) << 16;
> +    w |= (grub_uint64_t)(*p++) << 24;
> +    w |= (grub_uint64_t)(*p++) << 32;
> +    w |= (grub_uint64_t)(*p++) << 40;
> +    w |= (grub_uint64_t)(*p++) << 48;
> +    w |= (grub_uint64_t)(*p++) << 56;
> +    return w;
> +#endif
> +}
> +
> +static BLAKE2_INLINE void store32(void *dst, grub_uint32_t w) {
> +#if defined(NATIVE_LITTLE_ENDIAN)
> +    grub_memcpy(dst, &w, sizeof w);
> +#else
> +    grub_uint8_t *p = (grub_uint8_t *)dst;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +#endif
> +}
> +
> +static BLAKE2_INLINE void store64(void *dst, grub_uint64_t w) {
> +#if defined(NATIVE_LITTLE_ENDIAN)
> +    grub_memcpy(dst, &w, sizeof w);
> +#else
> +    grub_uint8_t *p = (grub_uint8_t *)dst;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +#endif
> +}
> +
> +static BLAKE2_INLINE grub_uint64_t load48(const void *src) {
> +    const grub_uint8_t *p = (const grub_uint8_t *)src;
> +    grub_uint64_t w = *p++;
> +    w |= (grub_uint64_t)(*p++) << 8;
> +    w |= (grub_uint64_t)(*p++) << 16;
> +    w |= (grub_uint64_t)(*p++) << 24;
> +    w |= (grub_uint64_t)(*p++) << 32;
> +    w |= (grub_uint64_t)(*p++) << 40;
> +    return w;
> +}
> +
> +static BLAKE2_INLINE void store48(void *dst, grub_uint64_t w) {
> +    grub_uint8_t *p = (grub_uint8_t *)dst;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +    w >>= 8;
> +    *p++ = (grub_uint8_t)w;
> +}
> +
> +static BLAKE2_INLINE grub_uint32_t rotr32(const grub_uint32_t w, const unsigned c) {
> +    return (w >> c) | (w << (32 - c));
> +}
> +
> +static BLAKE2_INLINE grub_uint64_t rotr64(const grub_uint64_t w, const unsigned c) {
> +    return (w >> c) | (w << (64 - c));
> +}
> +
> +#endif
> diff --git a/grub-core/lib/argon2/blake2/blake2.h b/grub-core/lib/argon2/blake2/blake2.h
> new file mode 100644
> index 000000000..4e8efeb22
> --- /dev/null
> +++ b/grub-core/lib/argon2/blake2/blake2.h
> @@ -0,0 +1,89 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +#ifndef PORTABLE_BLAKE2_H
> +#define PORTABLE_BLAKE2_H
> +
> +#include "../argon2.h"
> +
> +#if defined(__cplusplus)
> +extern "C" {
> +#endif
> +
> +enum blake2b_constant {
> +    BLAKE2B_BLOCKBYTES = 128,
> +    BLAKE2B_OUTBYTES = 64,
> +    BLAKE2B_KEYBYTES = 64,
> +    BLAKE2B_SALTBYTES = 16,
> +    BLAKE2B_PERSONALBYTES = 16
> +};
> +
> +#pragma pack(push, 1)
> +typedef struct __blake2b_param {
> +    grub_uint8_t digest_length;                   /* 1 */
> +    grub_uint8_t key_length;                      /* 2 */
> +    grub_uint8_t fanout;                          /* 3 */
> +    grub_uint8_t depth;                           /* 4 */
> +    grub_uint32_t leaf_length;                    /* 8 */
> +    grub_uint64_t node_offset;                    /* 16 */
> +    grub_uint8_t node_depth;                      /* 17 */
> +    grub_uint8_t inner_length;                    /* 18 */
> +    grub_uint8_t reserved[14];                    /* 32 */
> +    grub_uint8_t salt[BLAKE2B_SALTBYTES];         /* 48 */
> +    grub_uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
> +} blake2b_param;
> +#pragma pack(pop)
> +
> +typedef struct __blake2b_state {
> +    grub_uint64_t h[8];
> +    grub_uint64_t t[2];
> +    grub_uint64_t f[2];
> +    grub_uint8_t buf[BLAKE2B_BLOCKBYTES];
> +    unsigned buflen;
> +    unsigned outlen;
> +    grub_uint8_t last_node;
> +} blake2b_state;
> +
> +/* Ensure param structs have not been wrongly padded */
> +/* Poor man's static_assert */
> +enum {
> +    blake2_size_check_0 = 1 / !!(GRUB_CHAR_BIT == 8),
> +    blake2_size_check_2 =
> +        1 / !!(sizeof(blake2b_param) == sizeof(grub_uint64_t) * GRUB_CHAR_BIT)
> +};
> +
> +/* Streaming API */
> +ARGON2_LOCAL int blake2b_init(blake2b_state *S, grub_size_t outlen);
> +ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, grub_size_t outlen, const void *key,
> +                     grub_size_t keylen);
> +ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
> +ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, grub_size_t inlen);
> +ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, grub_size_t outlen);
> +
> +/* Simple API */
> +ARGON2_LOCAL int blake2b(void *out, grub_size_t outlen, const void *in, grub_size_t inlen,
> +                         const void *key, grub_size_t keylen);
> +
> +/* Argon2 Team - Begin Code */
> +ARGON2_LOCAL int blake2b_long(void *out, grub_size_t outlen, const void *in, grub_size_t inlen);
> +/* Argon2 Team - End Code */
> +
> +#if defined(__cplusplus)
> +}
> +#endif
> +
> +#endif
> diff --git a/grub-core/lib/argon2/blake2/blake2b.c b/grub-core/lib/argon2/blake2/blake2b.c
> new file mode 100644
> index 000000000..53abd7bef
> --- /dev/null
> +++ b/grub-core/lib/argon2/blake2/blake2b.c
> @@ -0,0 +1,388 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +#include "blake2.h"
> +#include "blake2-impl.h"
> +
> +static const grub_uint64_t blake2b_IV[8] = {
> +    GRUB_UINT64_C(0x6a09e667f3bcc908), GRUB_UINT64_C(0xbb67ae8584caa73b),
> +    GRUB_UINT64_C(0x3c6ef372fe94f82b), GRUB_UINT64_C(0xa54ff53a5f1d36f1),
> +    GRUB_UINT64_C(0x510e527fade682d1), GRUB_UINT64_C(0x9b05688c2b3e6c1f),
> +    GRUB_UINT64_C(0x1f83d9abfb41bd6b), GRUB_UINT64_C(0x5be0cd19137e2179)};
> +
> +static const unsigned int blake2b_sigma[12][16] = {
> +    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
> +    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
> +    {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
> +    {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
> +    {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
> +    {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
> +    {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
> +    {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
> +    {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
> +    {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
> +    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
> +    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
> +};
> +
> +void clear_internal_memory(void *v, grub_size_t n);
> +
> +static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S) {
> +    S->f[1] = (grub_uint64_t)-1;
> +}
> +
> +static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S) {
> +    if (S->last_node) {
> +        blake2b_set_lastnode(S);
> +    }
> +    S->f[0] = (grub_uint64_t)-1;
> +}
> +
> +static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S,
> +                                                    grub_uint64_t inc) {
> +    S->t[0] += inc;
> +    S->t[1] += (S->t[0] < inc);
> +}
> +
> +static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) {
> +    clear_internal_memory(S, sizeof(*S));      /* wipe */
> +    blake2b_set_lastblock(S); /* invalidate for further use */
> +}
> +
> +static BLAKE2_INLINE void blake2b_init0(blake2b_state *S) {
> +    grub_memset(S, 0, sizeof(*S));
> +    grub_memcpy(S->h, blake2b_IV, sizeof(S->h));
> +}
> +
> +int blake2b_init_param(blake2b_state *S, const blake2b_param *P) {
> +    const unsigned char *p = (const unsigned char *)P;
> +    unsigned int i;
> +
> +    if (NULL == P || NULL == S) {
> +        return -1;
> +    }
> +
> +    blake2b_init0(S);
> +    /* IV XOR Parameter Block */
> +    for (i = 0; i < 8; ++i) {
> +        S->h[i] ^= load64(&p[i * sizeof(S->h[i])]);
> +    }
> +    S->outlen = P->digest_length;
> +    return 0;
> +}
> +
> +/* Sequential blake2b initialization */
> +int blake2b_init(blake2b_state *S, grub_size_t outlen) {
> +    blake2b_param P;
> +
> +    if (S == NULL) {
> +        return -1;
> +    }
> +
> +    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
> +        blake2b_invalidate_state(S);
> +        return -1;
> +    }
> +
> +    /* Setup Parameter Block for unkeyed BLAKE2 */
> +    P.digest_length = (grub_uint8_t)outlen;
> +    P.key_length = 0;
> +    P.fanout = 1;
> +    P.depth = 1;
> +    P.leaf_length = 0;
> +    P.node_offset = 0;
> +    P.node_depth = 0;
> +    P.inner_length = 0;
> +    grub_memset(P.reserved, 0, sizeof(P.reserved));
> +    grub_memset(P.salt, 0, sizeof(P.salt));
> +    grub_memset(P.personal, 0, sizeof(P.personal));
> +
> +    return blake2b_init_param(S, &P);
> +}
> +
> +int blake2b_init_key(blake2b_state *S, grub_size_t outlen, const void *key,
> +                     grub_size_t keylen) {
> +    blake2b_param P;
> +
> +    if (S == NULL) {
> +        return -1;
> +    }
> +
> +    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
> +        blake2b_invalidate_state(S);
> +        return -1;
> +    }
> +
> +    if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) {
> +        blake2b_invalidate_state(S);
> +        return -1;
> +    }
> +
> +    /* Setup Parameter Block for keyed BLAKE2 */
> +    P.digest_length = (grub_uint8_t)outlen;
> +    P.key_length = (grub_uint8_t)keylen;
> +    P.fanout = 1;
> +    P.depth = 1;
> +    P.leaf_length = 0;
> +    P.node_offset = 0;
> +    P.node_depth = 0;
> +    P.inner_length = 0;
> +    grub_memset(P.reserved, 0, sizeof(P.reserved));
> +    grub_memset(P.salt, 0, sizeof(P.salt));
> +    grub_memset(P.personal, 0, sizeof(P.personal));
> +
> +    if (blake2b_init_param(S, &P) < 0) {
> +        blake2b_invalidate_state(S);
> +        return -1;
> +    }
> +
> +    {
> +        grub_uint8_t block[BLAKE2B_BLOCKBYTES];
> +        grub_memset(block, 0, BLAKE2B_BLOCKBYTES);
> +        grub_memcpy(block, key, keylen);
> +        blake2b_update(S, block, BLAKE2B_BLOCKBYTES);
> +        /* Burn the key from stack */
> +        clear_internal_memory(block, BLAKE2B_BLOCKBYTES);
> +    }
> +    return 0;
> +}
> +
> +static void blake2b_compress(blake2b_state *S, const grub_uint8_t *block) {
> +    grub_uint64_t m[16];
> +    grub_uint64_t v[16];
> +    unsigned int i, r;
> +
> +    for (i = 0; i < 16; ++i) {
> +        m[i] = load64(block + i * sizeof(m[i]));
> +    }
> +
> +    for (i = 0; i < 8; ++i) {
> +        v[i] = S->h[i];
> +    }
> +
> +    v[8] = blake2b_IV[0];
> +    v[9] = blake2b_IV[1];
> +    v[10] = blake2b_IV[2];
> +    v[11] = blake2b_IV[3];
> +    v[12] = blake2b_IV[4] ^ S->t[0];
> +    v[13] = blake2b_IV[5] ^ S->t[1];
> +    v[14] = blake2b_IV[6] ^ S->f[0];
> +    v[15] = blake2b_IV[7] ^ S->f[1];
> +
> +#define G(r, i, a, b, c, d)                                                    \
> +    do {                                                                       \
> +        a = a + b + m[blake2b_sigma[r][2 * i + 0]];                            \
> +        d = rotr64(d ^ a, 32);                                                 \
> +        c = c + d;                                                             \
> +        b = rotr64(b ^ c, 24);                                                 \
> +        a = a + b + m[blake2b_sigma[r][2 * i + 1]];                            \
> +        d = rotr64(d ^ a, 16);                                                 \
> +        c = c + d;                                                             \
> +        b = rotr64(b ^ c, 63);                                                 \
> +    } while ((void)0, 0)
> +
> +#define ROUND(r)                                                               \
> +    do {                                                                       \
> +        G(r, 0, v[0], v[4], v[8], v[12]);                                      \
> +        G(r, 1, v[1], v[5], v[9], v[13]);                                      \
> +        G(r, 2, v[2], v[6], v[10], v[14]);                                     \
> +        G(r, 3, v[3], v[7], v[11], v[15]);                                     \
> +        G(r, 4, v[0], v[5], v[10], v[15]);                                     \
> +        G(r, 5, v[1], v[6], v[11], v[12]);                                     \
> +        G(r, 6, v[2], v[7], v[8], v[13]);                                      \
> +        G(r, 7, v[3], v[4], v[9], v[14]);                                      \
> +    } while ((void)0, 0)
> +
> +    for (r = 0; r < 12; ++r) {
> +        ROUND(r);
> +    }
> +
> +    for (i = 0; i < 8; ++i) {
> +        S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
> +    }
> +
> +#undef G
> +#undef ROUND
> +}
> +
> +int blake2b_update(blake2b_state *S, const void *in, grub_size_t inlen) {
> +    const grub_uint8_t *pin = (const grub_uint8_t *)in;
> +
> +    if (inlen == 0) {
> +        return 0;
> +    }
> +
> +    /* Sanity check */
> +    if (S == NULL || in == NULL) {
> +        return -1;
> +    }
> +
> +    /* Is this a reused state? */
> +    if (S->f[0] != 0) {
> +        return -1;
> +    }
> +
> +    if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) {
> +        /* Complete current block */
> +        grub_size_t left = S->buflen;
> +        grub_size_t fill = BLAKE2B_BLOCKBYTES - left;
> +        grub_memcpy(&S->buf[left], pin, fill);
> +        blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
> +        blake2b_compress(S, S->buf);
> +        S->buflen = 0;
> +        inlen -= fill;
> +        pin += fill;
> +        /* Avoid buffer copies when possible */
> +        while (inlen > BLAKE2B_BLOCKBYTES) {
> +            blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
> +            blake2b_compress(S, pin);
> +            inlen -= BLAKE2B_BLOCKBYTES;
> +            pin += BLAKE2B_BLOCKBYTES;
> +        }
> +    }
> +    grub_memcpy(&S->buf[S->buflen], pin, inlen);
> +    S->buflen += (unsigned int)inlen;
> +    return 0;
> +}
> +
> +int blake2b_final(blake2b_state *S, void *out, grub_size_t outlen) {
> +    grub_uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
> +    unsigned int i;
> +
> +    /* Sanity checks */
> +    if (S == NULL || out == NULL || outlen < S->outlen) {
> +        return -1;
> +    }
> +
> +    /* Is this a reused state? */
> +    if (S->f[0] != 0) {
> +        return -1;
> +    }
> +
> +    blake2b_increment_counter(S, S->buflen);
> +    blake2b_set_lastblock(S);
> +    grub_memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */
> +    blake2b_compress(S, S->buf);
> +
> +    for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */
> +        store64(buffer + sizeof(S->h[i]) * i, S->h[i]);
> +    }
> +
> +    grub_memcpy(out, buffer, S->outlen);
> +    clear_internal_memory(buffer, sizeof(buffer));
> +    clear_internal_memory(S->buf, sizeof(S->buf));
> +    clear_internal_memory(S->h, sizeof(S->h));
> +    return 0;
> +}
> +
> +int blake2b(void *out, grub_size_t outlen, const void *in, grub_size_t inlen,
> +            const void *key, grub_size_t keylen) {
> +    blake2b_state S;
> +    int ret = -1;
> +
> +    /* Verify parameters */
> +    if (NULL == in && inlen > 0) {
> +        goto fail;
> +    }
> +
> +    if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) {
> +        goto fail;
> +    }
> +
> +    if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) {
> +        goto fail;
> +    }
> +
> +    if (keylen > 0) {
> +        if (blake2b_init_key(&S, outlen, key, keylen) < 0) {
> +            goto fail;
> +        }
> +    } else {
> +        if (blake2b_init(&S, outlen) < 0) {
> +            goto fail;
> +        }
> +    }
> +
> +    if (blake2b_update(&S, in, inlen) < 0) {
> +        goto fail;
> +    }
> +    ret = blake2b_final(&S, out, outlen);
> +
> +fail:
> +    clear_internal_memory(&S, sizeof(S));
> +    return ret;
> +}
> +
> +/* Argon2 Team - Begin Code */
> +int blake2b_long(void *pout, grub_size_t outlen, const void *in, grub_size_t inlen) {
> +    grub_uint8_t *out = (grub_uint8_t *)pout;
> +    blake2b_state blake_state;
> +    grub_uint8_t outlen_bytes[sizeof(grub_uint32_t)] = {0};
> +    int ret = -1;
> +
> +    if (outlen > GRUB_UINT32_MAX) {
> +        goto fail;
> +    }
> +
> +    /* Ensure little-endian byte order! */
> +    store32(outlen_bytes, (grub_uint32_t)outlen);
> +
> +#define TRY(statement)                                                         \
> +    do {                                                                       \
> +        ret = statement;                                                       \
> +        if (ret < 0) {                                                         \
> +            goto fail;                                                         \
> +        }                                                                      \
> +    } while ((void)0, 0)
> +
> +    if (outlen <= BLAKE2B_OUTBYTES) {
> +        TRY(blake2b_init(&blake_state, outlen));
> +        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
> +        TRY(blake2b_update(&blake_state, in, inlen));
> +        TRY(blake2b_final(&blake_state, out, outlen));
> +    } else {
> +        grub_uint32_t toproduce;
> +        grub_uint8_t out_buffer[BLAKE2B_OUTBYTES];
> +        grub_uint8_t in_buffer[BLAKE2B_OUTBYTES];
> +        TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES));
> +        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
> +        TRY(blake2b_update(&blake_state, in, inlen));
> +        TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES));
> +        grub_memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
> +        out += BLAKE2B_OUTBYTES / 2;
> +        toproduce = (grub_uint32_t)outlen - BLAKE2B_OUTBYTES / 2;
> +
> +        while (toproduce > BLAKE2B_OUTBYTES) {
> +            grub_memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
> +            TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer,
> +                        BLAKE2B_OUTBYTES, NULL, 0));
> +            grub_memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
> +            out += BLAKE2B_OUTBYTES / 2;
> +            toproduce -= BLAKE2B_OUTBYTES / 2;
> +        }
> +
> +        grub_memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
> +        TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL,
> +                    0));
> +        grub_memcpy(out, out_buffer, toproduce);
> +    }
> +fail:
> +    clear_internal_memory(&blake_state, sizeof(blake_state));
> +    return ret;
> +#undef TRY
> +}
> +/* Argon2 Team - End Code */
> diff --git a/grub-core/lib/argon2/blake2/blamka-round-ref.h b/grub-core/lib/argon2/blake2/blamka-round-ref.h
> new file mode 100644
> index 000000000..7f0071ada
> --- /dev/null
> +++ b/grub-core/lib/argon2/blake2/blamka-round-ref.h
> @@ -0,0 +1,56 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +#ifndef BLAKE_ROUND_MKA_H
> +#define BLAKE_ROUND_MKA_H
> +
> +#include "blake2.h"
> +#include "blake2-impl.h"
> +
> +/* designed by the Lyra PHC team */
> +static BLAKE2_INLINE grub_uint64_t fBlaMka(grub_uint64_t x, grub_uint64_t y) {
> +    const grub_uint64_t m = GRUB_UINT64_C(0xFFFFFFFF);
> +    const grub_uint64_t xy = (x & m) * (y & m);
> +    return x + y + 2 * xy;
> +}
> +
> +#define G(a, b, c, d)                                                          \
> +    do {                                                                       \
> +        a = fBlaMka(a, b);                                                     \
> +        d = rotr64(d ^ a, 32);                                                 \
> +        c = fBlaMka(c, d);                                                     \
> +        b = rotr64(b ^ c, 24);                                                 \
> +        a = fBlaMka(a, b);                                                     \
> +        d = rotr64(d ^ a, 16);                                                 \
> +        c = fBlaMka(c, d);                                                     \
> +        b = rotr64(b ^ c, 63);                                                 \
> +    } while ((void)0, 0)
> +
> +#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,   \
> +                           v12, v13, v14, v15)                                 \
> +    do {                                                                       \
> +        G(v0, v4, v8, v12);                                                    \
> +        G(v1, v5, v9, v13);                                                    \
> +        G(v2, v6, v10, v14);                                                   \
> +        G(v3, v7, v11, v15);                                                   \
> +        G(v0, v5, v10, v15);                                                   \
> +        G(v1, v6, v11, v12);                                                   \
> +        G(v2, v7, v8, v13);                                                    \
> +        G(v3, v4, v9, v14);                                                    \
> +    } while ((void)0, 0)
> +
> +#endif
> diff --git a/grub-core/lib/argon2/core.c b/grub-core/lib/argon2/core.c
> new file mode 100644
> index 000000000..1bb8e22e2
> --- /dev/null
> +++ b/grub-core/lib/argon2/core.c
> @@ -0,0 +1,525 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +/*For memory wiping*/
> +#ifdef _MSC_VER
> +#include <windows.h>
> +#include <winbase.h> /* For SecureZeroMemory */
> +#endif
> +#if defined __STDC_LIB_EXT1__
> +#define __STDC_WANT_LIB_EXT1__ 1
> +#endif
> +#define VC_GE_2005(version) (version >= 1400)
> +
> +/* for explicit_bzero() on glibc */
> +#define _DEFAULT_SOURCE
> +
> +#include "core.h"
> +#include "blake2/blake2.h"
> +#include "blake2/blake2-impl.h"
> +
> +#ifdef GENKAT
> +#include "genkat.h"
> +#endif
> +
> +#if defined(__clang__)
> +#if __has_attribute(optnone)
> +#define NOT_OPTIMIZED __attribute__((optnone))
> +#endif
> +#elif defined(__GNUC__)
> +#define GCC_VERSION                                                            \
> +    (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
> +#if GCC_VERSION >= 40400
> +#define NOT_OPTIMIZED __attribute__((optimize("O0")))
> +#endif
> +#endif
> +#ifndef NOT_OPTIMIZED
> +#define NOT_OPTIMIZED
> +#endif
> +
> +/***************Instance and Position constructors**********/
> +void init_block_value(block *b, grub_uint8_t in) { grub_memset(b->v, in, sizeof(b->v)); }
> +
> +void copy_block(block *dst, const block *src) {
> +    grub_memcpy(dst->v, src->v, sizeof(grub_uint64_t) * ARGON2_QWORDS_IN_BLOCK);
> +}
> +
> +void xor_block(block *dst, const block *src) {
> +    int i;
> +    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
> +        dst->v[i] ^= src->v[i];
> +    }
> +}
> +
> +static void load_block(block *dst, const void *input) {
> +    unsigned i;
> +    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
> +        dst->v[i] = load64((const grub_uint8_t *)input + i * sizeof(dst->v[i]));
> +    }
> +}
> +
> +static void store_block(void *output, const block *src) {
> +    unsigned i;
> +    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
> +        store64((grub_uint8_t *)output + i * sizeof(src->v[i]), src->v[i]);
> +    }
> +}
> +
> +/***************Memory functions*****************/
> +
> +int allocate_memory(const argon2_context *context, grub_uint8_t **memory,
> +                    grub_size_t num, grub_size_t size) {
> +    grub_size_t memory_size = num*size;
> +    if (memory == NULL) {
> +        return ARGON2_MEMORY_ALLOCATION_ERROR;
> +    }
> +
> +    /* 1. Check for multiplication overflow */
> +    if (size != 0 && memory_size / size != num) {
> +        return ARGON2_MEMORY_ALLOCATION_ERROR;
> +    }
> +
> +    /* 2. Try to allocate with appropriate allocator */
> +    if (context->allocate_cbk) {
> +        (context->allocate_cbk)(memory, memory_size);
> +    } else {
> +        *memory = grub_malloc(memory_size);
> +    }
> +
> +    if (*memory == NULL) {
> +        return ARGON2_MEMORY_ALLOCATION_ERROR;
> +    }
> +
> +    return ARGON2_OK;
> +}
> +
> +void grub_free_memory(const argon2_context *context, grub_uint8_t *memory,
> +                 grub_size_t num, grub_size_t size) {
> +    grub_size_t memory_size = num*size;
> +    clear_internal_memory(memory, memory_size);
> +    if (context->grub_free_cbk) {
> +        (context->grub_free_cbk)(memory, memory_size);
> +    } else {
> +        grub_free(memory);
> +    }
> +}
> +
> +#if defined(__OpenBSD__)
> +#define HAVE_EXPLICIT_BZERO 1
> +#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
> +#if __GLIBC_PREREQ(2,25)
> +#define HAVE_EXPLICIT_BZERO 1
> +#endif
> +#endif
> +
> +void NOT_OPTIMIZED secure_wipe_memory(void *v, grub_size_t n) {
> +#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER)
> +    SecureZeroMemory(v, n);
> +#elif defined grub_memset_s
> +    grub_memset_s(v, n, 0, n);
> +#elif defined(HAVE_EXPLICIT_BZERO)
> +    explicit_bzero(v, n);
> +#else
> +    static void *(*const volatile grub_memset_sec)(void *, int, grub_size_t) = &grub_memset;
> +    grub_memset_sec(v, 0, n);
> +#endif
> +}
> +
> +/* Memory clear flag defaults to true. */
> +int FLAG_clear_internal_memory = 1;
> +void clear_internal_memory(void *v, grub_size_t n) {
> +  if (FLAG_clear_internal_memory && v) {
> +    secure_wipe_memory(v, n);
> +  }
> +}
> +
> +void finalize(const argon2_context *context, argon2_instance_t *instance) {
> +    if (context != NULL && instance != NULL) {
> +        block blockhash;
> +        grub_uint32_t l;
> +
> +        copy_block(&blockhash, instance->memory + instance->lane_length - 1);
> +
> +        /* XOR the last blocks */
> +        for (l = 1; l < instance->lanes; ++l) {
> +            grub_uint32_t last_block_in_lane =
> +                l * instance->lane_length + (instance->lane_length - 1);
> +            xor_block(&blockhash, instance->memory + last_block_in_lane);
> +        }
> +
> +        /* Hash the result */
> +        {
> +            grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
> +            store_block(blockhash_bytes, &blockhash);
> +            blake2b_long(context->out, context->outlen, blockhash_bytes,
> +                         ARGON2_BLOCK_SIZE);
> +            /* clear blockhash and blockhash_bytes */
> +            clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE);
> +            clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
> +        }
> +
> +#ifdef GENKAT
> +        print_tag(context->out, context->outlen);
> +#endif
> +
> +        grub_free_memory(context, (grub_uint8_t *)instance->memory,
> +                    instance->memory_blocks, sizeof(block));
> +    }
> +}
> +
> +grub_uint32_t index_alpha(const argon2_instance_t *instance,
> +                     const argon2_position_t *position, grub_uint32_t pseudo_rand,
> +                     int same_lane) {
> +    /*
> +     * Pass 0:
> +     *      This lane : all already finished segments plus already constructed
> +     * blocks in this segment
> +     *      Other lanes : all already finished segments
> +     * Pass 1+:
> +     *      This lane : (SYNC_POINTS - 1) last segments plus already constructed
> +     * blocks in this segment
> +     *      Other lanes : (SYNC_POINTS - 1) last segments
> +     */
> +    grub_uint32_t reference_area_size;
> +    grub_uint64_t relative_position;
> +    grub_uint32_t start_position, absolute_position;
> +
> +    if (0 == position->pass) {
> +        /* First pass */
> +        if (0 == position->slice) {
> +            /* First slice */
> +            reference_area_size =
> +                position->index - 1; /* all but the previous */
> +        } else {
> +            if (same_lane) {
> +                /* The same lane => add current segment */
> +                reference_area_size =
> +                    position->slice * instance->segment_length +
> +                    position->index - 1;
> +            } else {
> +                reference_area_size =
> +                    position->slice * instance->segment_length +
> +                    ((position->index == 0) ? (-1) : 0);
> +            }
> +        }
> +    } else {
> +        /* Second pass */
> +        if (same_lane) {
> +            reference_area_size = instance->lane_length -
> +                                  instance->segment_length + position->index -
> +                                  1;
> +        } else {
> +            reference_area_size = instance->lane_length -
> +                                  instance->segment_length +
> +                                  ((position->index == 0) ? (-1) : 0);
> +        }
> +    }
> +
> +    /* 1.2.4. Mapping pseudo_rand to 0..<reference_area_size-1> and produce
> +     * relative position */
> +    relative_position = pseudo_rand;
> +    relative_position = relative_position * relative_position >> 32;
> +    relative_position = reference_area_size - 1 -
> +                        (reference_area_size * relative_position >> 32);
> +
> +    /* 1.2.5 Computing starting position */
> +    start_position = 0;
> +
> +    if (0 != position->pass) {
> +        start_position = (position->slice == ARGON2_SYNC_POINTS - 1)
> +                             ? 0
> +                             : (position->slice + 1) * instance->segment_length;
> +    }
> +
> +    /* 1.2.6. Computing absolute position */
> +    absolute_position = (start_position + relative_position) %
> +                        instance->lane_length; /* absolute position */
> +    return absolute_position;
> +}
> +
> +/* Single-threaded version for p=1 case */
> +static int fill_memory_blocks_st(argon2_instance_t *instance) {
> +    grub_uint32_t r, s, l;
> +
> +    for (r = 0; r < instance->passes; ++r) {
> +        for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
> +            for (l = 0; l < instance->lanes; ++l) {
> +                argon2_position_t position = {r, l, (grub_uint8_t)s, 0};
> +                fill_segment(instance, position);
> +            }
> +        }
> +#ifdef GENKAT
> +        internal_kat(instance, r); /* Print all memory blocks */
> +#endif
> +    }
> +    return ARGON2_OK;
> +}
> +
> +int fill_memory_blocks(argon2_instance_t *instance) {
> +	if (instance == NULL || instance->lanes == 0) {
> +	    return ARGON2_INCORRECT_PARAMETER;
> +    }
> +    return fill_memory_blocks_st(instance);
> +}
> +
> +int validate_inputs(const argon2_context *context) {
> +    if (NULL == context) {
> +        return ARGON2_INCORRECT_PARAMETER;
> +    }
> +
> +    if (NULL == context->out) {
> +        return ARGON2_OUTPUT_PTR_NULL;
> +    }
> +
> +    /* Validate output length */
> +    if (ARGON2_MIN_OUTLEN > context->outlen) {
> +        return ARGON2_OUTPUT_TOO_SHORT;
> +    }
> +
> +    if (ARGON2_MAX_OUTLEN < context->outlen) {
> +        return ARGON2_OUTPUT_TOO_LONG;
> +    }
> +
> +    /* Validate password (required param) */
> +    if (NULL == context->pwd) {
> +        if (0 != context->pwdlen) {
> +            return ARGON2_PWD_PTR_MISMATCH;
> +        }
> +    }
> +
> +    if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {
> +        return ARGON2_PWD_TOO_LONG;
> +    }
> +
> +    /* Validate salt (required param) */
> +    if (NULL == context->salt) {
> +        if (0 != context->saltlen) {
> +            return ARGON2_SALT_PTR_MISMATCH;
> +        }
> +    }
> +
> +    if (ARGON2_MIN_SALT_LENGTH > context->saltlen) {
> +        return ARGON2_SALT_TOO_SHORT;
> +    }
> +
> +    if (ARGON2_MAX_SALT_LENGTH < context->saltlen) {
> +        return ARGON2_SALT_TOO_LONG;
> +    }
> +
> +    /* Validate secret (optional param) */
> +    if (NULL == context->secret) {
> +        if (0 != context->secretlen) {
> +            return ARGON2_SECRET_PTR_MISMATCH;
> +        }
> +    } else {
> +        if (ARGON2_MAX_SECRET < context->secretlen) {
> +            return ARGON2_SECRET_TOO_LONG;
> +        }
> +    }
> +
> +    /* Validate associated data (optional param) */
> +    if (NULL == context->ad) {
> +        if (0 != context->adlen) {
> +            return ARGON2_AD_PTR_MISMATCH;
> +        }
> +    } else {
> +        if (ARGON2_MAX_AD_LENGTH < context->adlen) {
> +            return ARGON2_AD_TOO_LONG;
> +        }
> +    }
> +
> +    /* Validate memory cost */
> +    if (ARGON2_MIN_MEMORY > context->m_cost) {
> +        return ARGON2_MEMORY_TOO_LITTLE;
> +    }
> +
> +    if (context->m_cost < 8 * context->lanes) {
> +        return ARGON2_MEMORY_TOO_LITTLE;
> +    }
> +
> +    /* Validate time cost */
> +    if (ARGON2_MIN_TIME > context->t_cost) {
> +        return ARGON2_TIME_TOO_SMALL;
> +    }
> +
> +    if (ARGON2_MAX_TIME < context->t_cost) {
> +        return ARGON2_TIME_TOO_LARGE;
> +    }
> +
> +    /* Validate lanes */
> +    if (ARGON2_MIN_LANES > context->lanes) {
> +        return ARGON2_LANES_TOO_FEW;
> +    }
> +
> +    if (ARGON2_MAX_LANES < context->lanes) {
> +        return ARGON2_LANES_TOO_MANY;
> +    }
> +
> +    /* Validate threads */
> +    if (ARGON2_MIN_THREADS > context->threads) {
> +        return ARGON2_THREADS_TOO_FEW;
> +    }
> +
> +    if (ARGON2_MAX_THREADS < context->threads) {
> +        return ARGON2_THREADS_TOO_MANY;
> +    }
> +
> +    if (NULL != context->allocate_cbk && NULL == context->grub_free_cbk) {
> +        return ARGON2_FREE_MEMORY_CBK_NULL;
> +    }
> +
> +    if (NULL == context->allocate_cbk && NULL != context->grub_free_cbk) {
> +        return ARGON2_ALLOCATE_MEMORY_CBK_NULL;
> +    }
> +
> +    return ARGON2_OK;
> +}
> +
> +void fill_first_blocks(grub_uint8_t *blockhash, const argon2_instance_t *instance) {
> +    grub_uint32_t l;
> +    /* Make the first and second block in each lane as G(H0||0||i) or
> +       G(H0||1||i) */
> +    grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
> +    for (l = 0; l < instance->lanes; ++l) {
> +
> +        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0);
> +        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l);
> +        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
> +                     ARGON2_PREHASH_SEED_LENGTH);
> +        load_block(&instance->memory[l * instance->lane_length + 0],
> +                   blockhash_bytes);
> +
> +        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1);
> +        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
> +                     ARGON2_PREHASH_SEED_LENGTH);
> +        load_block(&instance->memory[l * instance->lane_length + 1],
> +                   blockhash_bytes);
> +    }
> +    clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
> +}
> +
> +void initial_hash(grub_uint8_t *blockhash, argon2_context *context,
> +                  argon2_type type) {
> +    blake2b_state BlakeHash;
> +    grub_uint8_t value[sizeof(grub_uint32_t)];
> +
> +    if (NULL == context || NULL == blockhash) {
> +        return;
> +    }
> +
> +    blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH);
> +
> +    store32(&value, context->lanes);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    store32(&value, context->outlen);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    store32(&value, context->m_cost);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    store32(&value, context->t_cost);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    store32(&value, context->version);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    store32(&value, (grub_uint32_t)type);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    store32(&value, context->pwdlen);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    if (context->pwd != NULL) {
> +        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->pwd,
> +                       context->pwdlen);
> +
> +        if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) {
> +            secure_wipe_memory(context->pwd, context->pwdlen);
> +            context->pwdlen = 0;
> +        }
> +    }
> +
> +    store32(&value, context->saltlen);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    if (context->salt != NULL) {
> +        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->salt,
> +                       context->saltlen);
> +    }
> +
> +    store32(&value, context->secretlen);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    if (context->secret != NULL) {
> +        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->secret,
> +                       context->secretlen);
> +
> +        if (context->flags & ARGON2_FLAG_CLEAR_SECRET) {
> +            secure_wipe_memory(context->secret, context->secretlen);
> +            context->secretlen = 0;
> +        }
> +    }
> +
> +    store32(&value, context->adlen);
> +    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
> +
> +    if (context->ad != NULL) {
> +        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->ad,
> +                       context->adlen);
> +    }
> +
> +    blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH);
> +}
> +
> +int initialize(argon2_instance_t *instance, argon2_context *context) {
> +    grub_uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH];
> +    int result = ARGON2_OK;
> +
> +    if (instance == NULL || context == NULL)
> +        return ARGON2_INCORRECT_PARAMETER;
> +    instance->context_ptr = context;
> +
> +    /* 1. Memory allocation */
> +    result = allocate_memory(context, (grub_uint8_t **)&(instance->memory),
> +                             instance->memory_blocks, sizeof(block));
> +    if (result != ARGON2_OK) {
> +        return result;
> +    }
> +
> +    /* 2. Initial hashing */
> +    /* H_0 + 8 extra bytes to produce the first blocks */
> +    /* grub_uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */
> +    /* Hashing all inputs */
> +    initial_hash(blockhash, context, instance->type);
> +    /* Zeroing 8 extra bytes */
> +    clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH,
> +                          ARGON2_PREHASH_SEED_LENGTH -
> +                              ARGON2_PREHASH_DIGEST_LENGTH);
> +
> +#ifdef GENKAT
> +    initial_kat(blockhash, context, instance->type);
> +#endif
> +
> +    /* 3. Creating first blocks, we always have at least two blocks in a slice
> +     */
> +    fill_first_blocks(blockhash, instance);
> +    /* Clearing the hash */
> +    clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH);
> +
> +    return ARGON2_OK;
> +}
> diff --git a/grub-core/lib/argon2/core.h b/grub-core/lib/argon2/core.h
> new file mode 100644
> index 000000000..bbcd56998
> --- /dev/null
> +++ b/grub-core/lib/argon2/core.h
> @@ -0,0 +1,228 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +#ifndef ARGON2_CORE_H
> +#define ARGON2_CORE_H
> +
> +#include "argon2.h"
> +
> +#define CONST_CAST(x) (x)(grub_addr_t)
> +
> +/**********************Argon2 internal constants*******************************/
> +
> +enum argon2_core_constants {
> +    /* Memory block size in bytes */
> +    ARGON2_BLOCK_SIZE = 1024,
> +    ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
> +    ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
> +    ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
> +    ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
> +
> +    /* Number of pseudo-random values generated by one call to Blake in Argon2i
> +       to
> +       generate reference block positions */
> +    ARGON2_ADDRESSES_IN_BLOCK = 128,
> +
> +    /* Pre-hashing digest length and its extension*/
> +    ARGON2_PREHASH_DIGEST_LENGTH = 64,
> +    ARGON2_PREHASH_SEED_LENGTH = 72
> +};
> +
> +/*************************Argon2 internal data types***********************/
> +
> +/*
> + * Structure for the (1KB) memory block implemented as 128 64-bit words.
> + * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no
> + * bounds checking).
> + */
> +typedef struct block_ { grub_uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block;
> +
> +/*****************Functions that work with the block******************/
> +
> +/* Initialize each byte of the block with @in */
> +void init_block_value(block *b, grub_uint8_t in);
> +
> +/* Copy block @src to block @dst */
> +void copy_block(block *dst, const block *src);
> +
> +/* XOR @src onto @dst bytewise */
> +void xor_block(block *dst, const block *src);
> +
> +/*
> + * Argon2 instance: memory pointer, number of passes, amount of memory, type,
> + * and derived values.
> + * Used to evaluate the number and location of blocks to construct in each
> + * thread
> + */
> +typedef struct Argon2_instance_t {
> +    block *memory;          /* Memory pointer */
> +    grub_uint32_t version;
> +    grub_uint32_t passes;        /* Number of passes */
> +    grub_uint32_t memory_blocks; /* Number of blocks in memory */
> +    grub_uint32_t segment_length;
> +    grub_uint32_t lane_length;
> +    grub_uint32_t lanes;
> +    grub_uint32_t threads;
> +    argon2_type type;
> +    int print_internals; /* whether to print the memory blocks */
> +    argon2_context *context_ptr; /* points back to original context */
> +} argon2_instance_t;
> +
> +/*
> + * Argon2 position: where we construct the block right now. Used to distribute
> + * work between threads.
> + */
> +typedef struct Argon2_position_t {
> +    grub_uint32_t pass;
> +    grub_uint32_t lane;
> +    grub_uint8_t slice;
> +    grub_uint32_t index;
> +} argon2_position_t;
> +
> +/*Struct that holds the inputs for thread handling FillSegment*/
> +typedef struct Argon2_thread_data {
> +    argon2_instance_t *instance_ptr;
> +    argon2_position_t pos;
> +} argon2_thread_data;
> +
> +/*************************Argon2 core functions********************************/
> +
> +/* Allocates memory to the given pointer, uses the appropriate allocator as
> + * specified in the context. Total allocated memory is num*size.
> + * @param context argon2_context which specifies the allocator
> + * @param memory pointer to the pointer to the memory
> + * @param size the size in bytes for each element to be allocated
> + * @param num the number of elements to be allocated
> + * @return ARGON2_OK if @memory is a valid pointer and memory is allocated
> + */
> +int allocate_memory(const argon2_context *context, grub_uint8_t **memory,
> +                    grub_size_t num, grub_size_t size);
> +
> +/*
> + * Frees memory at the given pointer, uses the appropriate deallocator as
> + * specified in the context. Also cleans the memory using clear_internal_memory.
> + * @param context argon2_context which specifies the deallocator
> + * @param memory pointer to buffer to be grub_freed
> + * @param size the size in bytes for each element to be deallocated
> + * @param num the number of elements to be deallocated
> + */
> +void grub_free_memory(const argon2_context *context, grub_uint8_t *memory,
> +                 grub_size_t num, grub_size_t size);
> +
> +/* Function that securely cleans the memory. This ignores any flags set
> + * regarding clearing memory. Usually one just calls clear_internal_memory.
> + * @param mem Pointer to the memory
> + * @param s Memory size in bytes
> + */
> +void secure_wipe_memory(void *v, grub_size_t n);
> +
> +/* Function that securely clears the memory if FLAG_clear_internal_memory is
> + * set. If the flag isn't set, this function does nothing.
> + * @param mem Pointer to the memory
> + * @param s Memory size in bytes
> + */
> +void clear_internal_memory(void *v, grub_size_t n);
> +
> +/*
> + * Computes absolute position of reference block in the lane following a skewed
> + * distribution and using a pseudo-random value as input
> + * @param instance Pointer to the current instance
> + * @param position Pointer to the current position
> + * @param pseudo_rand 32-bit pseudo-random value used to determine the position
> + * @param same_lane Indicates if the block will be taken from the current lane.
> + * If so we can reference the current segment
> + * @pre All pointers must be valid
> + */
> +grub_uint32_t index_alpha(const argon2_instance_t *instance,
> +                     const argon2_position_t *position, grub_uint32_t pseudo_rand,
> +                     int same_lane);
> +
> +/*
> + * Function that validates all inputs against predefined restrictions and return
> + * an error code
> + * @param context Pointer to current Argon2 context
> + * @return ARGON2_OK if everything is all right, otherwise one of error codes
> + * (all defined in <argon2.h>
> + */
> +int validate_inputs(const argon2_context *context);
> +
> +/*
> + * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears
> + * password and secret if needed
> + * @param  context  Pointer to the Argon2 internal structure containing memory
> + * pointer, and parameters for time and space requirements.
> + * @param  blockhash Buffer for pre-hashing digest
> + * @param  type Argon2 type
> + * @pre    @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes
> + * allocated
> + */
> +void initial_hash(grub_uint8_t *blockhash, argon2_context *context,
> +                  argon2_type type);
> +
> +/*
> + * Function creates first 2 blocks per lane
> + * @param instance Pointer to the current instance
> + * @param blockhash Pointer to the pre-hashing digest
> + * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values
> + */
> +void fill_first_blocks(grub_uint8_t *blockhash, const argon2_instance_t *instance);
> +
> +/*
> + * Function allocates memory, hashes the inputs with Blake,  and creates first
> + * two blocks. Returns the pointer to the main memory with 2 blocks per lane
> + * initialized
> + * @param  context  Pointer to the Argon2 internal structure containing memory
> + * pointer, and parameters for time and space requirements.
> + * @param  instance Current Argon2 instance
> + * @return Zero if successful, -1 if memory failed to allocate. @context->state
> + * will be modified if successful.
> + */
> +int initialize(argon2_instance_t *instance, argon2_context *context);
> +
> +/*
> + * XORing the last block of each lane, hashing it, making the tag. Deallocates
> + * the memory.
> + * @param context Pointer to current Argon2 context (use only the out parameters
> + * from it)
> + * @param instance Pointer to current instance of Argon2
> + * @pre instance->state must point to necessary amount of memory
> + * @pre context->out must point to outlen bytes of memory
> + * @pre if context->grub_free_cbk is not NULL, it should point to a function that
> + * deallocates memory
> + */
> +void finalize(const argon2_context *context, argon2_instance_t *instance);
> +
> +/*
> + * Function that fills the segment using previous segments also from other
> + * threads
> + * @param context current context
> + * @param instance Pointer to the current instance
> + * @param position Current position
> + * @pre all block pointers must be valid
> + */
> +void fill_segment(const argon2_instance_t *instance,
> +                  argon2_position_t position);
> +
> +/*
> + * Function that fills the entire memory t_cost times based on the first two
> + * blocks in each lane
> + * @param instance Pointer to the current instance
> + * @return ARGON2_OK if successful, @context->state
> + */
> +int fill_memory_blocks(argon2_instance_t *instance);
> +
> +#endif
> diff --git a/grub-core/lib/argon2/ref.c b/grub-core/lib/argon2/ref.c
> new file mode 100644
> index 000000000..d1f4134b3
> --- /dev/null
> +++ b/grub-core/lib/argon2/ref.c
> @@ -0,0 +1,190 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +#include "argon2.h"
> +#include "core.h"
> +
> +#include "blake2/blamka-round-ref.h"
> +#include "blake2/blake2-impl.h"
> +#include "blake2/blake2.h"
> +
> +
> +/*
> + * Function fills a new memory block and optionally XORs the old block over the new one.
> + * @next_block must be initialized.
> + * @param prev_block Pointer to the previous block
> + * @param ref_block Pointer to the reference block
> + * @param next_block Pointer to the block to be constructed
> + * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
> + * @pre all block pointers must be valid
> + */
> +static void fill_block(const block *prev_block, const block *ref_block,
> +                       block *next_block, int with_xor) {
> +    block blockR, block_tmp;
> +    unsigned i;
> +
> +    copy_block(&blockR, ref_block);
> +    xor_block(&blockR, prev_block);
> +    copy_block(&block_tmp, &blockR);
> +    /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */
> +    if (with_xor) {
> +        /* Saving the next block contents for XOR over: */
> +        xor_block(&block_tmp, next_block);
> +        /* Now blockR = ref_block + prev_block and
> +           block_tmp = ref_block + prev_block + next_block */
> +    }
> +
> +    /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
> +       (16,17,..31)... finally (112,113,...127) */
> +    for (i = 0; i < 8; ++i) {
> +        BLAKE2_ROUND_NOMSG(
> +            blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],
> +            blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],
> +            blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],
> +            blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],
> +            blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],
> +            blockR.v[16 * i + 15]);
> +    }
> +
> +    /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then
> +       (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */
> +    for (i = 0; i < 8; i++) {
> +        BLAKE2_ROUND_NOMSG(
> +            blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],
> +            blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],
> +            blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],
> +            blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],
> +            blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],
> +            blockR.v[2 * i + 113]);
> +    }
> +
> +    copy_block(next_block, &block_tmp);
> +    xor_block(next_block, &blockR);
> +}
> +
> +static void next_addresses(block *address_block, block *input_block,
> +                           const block *zero_block) {
> +    input_block->v[6]++;
> +    fill_block(zero_block, input_block, address_block, 0);
> +    fill_block(zero_block, address_block, address_block, 0);
> +}
> +
> +void fill_segment(const argon2_instance_t *instance,
> +                  argon2_position_t position) {
> +    block *ref_block = NULL, *curr_block = NULL;
> +    block address_block, input_block, zero_block;
> +    grub_uint64_t pseudo_rand, ref_index, ref_lane;
> +    grub_uint32_t prev_offset, curr_offset;
> +    grub_uint32_t starting_index;
> +    grub_uint32_t i;
> +    int data_independent_addressing;
> +
> +    if (instance == NULL) {
> +        return;
> +    }
> +
> +    data_independent_addressing =
> +        (instance->type == Argon2_i) ||
> +        (instance->type == Argon2_id && (position.pass == 0) &&
> +         (position.slice < ARGON2_SYNC_POINTS / 2));
> +
> +    if (data_independent_addressing) {
> +        init_block_value(&zero_block, 0);
> +        init_block_value(&input_block, 0);
> +
> +        input_block.v[0] = position.pass;
> +        input_block.v[1] = position.lane;
> +        input_block.v[2] = position.slice;
> +        input_block.v[3] = instance->memory_blocks;
> +        input_block.v[4] = instance->passes;
> +        input_block.v[5] = instance->type;
> +    }
> +
> +    starting_index = 0;
> +
> +    if ((0 == position.pass) && (0 == position.slice)) {
> +        starting_index = 2; /* we have already generated the first two blocks */
> +
> +        /* Don't forget to generate the first block of addresses: */
> +        if (data_independent_addressing) {
> +            next_addresses(&address_block, &input_block, &zero_block);
> +        }
> +    }
> +
> +    /* Offset of the current block */
> +    curr_offset = position.lane * instance->lane_length +
> +                  position.slice * instance->segment_length + starting_index;
> +
> +    if (0 == curr_offset % instance->lane_length) {
> +        /* Last block in this lane */
> +        prev_offset = curr_offset + instance->lane_length - 1;
> +    } else {
> +        /* Previous block */
> +        prev_offset = curr_offset - 1;
> +    }
> +
> +    for (i = starting_index; i < instance->segment_length;
> +         ++i, ++curr_offset, ++prev_offset) {
> +        /*1.1 Rotating prev_offset if needed */
> +        if (curr_offset % instance->lane_length == 1) {
> +            prev_offset = curr_offset - 1;
> +        }
> +
> +        /* 1.2 Computing the index of the reference block */
> +        /* 1.2.1 Taking pseudo-random value from the previous block */
> +        if (data_independent_addressing) {
> +            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
> +                next_addresses(&address_block, &input_block, &zero_block);
> +            }
> +            pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
> +        } else {
> +            pseudo_rand = instance->memory[prev_offset].v[0];
> +        }
> +
> +        /* 1.2.2 Computing the lane of the reference block */
> +        ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
> +
> +        if ((position.pass == 0) && (position.slice == 0)) {
> +            /* Can not reference other lanes yet */
> +            ref_lane = position.lane;
> +        }
> +
> +        /* 1.2.3 Computing the number of possible reference block within the
> +         * lane.
> +         */
> +        position.index = i;
> +        ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
> +                                ref_lane == position.lane);
> +
> +        /* 2 Creating a new block */
> +        ref_block =
> +            instance->memory + instance->lane_length * ref_lane + ref_index;
> +        curr_block = instance->memory + curr_offset;
> +        if (ARGON2_VERSION_10 == instance->version) {
> +            /* version 1.2.1 and earlier: overwrite, not XOR */
> +            fill_block(instance->memory + prev_offset, ref_block, curr_block, 0);
> +        } else {
> +            if(0 == position.pass) {
> +                fill_block(instance->memory + prev_offset, ref_block,
> +                           curr_block, 0);
> +            } else {
> +                fill_block(instance->memory + prev_offset, ref_block,
> +                           curr_block, 1);
> +            }
> +        }
> +    }
> +}
> 


-- 
Eli Schwartz
Bug Wrangler and Trusted User


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 1601 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-10 20:44   ` Eli Schwartz
@ 2020-03-10 21:42     ` Patrick Steinhardt
  0 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-10 21:42 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 1340 bytes --]

On Tue, Mar 10, 2020 at 04:44:11PM -0400, Eli Schwartz wrote:
> On 3/10/20 2:58 PM, Patrick Steinhardt wrote:
> > In order to support the Argon2 key derival function for LUKS2, we
> > obviously need to implement Argon2. It doesn't make a lot of sense to
> > hand-code any crypto, which is why this commit instead imports Argon2
> > from the cryptsetup project. This commit thus imports the code from the
> > official reference implementation located at [1].
> 
> Which one is it? :p
> 
> Perhaps, "which is why this commit instead imports the Argon2
> implementation used by the cryptsetup project, that is, the official
> reference implementation located at [1]."

Oops, yes. This is an artifact caused by switching implementations from
cryptsetup to the reference implementation midway through. Thanks for
pointing out, will fix!

> 
> > The code is licensed
> > under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
> > 2.0 are compatible with GPLv3, it should be fine to import that code.
> > 
> > The code is imported from commit 62358ba (Merge pull request #270 from
> > bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
> > several adjustments were required that have beed documented in
> > "grub-dev.texi".
> 
> typo:
> 
> "beed" -> "been"

Ditto.

Patrick

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB
  2020-03-10 18:58 ` [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB Patrick Steinhardt
@ 2020-03-13 12:42   ` Daniel Kiper
  2020-03-13 12:55   ` Leif Lindholm
  1 sibling, 0 replies; 41+ messages in thread
From: Daniel Kiper @ 2020-03-13 12:42 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Leif Lindholm, agraf, pjones, mjg59, phcoder, Milan Broz

On Tue, Mar 10, 2020 at 07:58:28PM +0100, Patrick Steinhardt wrote:
> By default, GRUB will allocate a quarter of the pages it got available
> in the EFI subsystem. On many current systems, this will amount to
> roughly 800MB of RAM assuming an address space of 32 bits. This is
> plenty for most use cases, but it doesn't suffice when using full disk
> encryption with a key derival function based on Argon2.
>
> Besides the usual iteration count known from PBKDF2, Argon2 introduces
> two additional parameters "memory" and "parallelism". While the latter
> doesn't really matter to us, the memory parameter is quite interesting.
> If encrypting a partition with LUKS2 using Argon2 as KDF, then
> cryptsetup will default to a memory parameter of 1GB. Meaning we need to
> allocate a buffer of 1GB in size in order to be able to derive the key,
> which definitely won't squeeze into the limit of 800MB.
>
> To prepare for Argon2, this commit reworks the memory allocation
> algorithm for EFI platforms. Instead of trying to allocate a quarter of
> memory available, let's instead introduce a constant target amount of
> bytes that we try to allocate. The target is set to the previous value
> of MAX_HEAP_SIZE, which amounts to 1.6GB and thus sufficiently high to
> accomodate for both Argon2 as well as other functionality. The value is
> then clamped to at most half of available memory but at least 100MB.

It seems to me that 0x100000 (MIN_HEAP_PAGES) equals to 1 MiB...

> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  grub-core/kern/efi/mm.c | 21 +++++++++++----------
>  1 file changed, 11 insertions(+), 10 deletions(-)
>
> diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
> index b02fab1b1..367a726c6 100644
> --- a/grub-core/kern/efi/mm.c
> +++ b/grub-core/kern/efi/mm.c
> @@ -39,8 +39,8 @@
>  #define MEMORY_MAP_SIZE	0x3000
>
>  /* The minimum and maximum heap size for GRUB itself.  */
> -#define MIN_HEAP_SIZE	0x100000
> -#define MAX_HEAP_SIZE	(1600 * 0x100000)
> +#define MIN_HEAP_PAGES		BYTES_TO_PAGES(       0x100000)
> +#define TARGET_HEAP_PAGES	BYTES_TO_PAGES(1600 * 0x100000)
>
>  static void *finish_mmap_buf = 0;
>  static grub_efi_uintn_t finish_mmap_size = 0;
> @@ -559,7 +559,7 @@ grub_efi_mm_init (void)
>    grub_efi_uintn_t map_size;
>    grub_efi_uintn_t desc_size;
>    grub_efi_uint64_t total_pages;
> -  grub_efi_uint64_t required_pages;
> +  grub_efi_uint64_t target_heap_pages;
>    int mm_status;
>
>    /* Prepare a memory region to store two memory maps.  */
> @@ -599,14 +599,15 @@ grub_efi_mm_init (void)
>    filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
>  					       desc_size, memory_map_end);
>
> -  /* By default, request a quarter of the available memory.  */
> +  /* By default, request TARGET_HEAP_PAGES pages. If that exceeds half of meory
> +   * available, clamp it, but request at least MIN_HEAP_PAGES. */
>    total_pages = get_total_pages (filtered_memory_map, desc_size,
>  				 filtered_memory_map_end);
> -  required_pages = (total_pages >> 2);
> -  if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
> -    required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
> -  else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))
> -    required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE);
> +  target_heap_pages = TARGET_HEAP_PAGES;
> +  if (target_heap_pages > (total_pages / 2))
> +    target_heap_pages = total_pages / 2;
> +  if (target_heap_pages < MIN_HEAP_PAGES)
> +    target_heap_pages = MIN_HEAP_PAGES;

target_heap_pages = grub_min (total_pages / 2, TARGET_HEAP_PAGES);
target_heap_pages = grub_max (target_heap_pages, MIN_HEAP_PAGES);

Except that algorithm LGTM. Leif?

Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 2/5] types.h: add UINT-related macros needed for Argon2
  2020-03-10 18:58 ` [PATCH v3 2/5] types.h: add UINT-related macros needed for Argon2 Patrick Steinhardt
@ 2020-03-13 12:49   ` Daniel Kiper
  0 siblings, 0 replies; 41+ messages in thread
From: Daniel Kiper @ 2020-03-13 12:49 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Leif Lindholm, agraf, pjones, mjg59, phcoder, Milan Broz

On Tue, Mar 10, 2020 at 07:58:29PM +0100, Patrick Steinhardt wrote:
> For the upcoming import of the Argon2 library, we need the macros
> GRUB_UINT32_MAX, GRUB_UINT32_C and GRUB_UINT64_C. Add them as a
> preparatory step.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>

Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>

Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB
  2020-03-10 18:58 ` [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB Patrick Steinhardt
  2020-03-13 12:42   ` Daniel Kiper
@ 2020-03-13 12:55   ` Leif Lindholm
  2020-03-13 13:59     ` Daniel Kiper
                       ` (2 more replies)
  1 sibling, 3 replies; 41+ messages in thread
From: Leif Lindholm @ 2020-03-13 12:55 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, agraf, pjones, mjg59, phcoder, Milan Broz

On Tue, Mar 10, 2020 at 19:58:28 +0100, Patrick Steinhardt wrote:
> By default, GRUB will allocate a quarter of the pages it got available
> in the EFI subsystem. On many current systems, this will amount to
> roughly 800MB of RAM assuming an address space of 32 bits. This is
> plenty for most use cases, but it doesn't suffice when using full disk
> encryption with a key derival function based on Argon2.
> 
> Besides the usual iteration count known from PBKDF2, Argon2 introduces
> two additional parameters "memory" and "parallelism". While the latter
> doesn't really matter to us, the memory parameter is quite interesting.
> If encrypting a partition with LUKS2 using Argon2 as KDF, then
> cryptsetup will default to a memory parameter of 1GB. Meaning we need to
> allocate a buffer of 1GB in size in order to be able to derive the key,
> which definitely won't squeeze into the limit of 800MB.
> 
> To prepare for Argon2, this commit reworks the memory allocation
> algorithm for EFI platforms. Instead of trying to allocate a quarter of
> memory available, let's instead introduce a constant target amount of
> bytes that we try to allocate. The target is set to the previous value
> of MAX_HEAP_SIZE, which amounts to 1.6GB and thus sufficiently high to
> accomodate for both Argon2 as well as other functionality. The value is
> then clamped to at most half of available memory but at least 100MB.

Thanks for this, but it doesn't fully resolve my concerns.
Comments below.

> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  grub-core/kern/efi/mm.c | 21 +++++++++++----------
>  1 file changed, 11 insertions(+), 10 deletions(-)
> 
> diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
> index b02fab1b1..367a726c6 100644
> --- a/grub-core/kern/efi/mm.c
> +++ b/grub-core/kern/efi/mm.c
> @@ -39,8 +39,8 @@
>  #define MEMORY_MAP_SIZE	0x3000
>  
>  /* The minimum and maximum heap size for GRUB itself.  */
> -#define MIN_HEAP_SIZE	0x100000
> -#define MAX_HEAP_SIZE	(1600 * 0x100000)
> +#define MIN_HEAP_PAGES		BYTES_TO_PAGES(       0x100000)
> +#define TARGET_HEAP_PAGES	BYTES_TO_PAGES(1600 * 0x100000)
>  
>  static void *finish_mmap_buf = 0;
>  static grub_efi_uintn_t finish_mmap_size = 0;
> @@ -559,7 +559,7 @@ grub_efi_mm_init (void)
>    grub_efi_uintn_t map_size;
>    grub_efi_uintn_t desc_size;
>    grub_efi_uint64_t total_pages;
> -  grub_efi_uint64_t required_pages;
> +  grub_efi_uint64_t target_heap_pages;
>    int mm_status;
>  
>    /* Prepare a memory region to store two memory maps.  */
> @@ -599,14 +599,15 @@ grub_efi_mm_init (void)
>    filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
>  					       desc_size, memory_map_end);
>  
> -  /* By default, request a quarter of the available memory.  */
> +  /* By default, request TARGET_HEAP_PAGES pages. If that exceeds half of meory
> +   * available, clamp it, but request at least MIN_HEAP_PAGES. */
>    total_pages = get_total_pages (filtered_memory_map, desc_size,
>  				 filtered_memory_map_end);
> -  required_pages = (total_pages >> 2);
> -  if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
> -    required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
> -  else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))
> -    required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE);
> +  target_heap_pages = TARGET_HEAP_PAGES;
> +  if (target_heap_pages > (total_pages / 2))
> +    target_heap_pages = total_pages / 2;

If we can't get the amount we *need* for the new functionality, we
*still* go ahead and unconditionally reserve 50% of RAM?

I think a change this substantial, that is likely to break some
existing installations, needs to be conditionalised.

My idea was something along the lines of (pseudocode - coding style,
macro use and naming may or may not be suitable):

  target_heap_pages = MIN_HEAP_PAGES;
#ifdef GRUB_LUKS2_ARGON2_ENABLED
  target_heap_pages += GRUB_LUKS2_ARGON2_PAGES;
#endif

and then

  if (target_heap_pages > (total_pages >> 2)
    target_heap_pages = total_pages >> 2;

and then possibly

  if (target_heap_pages > MAX_HEAP_PAGES)
    target_heap_pages = MAX_HEAP_PAGES;


This for something simplistic with low risk, as we're so near release.

(Yes, this may mean we want to increase MIN_HEAP_PAGES, or add
some other intermediate #define as well.)

After 2.06 release I think I would like to look into the possibility
of something runtime-controllable, like having modules requesting
expansion of available heap space at load time.

Regards,

Leif

> +  if (target_heap_pages < MIN_HEAP_PAGES)
> +    target_heap_pages = MIN_HEAP_PAGES;
>  
>    /* Sort the filtered descriptors, so that GRUB can allocate pages
>       from smaller regions.  */
> @@ -614,7 +615,7 @@ grub_efi_mm_init (void)
>  
>    /* Allocate memory regions for GRUB's memory management.  */
>    add_memory_regions (filtered_memory_map, desc_size,
> -		      filtered_memory_map_end, required_pages);
> +		      filtered_memory_map_end, target_heap_pages);
>  
>  #if 0
>    /* For debug.  */
> -- 
> 2.25.1
> 


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-10 18:58 ` [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
  2020-03-10 20:44   ` Eli Schwartz
@ 2020-03-13 13:13   ` Daniel Kiper
  2020-03-16 17:21     ` Daniel Kiper
  2021-01-19  0:07   ` Petr Vorel
  2021-08-08 13:58   ` [PATCH v4 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
  3 siblings, 1 reply; 41+ messages in thread
From: Daniel Kiper @ 2020-03-13 13:13 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Leif Lindholm, agraf, pjones, mjg59, phcoder, Milan Broz

On Tue, Mar 10, 2020 at 07:58:30PM +0100, Patrick Steinhardt wrote:
> In order to support the Argon2 key derival function for LUKS2, we
> obviously need to implement Argon2. It doesn't make a lot of sense to
> hand-code any crypto, which is why this commit instead imports Argon2
> from the cryptsetup project. This commit thus imports the code from the
> official reference implementation located at [1]. The code is licensed
> under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
> 2.0 are compatible with GPLv3, it should be fine to import that code.
>
> The code is imported from commit 62358ba (Merge pull request #270 from
> bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
> several adjustments were required that have beed documented in
> "grub-dev.texi".
>
> [1]: https://github.com/P-H-C/phc-winner-argon2
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>

[...]

> diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
> new file mode 100644
> index 000000000..c77f7f6ff
> --- /dev/null
> +++ b/grub-core/lib/argon2/argon2.c
> @@ -0,0 +1,232 @@
> +/*
> + * Argon2 reference source code package - reference C implementations
> + *
> + * Copyright 2015
> + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> + *
> + * You may use this work under the terms of a Creative Commons CC0 1.0
> + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> + * these licenses can be found at:
> + *
> + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * You should have received a copy of both of these licenses along with this
> + * software. If not, they may be obtained at the above URLs.
> + */
> +
> +#include <grub/dl.h>
> +
> +#include "argon2.h"
> +#include "core.h"
> +
> +GRUB_MOD_LICENSE ("GPLv3");

I think we should change that if the license above is different.
Anyway, I am trying to get in touch with FSF license team. I have not
got a reply yet... I will see what is possible in my company...

Otherwise patch LGTM...

Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB
  2020-03-13 12:55   ` Leif Lindholm
@ 2020-03-13 13:59     ` Daniel Kiper
  2020-03-15 14:01       ` Patrick Steinhardt
  2020-03-15 10:14     ` Patrick Steinhardt
  2020-03-15 10:41     ` Patrick Steinhardt
  2 siblings, 1 reply; 41+ messages in thread
From: Daniel Kiper @ 2020-03-13 13:59 UTC (permalink / raw)
  To: Leif Lindholm
  Cc: Patrick Steinhardt, grub-devel, agraf, pjones, mjg59, phcoder,
	Milan Broz

On Fri, Mar 13, 2020 at 12:55:08PM +0000, Leif Lindholm wrote:
> On Tue, Mar 10, 2020 at 19:58:28 +0100, Patrick Steinhardt wrote:
> > By default, GRUB will allocate a quarter of the pages it got available
> > in the EFI subsystem. On many current systems, this will amount to
> > roughly 800MB of RAM assuming an address space of 32 bits. This is
> > plenty for most use cases, but it doesn't suffice when using full disk
> > encryption with a key derival function based on Argon2.
> >
> > Besides the usual iteration count known from PBKDF2, Argon2 introduces
> > two additional parameters "memory" and "parallelism". While the latter
> > doesn't really matter to us, the memory parameter is quite interesting.
> > If encrypting a partition with LUKS2 using Argon2 as KDF, then
> > cryptsetup will default to a memory parameter of 1GB. Meaning we need to
> > allocate a buffer of 1GB in size in order to be able to derive the key,
> > which definitely won't squeeze into the limit of 800MB.
> >
> > To prepare for Argon2, this commit reworks the memory allocation
> > algorithm for EFI platforms. Instead of trying to allocate a quarter of
> > memory available, let's instead introduce a constant target amount of
> > bytes that we try to allocate. The target is set to the previous value
> > of MAX_HEAP_SIZE, which amounts to 1.6GB and thus sufficiently high to
> > accomodate for both Argon2 as well as other functionality. The value is
> > then clamped to at most half of available memory but at least 100MB.
>
> Thanks for this, but it doesn't fully resolve my concerns.
> Comments below.
>
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > ---
> >  grub-core/kern/efi/mm.c | 21 +++++++++++----------
> >  1 file changed, 11 insertions(+), 10 deletions(-)
> >
> > diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
> > index b02fab1b1..367a726c6 100644
> > --- a/grub-core/kern/efi/mm.c
> > +++ b/grub-core/kern/efi/mm.c
> > @@ -39,8 +39,8 @@
> >  #define MEMORY_MAP_SIZE	0x3000
> >
> >  /* The minimum and maximum heap size for GRUB itself.  */
> > -#define MIN_HEAP_SIZE	0x100000
> > -#define MAX_HEAP_SIZE	(1600 * 0x100000)
> > +#define MIN_HEAP_PAGES		BYTES_TO_PAGES(       0x100000)
> > +#define TARGET_HEAP_PAGES	BYTES_TO_PAGES(1600 * 0x100000)
> >
> >  static void *finish_mmap_buf = 0;
> >  static grub_efi_uintn_t finish_mmap_size = 0;
> > @@ -559,7 +559,7 @@ grub_efi_mm_init (void)
> >    grub_efi_uintn_t map_size;
> >    grub_efi_uintn_t desc_size;
> >    grub_efi_uint64_t total_pages;
> > -  grub_efi_uint64_t required_pages;
> > +  grub_efi_uint64_t target_heap_pages;
> >    int mm_status;
> >
> >    /* Prepare a memory region to store two memory maps.  */
> > @@ -599,14 +599,15 @@ grub_efi_mm_init (void)
> >    filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
> >  					       desc_size, memory_map_end);
> >
> > -  /* By default, request a quarter of the available memory.  */
> > +  /* By default, request TARGET_HEAP_PAGES pages. If that exceeds half of meory
> > +   * available, clamp it, but request at least MIN_HEAP_PAGES. */
> >    total_pages = get_total_pages (filtered_memory_map, desc_size,
> >  				 filtered_memory_map_end);
> > -  required_pages = (total_pages >> 2);
> > -  if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
> > -    required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
> > -  else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))
> > -    required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE);
> > +  target_heap_pages = TARGET_HEAP_PAGES;
> > +  if (target_heap_pages > (total_pages / 2))
> > +    target_heap_pages = total_pages / 2;
>
> If we can't get the amount we *need* for the new functionality, we
> *still* go ahead and unconditionally reserve 50% of RAM?
>
> I think a change this substantial, that is likely to break some
> existing installations, needs to be conditionalised.
>
> My idea was something along the lines of (pseudocode - coding style,
> macro use and naming may or may not be suitable):
>
>   target_heap_pages = MIN_HEAP_PAGES;
> #ifdef GRUB_LUKS2_ARGON2_ENABLED
>   target_heap_pages += GRUB_LUKS2_ARGON2_PAGES;
> #endif
>
> and then
>
>   if (target_heap_pages > (total_pages >> 2)
>     target_heap_pages = total_pages >> 2;
>
> and then possibly
>
>   if (target_heap_pages > MAX_HEAP_PAGES)
>     target_heap_pages = MAX_HEAP_PAGES;
>
>
> This for something simplistic with low risk, as we're so near release.
>
> (Yes, this may mean we want to increase MIN_HEAP_PAGES, or add
> some other intermediate #define as well.)
>
> After 2.06 release I think I would like to look into the possibility
> of something runtime-controllable, like having modules requesting
> expansion of available heap space at load time.

Leif, thanks a lot for the input.

Patrick, please make Argon2 functionality enabled/disabled by the
./configure. By default it have to be disabled. Additionally, please add
to the grub-dev.texi an explanation what is the impact of enabling Argon2.

However, as Leif said, we can back to the discussion about "something
runtime-controllable, like having modules requesting expansion of
available heap space at load time" after the release.

Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB
  2020-03-13 12:55   ` Leif Lindholm
  2020-03-13 13:59     ` Daniel Kiper
@ 2020-03-15 10:14     ` Patrick Steinhardt
  2020-03-15 10:41     ` Patrick Steinhardt
  2 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-15 10:14 UTC (permalink / raw)
  To: Leif Lindholm
  Cc: grub-devel, Daniel Kiper, agraf, pjones, mjg59, phcoder, Milan Broz

[-- Attachment #1: Type: text/plain, Size: 5130 bytes --]

On Fri, Mar 13, 2020 at 12:55:08PM +0000, Leif Lindholm wrote:
> On Tue, Mar 10, 2020 at 19:58:28 +0100, Patrick Steinhardt wrote:
> > By default, GRUB will allocate a quarter of the pages it got available
> > in the EFI subsystem. On many current systems, this will amount to
> > roughly 800MB of RAM assuming an address space of 32 bits. This is
> > plenty for most use cases, but it doesn't suffice when using full disk
> > encryption with a key derival function based on Argon2.
> > 
> > Besides the usual iteration count known from PBKDF2, Argon2 introduces
> > two additional parameters "memory" and "parallelism". While the latter
> > doesn't really matter to us, the memory parameter is quite interesting.
> > If encrypting a partition with LUKS2 using Argon2 as KDF, then
> > cryptsetup will default to a memory parameter of 1GB. Meaning we need to
> > allocate a buffer of 1GB in size in order to be able to derive the key,
> > which definitely won't squeeze into the limit of 800MB.
> > 
> > To prepare for Argon2, this commit reworks the memory allocation
> > algorithm for EFI platforms. Instead of trying to allocate a quarter of
> > memory available, let's instead introduce a constant target amount of
> > bytes that we try to allocate. The target is set to the previous value
> > of MAX_HEAP_SIZE, which amounts to 1.6GB and thus sufficiently high to
> > accomodate for both Argon2 as well as other functionality. The value is
> > then clamped to at most half of available memory but at least 100MB.
> 
> Thanks for this, but it doesn't fully resolve my concerns.
> Comments below.
> 
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > ---
> >  grub-core/kern/efi/mm.c | 21 +++++++++++----------
> >  1 file changed, 11 insertions(+), 10 deletions(-)
> > 
> > diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
> > index b02fab1b1..367a726c6 100644
> > --- a/grub-core/kern/efi/mm.c
> > +++ b/grub-core/kern/efi/mm.c
> > @@ -39,8 +39,8 @@
> >  #define MEMORY_MAP_SIZE	0x3000
> >  
> >  /* The minimum and maximum heap size for GRUB itself.  */
> > -#define MIN_HEAP_SIZE	0x100000
> > -#define MAX_HEAP_SIZE	(1600 * 0x100000)
> > +#define MIN_HEAP_PAGES		BYTES_TO_PAGES(       0x100000)
> > +#define TARGET_HEAP_PAGES	BYTES_TO_PAGES(1600 * 0x100000)
> >  
> >  static void *finish_mmap_buf = 0;
> >  static grub_efi_uintn_t finish_mmap_size = 0;
> > @@ -559,7 +559,7 @@ grub_efi_mm_init (void)
> >    grub_efi_uintn_t map_size;
> >    grub_efi_uintn_t desc_size;
> >    grub_efi_uint64_t total_pages;
> > -  grub_efi_uint64_t required_pages;
> > +  grub_efi_uint64_t target_heap_pages;
> >    int mm_status;
> >  
> >    /* Prepare a memory region to store two memory maps.  */
> > @@ -599,14 +599,15 @@ grub_efi_mm_init (void)
> >    filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
> >  					       desc_size, memory_map_end);
> >  
> > -  /* By default, request a quarter of the available memory.  */
> > +  /* By default, request TARGET_HEAP_PAGES pages. If that exceeds half of meory
> > +   * available, clamp it, but request at least MIN_HEAP_PAGES. */
> >    total_pages = get_total_pages (filtered_memory_map, desc_size,
> >  				 filtered_memory_map_end);
> > -  required_pages = (total_pages >> 2);
> > -  if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
> > -    required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
> > -  else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))
> > -    required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE);
> > +  target_heap_pages = TARGET_HEAP_PAGES;
> > +  if (target_heap_pages > (total_pages / 2))
> > +    target_heap_pages = total_pages / 2;
> 
> If we can't get the amount we *need* for the new functionality, we
> *still* go ahead and unconditionally reserve 50% of RAM?
>
> I think a change this substantial, that is likely to break some
> existing installations, needs to be conditionalised.

Oops, yeah. I had the intention to revert this back to use
(total_pages >>2) but forgot.

> My idea was something along the lines of (pseudocode - coding style,
> macro use and naming may or may not be suitable):
> 
>   target_heap_pages = MIN_HEAP_PAGES;
> #ifdef GRUB_LUKS2_ARGON2_ENABLED
>   target_heap_pages += GRUB_LUKS2_ARGON2_PAGES;
> #endif
> 
> and then
> 
>   if (target_heap_pages > (total_pages >> 2)
>     target_heap_pages = total_pages >> 2;
> 
> and then possibly
> 
>   if (target_heap_pages > MAX_HEAP_PAGES)
>     target_heap_pages = MAX_HEAP_PAGES;
> 
> This for something simplistic with low risk, as we're so near release.

Ah, yeah, that makes a lot of sense to me. Thanks for pointing out!

> 
> (Yes, this may mean we want to increase MIN_HEAP_PAGES, or add
> some other intermediate #define as well.)
> 
> After 2.06 release I think I would like to look into the possibility
> of something runtime-controllable, like having modules requesting
> expansion of available heap space at load time.

That sounds like a worthwhile goal to me, agreed.

Thanks for your input!

Patrick

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB
  2020-03-13 12:55   ` Leif Lindholm
  2020-03-13 13:59     ` Daniel Kiper
  2020-03-15 10:14     ` Patrick Steinhardt
@ 2020-03-15 10:41     ` Patrick Steinhardt
  2 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-15 10:41 UTC (permalink / raw)
  To: Leif Lindholm
  Cc: grub-devel, Daniel Kiper, agraf, pjones, mjg59, phcoder, Milan Broz

[-- Attachment #1: Type: text/plain, Size: 2009 bytes --]

On Fri, Mar 13, 2020 at 12:55:08PM +0000, Leif Lindholm wrote:
> My idea was something along the lines of (pseudocode - coding style,
> macro use and naming may or may not be suitable):
> 
>   target_heap_pages = MIN_HEAP_PAGES;
> #ifdef GRUB_LUKS2_ARGON2_ENABLED
>   target_heap_pages += GRUB_LUKS2_ARGON2_PAGES;
> #endif
> 
> and then
> 
>   if (target_heap_pages > (total_pages >> 2)
>     target_heap_pages = total_pages >> 2;
> 
> and then possibly
> 
>   if (target_heap_pages > MAX_HEAP_PAGES)
>     target_heap_pages = MAX_HEAP_PAGES;

What do you think about the following algorithm:

  /* Aim to satisfy requirements posed by both GRUB and other modules.  */
  target_pages = MIN_HEAP_PAGES;
#ifdef GRUB_LUKS2_ARGON2_ENABLED
  target_pages += GRUB_LUKS2_ARGON2_PAGES;
#endif

  total_pages = get_total_pages (filtered_memory_map, desc_size,
				 filtered_memory_map_end);

  /* By default, request a quarter of the available memory.  */
  required_pages = (total_pages >> 2);
  /* But try to satisfy requirements set forth by modules.  */
  required_pages = grub_max (required_pages, target_pages);
  /* And clamp to MIN_HEAP_PAGES <= required_pages <= MAX_HEAP_PAGES.  */
  required_pages = grub_max (required_pages, MIN_HEAP_PAGES);
  required_pages = grub_min (required_pages, MAX_HEAP_PAGES);

In the general case where GRUB_LUKS2_ARGON2_ENABLED is not set, it will
behave exactly the same as before: we request a quarter of available
pages and clamp to MIN_HEAP_PAGES <= required_pages <= MAX_HEAP_PAGES.
If GRUB_LUKS2_ARGON2_ENABLED is set, it will also behave that way,
except for the case where `required_pages < target_pages`, where we just
set `required_pages = target_pages`. As we're still doing the clamping,
we will end up with at most MAX_HEAP_PAGES (1.6GB), which should be
sufficient.

I think this is the least invasive way this can be implemented with
minimal risk: in the general case it is exactly the same as before.

Patrick

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB
  2020-03-13 13:59     ` Daniel Kiper
@ 2020-03-15 14:01       ` Patrick Steinhardt
  0 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-15 14:01 UTC (permalink / raw)
  To: Daniel Kiper
  Cc: Leif Lindholm, grub-devel, agraf, pjones, mjg59, phcoder, Milan Broz

[-- Attachment #1: Type: text/plain, Size: 1959 bytes --]

On Fri, Mar 13, 2020 at 02:59:46PM +0100, Daniel Kiper wrote:
> Patrick, please make Argon2 functionality enabled/disabled by the
> ./configure. By default it have to be disabled. Additionally, please add
> to the grub-dev.texi an explanation what is the impact of enabling Argon2.

Is there any obvious way to conditionally build modules and libs into
the kernel based on a feature flag? The only way I see it to be doable
is by re-using groups as known by gentpl.py, so that I may do the
following:

# Makefile.util.def

    library = {
      name = libgrubkern.a;
      cflags = '$(CFLAGS_GNULIB)';
      cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/grub-core/lib/json';
      argon2_cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/grub-core/lib/json -I$(srcdir)/grub-core/lib/argon2';

      common = util/misc.c;
      common = grub-core/kern/command.c;
      common = grub-core/kern/device.c;
      ...

      argon2 = grub-core/lib/argon2/argon2.c;
      argon2 = grub-core/lib/argon2/core.c;
      argon2 = grub-core/lib/argon2/ref.c;
      argon2 = grub-core/lib/argon2/blake2/blake2b.c;
    };

# grub-core/Makefile.core.def

    module = {
      name = argon2;
      common = lib/argon2/argon2.c;
      common = lib/argon2/core.c;
      common = lib/argon2/ref.c;
      common = lib/argon2/blake2/blake2b.c;
      enable = argon2;
    };

    module = {
      name = luks2;
      common = disk/luks2.c;
      common = lib/gnulib/base64.c;
      cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
      cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json';
      argon2_cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json -I$(srcdir)/lib/argon2';
    };

I don't think that gentpl.py is currently able to act based on configure
options, but only decides by build platforms. Please let me know I'm
missing the bigger picture here, and if there's any module that already
does that kind of stuff that'd be a great help.

Patrick

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-13 13:13   ` Daniel Kiper
@ 2020-03-16 17:21     ` Daniel Kiper
  2020-03-16 17:52       ` Patrick Steinhardt
  2020-03-16 19:57       ` Konrad Rzeszutek Wilk
  0 siblings, 2 replies; 41+ messages in thread
From: Daniel Kiper @ 2020-03-16 17:21 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Leif Lindholm, agraf, pjones, mjg59, phcoder, Milan Broz

On Fri, Mar 13, 2020 at 02:13:49PM +0100, Daniel Kiper wrote:
> On Tue, Mar 10, 2020 at 07:58:30PM +0100, Patrick Steinhardt wrote:
> > In order to support the Argon2 key derival function for LUKS2, we
> > obviously need to implement Argon2. It doesn't make a lot of sense to
> > hand-code any crypto, which is why this commit instead imports Argon2
> > from the cryptsetup project. This commit thus imports the code from the
> > official reference implementation located at [1]. The code is licensed
> > under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
> > 2.0 are compatible with GPLv3, it should be fine to import that code.
> >
> > The code is imported from commit 62358ba (Merge pull request #270 from
> > bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
> > several adjustments were required that have beed documented in
> > "grub-dev.texi".
> >
> > [1]: https://github.com/P-H-C/phc-winner-argon2
> >
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
>
> [...]
>
> > diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
> > new file mode 100644
> > index 000000000..c77f7f6ff
> > --- /dev/null
> > +++ b/grub-core/lib/argon2/argon2.c
> > @@ -0,0 +1,232 @@
> > +/*
> > + * Argon2 reference source code package - reference C implementations
> > + *
> > + * Copyright 2015
> > + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> > + *
> > + * You may use this work under the terms of a Creative Commons CC0 1.0
> > + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> > + * these licenses can be found at:
> > + *
> > + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> > + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * You should have received a copy of both of these licenses along with this
> > + * software. If not, they may be obtained at the above URLs.
> > + */
> > +
> > +#include <grub/dl.h>
> > +
> > +#include "argon2.h"
> > +#include "core.h"
> > +
> > +GRUB_MOD_LICENSE ("GPLv3");
>
> I think we should change that if the license above is different.
> Anyway, I am trying to get in touch with FSF license team. I have not
> got a reply yet... I will see what is possible in my company...

Got an unofficial reply that we cannot remove current license from the
Argon2 reference source code package. However, we can add GPLv3 header
after current license header. Hence, I would suggest heading in that
direction. Still waiting for final confirmation. Sadly usual turn around
is about two weeks...

Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-16 17:21     ` Daniel Kiper
@ 2020-03-16 17:52       ` Patrick Steinhardt
  2020-03-16 20:03         ` Daniel Kiper
  2020-03-16 19:57       ` Konrad Rzeszutek Wilk
  1 sibling, 1 reply; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-16 17:52 UTC (permalink / raw)
  To: Daniel Kiper
  Cc: grub-devel, Leif Lindholm, agraf, pjones, mjg59, phcoder, Milan Broz

[-- Attachment #1: Type: text/plain, Size: 3377 bytes --]

On Mon, Mar 16, 2020 at 06:21:06PM +0100, Daniel Kiper wrote:
> On Fri, Mar 13, 2020 at 02:13:49PM +0100, Daniel Kiper wrote:
> > On Tue, Mar 10, 2020 at 07:58:30PM +0100, Patrick Steinhardt wrote:
> > > In order to support the Argon2 key derival function for LUKS2, we
> > > obviously need to implement Argon2. It doesn't make a lot of sense to
> > > hand-code any crypto, which is why this commit instead imports Argon2
> > > from the cryptsetup project. This commit thus imports the code from the
> > > official reference implementation located at [1]. The code is licensed
> > > under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
> > > 2.0 are compatible with GPLv3, it should be fine to import that code.
> > >
> > > The code is imported from commit 62358ba (Merge pull request #270 from
> > > bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
> > > several adjustments were required that have beed documented in
> > > "grub-dev.texi".
> > >
> > > [1]: https://github.com/P-H-C/phc-winner-argon2
> > >
> > > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> >
> > [...]
> >
> > > diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
> > > new file mode 100644
> > > index 000000000..c77f7f6ff
> > > --- /dev/null
> > > +++ b/grub-core/lib/argon2/argon2.c
> > > @@ -0,0 +1,232 @@
> > > +/*
> > > + * Argon2 reference source code package - reference C implementations
> > > + *
> > > + * Copyright 2015
> > > + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> > > + *
> > > + * You may use this work under the terms of a Creative Commons CC0 1.0
> > > + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> > > + * these licenses can be found at:
> > > + *
> > > + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> > > + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> > > + *
> > > + * You should have received a copy of both of these licenses along with this
> > > + * software. If not, they may be obtained at the above URLs.
> > > + */
> > > +
> > > +#include <grub/dl.h>
> > > +
> > > +#include "argon2.h"
> > > +#include "core.h"
> > > +
> > > +GRUB_MOD_LICENSE ("GPLv3");
> >
> > I think we should change that if the license above is different.
> > Anyway, I am trying to get in touch with FSF license team. I have not
> > got a reply yet... I will see what is possible in my company...
> 
> Got an unofficial reply that we cannot remove current license from the
> Argon2 reference source code package. However, we can add GPLv3 header
> after current license header. Hence, I would suggest heading in that
> direction. Still waiting for final confirmation.

Thanks for handling this issue. So if I got that right, we can keep
their header intact, add an additional header for GPLv3 and then we're
fine with using `GRUB_MOD_LICENSE ("GPLv3")`? If so, then I'm happy to
do that.

> Sadly usual turn around is about two weeks...

While I could still try to squeeze into v2.04, I think the most sensible
way forward would be to defer Argon2 support to v2.06. There's still
some open questions, and I'm not sure I feel comfortable with hitting
master so close to the pending release. Let me know if you feel
otherwise.

Patrick

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-16 17:21     ` Daniel Kiper
  2020-03-16 17:52       ` Patrick Steinhardt
@ 2020-03-16 19:57       ` Konrad Rzeszutek Wilk
  2020-03-18 11:52         ` Patrick Steinhardt
  1 sibling, 1 reply; 41+ messages in thread
From: Konrad Rzeszutek Wilk @ 2020-03-16 19:57 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Patrick Steinhardt, Leif Lindholm, agraf, pjones, mjg59, phcoder,
	Milan Broz

On Mon, Mar 16, 2020 at 06:21:06PM +0100, Daniel Kiper wrote:
> On Fri, Mar 13, 2020 at 02:13:49PM +0100, Daniel Kiper wrote:
> > On Tue, Mar 10, 2020 at 07:58:30PM +0100, Patrick Steinhardt wrote:
> > > In order to support the Argon2 key derival function for LUKS2, we
> > > obviously need to implement Argon2. It doesn't make a lot of sense to
> > > hand-code any crypto, which is why this commit instead imports Argon2
> > > from the cryptsetup project. This commit thus imports the code from the
> > > official reference implementation located at [1]. The code is licensed
> > > under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
> > > 2.0 are compatible with GPLv3, it should be fine to import that code.
> > >
> > > The code is imported from commit 62358ba (Merge pull request #270 from
> > > bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
> > > several adjustments were required that have beed documented in
> > > "grub-dev.texi".
> > >
> > > [1]: https://github.com/P-H-C/phc-winner-argon2
> > >
> > > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> >
> > [...]
> >
> > > diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
> > > new file mode 100644
> > > index 000000000..c77f7f6ff
> > > --- /dev/null
> > > +++ b/grub-core/lib/argon2/argon2.c
> > > @@ -0,0 +1,232 @@
> > > +/*
> > > + * Argon2 reference source code package - reference C implementations
> > > + *
> > > + * Copyright 2015
> > > + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> > > + *
> > > + * You may use this work under the terms of a Creative Commons CC0 1.0
> > > + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> > > + * these licenses can be found at:
> > > + *
> > > + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> > > + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> > > + *
> > > + * You should have received a copy of both of these licenses along with this
> > > + * software. If not, they may be obtained at the above URLs.
> > > + */
> > > +
> > > +#include <grub/dl.h>
> > > +
> > > +#include "argon2.h"
> > > +#include "core.h"
> > > +
> > > +GRUB_MOD_LICENSE ("GPLv3");
> >
> > I think we should change that if the license above is different.
> > Anyway, I am trying to get in touch with FSF license team. I have not
> > got a reply yet... I will see what is possible in my company...
> 
> Got an unofficial reply that we cannot remove current license from the
> Argon2 reference source code package. However, we can add GPLv3 header
> after current license header. Hence, I would suggest heading in that
> direction. Still waiting for final confirmation. Sadly usual turn around
> is about two weeks...

Sorry for asking this so late- but has anybody tried contacting the authors
(Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves) and
asking if they would be willing to post their code under GPL-v3?


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-16 17:52       ` Patrick Steinhardt
@ 2020-03-16 20:03         ` Daniel Kiper
  2020-03-17  5:51           ` Patrick Steinhardt
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Kiper @ 2020-03-16 20:03 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Leif Lindholm, agraf, pjones, mjg59, phcoder, Milan Broz

On Mon, Mar 16, 2020 at 06:52:30PM +0100, Patrick Steinhardt wrote:
> On Mon, Mar 16, 2020 at 06:21:06PM +0100, Daniel Kiper wrote:
> > On Fri, Mar 13, 2020 at 02:13:49PM +0100, Daniel Kiper wrote:
> > > On Tue, Mar 10, 2020 at 07:58:30PM +0100, Patrick Steinhardt wrote:
> > > > In order to support the Argon2 key derival function for LUKS2, we
> > > > obviously need to implement Argon2. It doesn't make a lot of sense to
> > > > hand-code any crypto, which is why this commit instead imports Argon2
> > > > from the cryptsetup project. This commit thus imports the code from the
> > > > official reference implementation located at [1]. The code is licensed
> > > > under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
> > > > 2.0 are compatible with GPLv3, it should be fine to import that code.
> > > >
> > > > The code is imported from commit 62358ba (Merge pull request #270 from
> > > > bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
> > > > several adjustments were required that have beed documented in
> > > > "grub-dev.texi".
> > > >
> > > > [1]: https://github.com/P-H-C/phc-winner-argon2
> > > >
> > > > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > >
> > > [...]
> > >
> > > > diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
> > > > new file mode 100644
> > > > index 000000000..c77f7f6ff
> > > > --- /dev/null
> > > > +++ b/grub-core/lib/argon2/argon2.c
> > > > @@ -0,0 +1,232 @@
> > > > +/*
> > > > + * Argon2 reference source code package - reference C implementations
> > > > + *
> > > > + * Copyright 2015
> > > > + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> > > > + *
> > > > + * You may use this work under the terms of a Creative Commons CC0 1.0
> > > > + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> > > > + * these licenses can be found at:
> > > > + *
> > > > + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> > > > + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> > > > + *
> > > > + * You should have received a copy of both of these licenses along with this
> > > > + * software. If not, they may be obtained at the above URLs.
> > > > + */
> > > > +
> > > > +#include <grub/dl.h>
> > > > +
> > > > +#include "argon2.h"
> > > > +#include "core.h"
> > > > +
> > > > +GRUB_MOD_LICENSE ("GPLv3");
> > >
> > > I think we should change that if the license above is different.
> > > Anyway, I am trying to get in touch with FSF license team. I have not
> > > got a reply yet... I will see what is possible in my company...
> >
> > Got an unofficial reply that we cannot remove current license from the
> > Argon2 reference source code package. However, we can add GPLv3 header
> > after current license header. Hence, I would suggest heading in that
> > direction. Still waiting for final confirmation.
>
> Thanks for handling this issue. So if I got that right, we can keep
> their header intact, add an additional header for GPLv3 and then we're
> fine with using `GRUB_MOD_LICENSE ("GPLv3")`? If so, then I'm happy to
> do that.

This is my understating too. Though I will be sure when I get a reply
from lawyers...

> > Sadly usual turn around is about two weeks...
>
> While I could still try to squeeze into v2.04, I think the most sensible

s/v2.04/v2.06/?

> way forward would be to defer Argon2 support to v2.06. There's still

s/v2.06/v2.08/?

> some open questions, and I'm not sure I feel comfortable with hitting
> master so close to the pending release. Let me know if you feel
> otherwise.

I have the same feeling. So, if it is not very critical for you to have
this in 2.06 I would suggest to deffer development until the release.
In the mean time I think we will be able to hammer out solutions for
your open questions.

Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-16 20:03         ` Daniel Kiper
@ 2020-03-17  5:51           ` Patrick Steinhardt
  2020-03-17 10:45             ` Leif Lindholm
  0 siblings, 1 reply; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-17  5:51 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Leif Lindholm, agraf, pjones, mjg59, phcoder, Milan Broz

[-- Attachment #1: Type: text/plain, Size: 1203 bytes --]

On Mon, Mar 16, 2020 at 09:03:24PM +0100, Daniel Kiper wrote:
> On Mon, Mar 16, 2020 at 06:52:30PM +0100, Patrick Steinhardt wrote:
> > On Mon, Mar 16, 2020 at 06:21:06PM +0100, Daniel Kiper wrote:
> This is my understating too. Though I will be sure when I get a reply
> from lawyers...
> 
> > > Sadly usual turn around is about two weeks...
> >
> > While I could still try to squeeze into v2.04, I think the most sensible
> 
> s/v2.04/v2.06/?
> 
> > way forward would be to defer Argon2 support to v2.06. There's still
> 
> s/v2.06/v2.08/?

Oops, yes, of course.

> > some open questions, and I'm not sure I feel comfortable with hitting
> > master so close to the pending release. Let me know if you feel
> > otherwise.
> 
> I have the same feeling. So, if it is not very critical for you to have
> this in 2.06 I would suggest to deffer development until the release.
> In the mean time I think we will be able to hammer out solutions for
> your open questions.

Not at all. I'm happy with LUKS2 support in the first place, and
initially one may just use a PBKDF2 keyslot. It's trivial enough to
migrate to Argon2 at a later point anyway. So let's defer it!

Patrick

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-17  5:51           ` Patrick Steinhardt
@ 2020-03-17 10:45             ` Leif Lindholm
  0 siblings, 0 replies; 41+ messages in thread
From: Leif Lindholm @ 2020-03-17 10:45 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: The development of GNU GRUB, agraf, pjones, mjg59, phcoder, Milan Broz

On Tue, Mar 17, 2020 at 06:51:54 +0100, Patrick Steinhardt wrote:
> > > some open questions, and I'm not sure I feel comfortable with hitting
> > > master so close to the pending release. Let me know if you feel
> > > otherwise.
> > 
> > I have the same feeling. So, if it is not very critical for you to have
> > this in 2.06 I would suggest to deffer development until the release.
> > In the mean time I think we will be able to hammer out solutions for
> > your open questions.
> 
> Not at all. I'm happy with LUKS2 support in the first place, and
> initially one may just use a PBKDF2 keyslot. It's trivial enough to
> migrate to Argon2 at a later point anyway. So let's defer it!

Yes, it would be nice if we could resolve the heap size issue in a
permanent way for initial inclusion.

/
    Leif


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-16 19:57       ` Konrad Rzeszutek Wilk
@ 2020-03-18 11:52         ` Patrick Steinhardt
  0 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2020-03-18 11:52 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk
  Cc: The development of GNU GRUB, Leif Lindholm, agraf, pjones, mjg59,
	phcoder, Milan Broz

[-- Attachment #1: Type: text/plain, Size: 3411 bytes --]

On Mon, Mar 16, 2020 at 03:57:02PM -0400, Konrad Rzeszutek Wilk wrote:
> On Mon, Mar 16, 2020 at 06:21:06PM +0100, Daniel Kiper wrote:
> > On Fri, Mar 13, 2020 at 02:13:49PM +0100, Daniel Kiper wrote:
> > > On Tue, Mar 10, 2020 at 07:58:30PM +0100, Patrick Steinhardt wrote:
> > > > In order to support the Argon2 key derival function for LUKS2, we
> > > > obviously need to implement Argon2. It doesn't make a lot of sense to
> > > > hand-code any crypto, which is why this commit instead imports Argon2
> > > > from the cryptsetup project. This commit thus imports the code from the
> > > > official reference implementation located at [1]. The code is licensed
> > > > under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
> > > > 2.0 are compatible with GPLv3, it should be fine to import that code.
> > > >
> > > > The code is imported from commit 62358ba (Merge pull request #270 from
> > > > bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
> > > > several adjustments were required that have beed documented in
> > > > "grub-dev.texi".
> > > >
> > > > [1]: https://github.com/P-H-C/phc-winner-argon2
> > > >
> > > > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > >
> > > [...]
> > >
> > > > diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
> > > > new file mode 100644
> > > > index 000000000..c77f7f6ff
> > > > --- /dev/null
> > > > +++ b/grub-core/lib/argon2/argon2.c
> > > > @@ -0,0 +1,232 @@
> > > > +/*
> > > > + * Argon2 reference source code package - reference C implementations
> > > > + *
> > > > + * Copyright 2015
> > > > + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
> > > > + *
> > > > + * You may use this work under the terms of a Creative Commons CC0 1.0
> > > > + * License/Waiver or the Apache Public License 2.0, at your option. The terms of
> > > > + * these licenses can be found at:
> > > > + *
> > > > + * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
> > > > + * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
> > > > + *
> > > > + * You should have received a copy of both of these licenses along with this
> > > > + * software. If not, they may be obtained at the above URLs.
> > > > + */
> > > > +
> > > > +#include <grub/dl.h>
> > > > +
> > > > +#include "argon2.h"
> > > > +#include "core.h"
> > > > +
> > > > +GRUB_MOD_LICENSE ("GPLv3");
> > >
> > > I think we should change that if the license above is different.
> > > Anyway, I am trying to get in touch with FSF license team. I have not
> > > got a reply yet... I will see what is possible in my company...
> > 
> > Got an unofficial reply that we cannot remove current license from the
> > Argon2 reference source code package. However, we can add GPLv3 header
> > after current license header. Hence, I would suggest heading in that
> > direction. Still waiting for final confirmation. Sadly usual turn around
> > is about two weeks...
> 
> Sorry for asking this so late- but has anybody tried contacting the authors
> (Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves) and
> asking if they would be willing to post their code under GPL-v3?

Honestly I didn't even consider this, but you've certainly got a point.
I will try and reach out to them later this week.

Patrick

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 0/5] Support Argon2 KDF in LUKS2
  2020-03-10 18:58 [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
                   ` (4 preceding siblings ...)
  2020-03-10 18:58 ` [PATCH v3 5/5] luks2: Support key derival via Argon2 Patrick Steinhardt
@ 2020-03-25 17:12 ` Daniel Kiper
  5 siblings, 0 replies; 41+ messages in thread
From: Daniel Kiper @ 2020-03-25 17:12 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Leif Lindholm, agraf, pjones, mjg59, phcoder, Milan Broz

Hi Patrick,

On Tue, Mar 10, 2020 at 07:58:27PM +0100, Patrick Steinhardt wrote:
> Hi,
>
> this is the third version of my patchset to support the Argon2 KDF in
> LUKS2. The following things have changed in comparison to v2:
>
>     - Improved the GRUB_UINT_C macros to not use `elif 1` and fixed
>       indentation.
>
>     - Dropped the upstreamed patch to fix a missing newline.
>
>     - Reworked how we allocate memory on EFI. Previously, we always
>       targeted to acquire 1/4 of available memory. Now we're always
>       trying to allocate MAX_HEAP_SIZE (1.6GB) but clamp it to at most
>       1/2 of available memory and at least MIN_HEAP_SIZE (100MB).
>
> So especially the last part is the interesting one. I _think_ that it's
> roughly what Leif had in mind, but please do correct me if I'm wrong.

So, according to our earlier discussion I am not treating this patchset
as a release material. However, I would like to merge fixed version of
it after the release. In the meantime I am investigating the legal matter
related to this patchset.

Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2020-03-10 18:58 ` [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
  2020-03-10 20:44   ` Eli Schwartz
  2020-03-13 13:13   ` Daniel Kiper
@ 2021-01-19  0:07   ` Petr Vorel
  2021-01-19 11:10     ` Dmitry
  2021-08-08 13:58   ` [PATCH v4 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
  3 siblings, 1 reply; 41+ messages in thread
From: Petr Vorel @ 2021-01-19  0:07 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: grub-devel

Hi Patrick,

I know that this patchset needs some changes and is not planned to be included
in 2.06. But anyway, testing it I found:

...
> +++ b/grub-core/lib/argon2/core.c
> +/* for explicit_bzero() on glibc */
> +#define _DEFAULT_SOURCE
...
> +#if defined(__OpenBSD__)
> +#define HAVE_EXPLICIT_BZERO 1
> +#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
> +#if __GLIBC_PREREQ(2,25)
> +#define HAVE_EXPLICIT_BZERO 1
> +#endif
Does this work? I get:

    grub-core/lib/argon2/core.c: In function ‘secure_wipe_memory’:
    grub-core/lib/argon2/core.c:135:5: error: implicit declaration of function ‘explicit_bzero’ [-Werror=implicit-function-declaration]
      135 |     explicit_bzero(v, n);

Including <string.h> isn't obviously a good idea.
What's wrong? I have to miss something obvious.

> +#endif

If I remove HAVE_EXPLICIT_BZERO definition, I get errors when generating
moddep.lst:

make[3]: Entering directory '/home/pevik/install/src/grub.git/grub-core'
cat syminfo.lst | sort | gawk -f ./genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1)
__moddi3 in argon2 is not defined
__umoddi3 in argon2 is not defined

My config-util.h does not have HAVE___MODDI3 and HAVE___UMODDI3.
What's wrong?

I'm compiling on recent distro.
Thanks for any hint.

Kind regards,
Petr


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2021-01-19  0:07   ` Petr Vorel
@ 2021-01-19 11:10     ` Dmitry
  2021-01-19 13:06       ` Petr Vorel
  0 siblings, 1 reply; 41+ messages in thread
From: Dmitry @ 2021-01-19 11:10 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Patrick Steinhardt, petr.vorel

Please try to build only for the "efi-64" platform. (not "pc")

Dmitry

вт, 19 янв. 2021 г. в 03:08, Petr Vorel <petr.vorel@gmail.com>:
>
> Hi Patrick,
>
> I know that this patchset needs some changes and is not planned to be included
> in 2.06. But anyway, testing it I found:
>
> ...
> > +++ b/grub-core/lib/argon2/core.c
> > +/* for explicit_bzero() on glibc */
> > +#define _DEFAULT_SOURCE
> ...
> > +#if defined(__OpenBSD__)
> > +#define HAVE_EXPLICIT_BZERO 1
> > +#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
> > +#if __GLIBC_PREREQ(2,25)
> > +#define HAVE_EXPLICIT_BZERO 1
> > +#endif
> Does this work? I get:
>
>     grub-core/lib/argon2/core.c: In function ‘secure_wipe_memory’:
>     grub-core/lib/argon2/core.c:135:5: error: implicit declaration of function ‘explicit_bzero’ [-Werror=implicit-function-declaration]
>       135 |     explicit_bzero(v, n);
>
> Including <string.h> isn't obviously a good idea.
> What's wrong? I have to miss something obvious.
>
> > +#endif
>
> If I remove HAVE_EXPLICIT_BZERO definition, I get errors when generating
> moddep.lst:
>
> make[3]: Entering directory '/home/pevik/install/src/grub.git/grub-core'
> cat syminfo.lst | sort | gawk -f ./genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1)
> __moddi3 in argon2 is not defined
> __umoddi3 in argon2 is not defined
>
> My config-util.h does not have HAVE___MODDI3 and HAVE___UMODDI3.
> What's wrong?
>
> I'm compiling on recent distro.
> Thanks for any hint.
>
> Kind regards,
> Petr
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2021-01-19 11:10     ` Dmitry
@ 2021-01-19 13:06       ` Petr Vorel
  2021-01-19 15:42         ` Matt Turner
  2021-01-19 19:03         ` Patrick Steinhardt
  0 siblings, 2 replies; 41+ messages in thread
From: Petr Vorel @ 2021-01-19 13:06 UTC (permalink / raw)
  To: Dmitry; +Cc: The development of GNU GRUB, Patrick Steinhardt, Daniel Kiper

Hi,

> Please try to build only for the "efi-64" platform. (not "pc")
right, I'll test it, but we need to support also legacy bios.

BTW as Argon2 is the default PBKDF algorithm in current cryptsetup, Debian
installer (and probably other distros' installers) uses it and it has to be
converted after installation with Live CD / connecting HDD on different machine.

Therefore postponing Argon2 to another release means users will have it in 2+
years after 2.06 release (unless distros backport it).

Kind regards,
Petr

> Dmitry

> вт, 19 янв. 2021 г. в 03:08, Petr Vorel <petr.vorel@gmail.com>:

> > Hi Patrick,

> > I know that this patchset needs some changes and is not planned to be included
> > in 2.06. But anyway, testing it I found:

> > ...
> > > +++ b/grub-core/lib/argon2/core.c
> > > +/* for explicit_bzero() on glibc */
> > > +#define _DEFAULT_SOURCE
> > ...
> > > +#if defined(__OpenBSD__)
> > > +#define HAVE_EXPLICIT_BZERO 1
> > > +#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
> > > +#if __GLIBC_PREREQ(2,25)
> > > +#define HAVE_EXPLICIT_BZERO 1
> > > +#endif
> > Does this work? I get:

> >     grub-core/lib/argon2/core.c: In function ‘secure_wipe_memory’:
> >     grub-core/lib/argon2/core.c:135:5: error: implicit declaration of function ‘explicit_bzero’ [-Werror=implicit-function-declaration]
> >       135 |     explicit_bzero(v, n);

> > Including <string.h> isn't obviously a good idea.
> > What's wrong? I have to miss something obvious.

> > > +#endif

> > If I remove HAVE_EXPLICIT_BZERO definition, I get errors when generating
> > moddep.lst:

> > make[3]: Entering directory '/home/pevik/install/src/grub.git/grub-core'
> > cat syminfo.lst | sort | gawk -f ./genmoddep.awk > moddep.lst || (rm -f moddep.lst; exit 1)
> > __moddi3 in argon2 is not defined
> > __umoddi3 in argon2 is not defined

> > My config-util.h does not have HAVE___MODDI3 and HAVE___UMODDI3.
> > What's wrong?

> > I'm compiling on recent distro.
> > Thanks for any hint.

> > Kind regards,
> > Petr


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2021-01-19 13:06       ` Petr Vorel
@ 2021-01-19 15:42         ` Matt Turner
  2021-01-19 19:03         ` Patrick Steinhardt
  1 sibling, 0 replies; 41+ messages in thread
From: Matt Turner @ 2021-01-19 15:42 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Dmitry, Patrick Steinhardt, Daniel Kiper

On Tue, Jan 19, 2021 at 8:12 AM Petr Vorel <petr.vorel@gmail.com> wrote:
> Therefore postponing Argon2 to another release means users will have it in 2+
> years after 2.06 release (unless distros backport it).

Maybe we can have more frequent releases? Every two years is a pretty
artificial limitation.


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2021-01-19 13:06       ` Petr Vorel
  2021-01-19 15:42         ` Matt Turner
@ 2021-01-19 19:03         ` Patrick Steinhardt
  2021-01-19 19:31           ` Petr Vorel
  1 sibling, 1 reply; 41+ messages in thread
From: Patrick Steinhardt @ 2021-01-19 19:03 UTC (permalink / raw)
  To: Petr Vorel; +Cc: Dmitry, The development of GNU GRUB, Daniel Kiper

[-- Attachment #1: Type: text/plain, Size: 1195 bytes --]

On Tue, Jan 19, 2021 at 02:06:15PM +0100, Petr Vorel wrote:
> Hi,
> 
> > Please try to build only for the "efi-64" platform. (not "pc")
> right, I'll test it, but we need to support also legacy bios.

I wasn't aware it wouldn't build on the "pc" platform, but I never even
tried in the first place. The patch series definitely needs more
polishing anyway, but thanks for making me aware.

> BTW as Argon2 is the default PBKDF algorithm in current cryptsetup, Debian
> installer (and probably other distros' installers) uses it and it has to be
> converted after installation with Live CD / connecting HDD on different machine.
> 
> Therefore postponing Argon2 to another release means users will have it in 2+
> years after 2.06 release (unless distros backport it).

That cannot be helped, unfortunately. The current release has been
taking far too long already, and delaying it even further will
completely bar anybody from using LUKS2 with GRUB in the first place.

I don't really know about the release cycle, but personally I wouldn't
mind to accelerate it. That's only my two cents though as somebody who
hasn't been involved in the project that deeply.

Patrick

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2021-01-19 19:03         ` Patrick Steinhardt
@ 2021-01-19 19:31           ` Petr Vorel
  2021-01-21 14:49             ` IS: GRUB release cycle: WAS: " Daniel Kiper
  0 siblings, 1 reply; 41+ messages in thread
From: Petr Vorel @ 2021-01-19 19:31 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: Dmitry, The development of GNU GRUB, Daniel Kiper

Hi Patrick,

> On Tue, Jan 19, 2021 at 02:06:15PM +0100, Petr Vorel wrote:
> > Hi,

> > > Please try to build only for the "efi-64" platform. (not "pc")
> > right, I'll test it, but we need to support also legacy bios.

> I wasn't aware it wouldn't build on the "pc" platform, but I never even
> tried in the first place. The patch series definitely needs more
> polishing anyway, but thanks for making me aware.
Thanks!
One more note: "Argon2 not supported" is not shown, instead there is 
"Invalid encryption" printed later in luks2_recover_key().
It was trivial to modify sources to find it, but that will not be user friendly
for users which will run grub2 from distro package.

> > BTW as Argon2 is the default PBKDF algorithm in current cryptsetup, Debian
> > installer (and probably other distros' installers) uses it and it has to be
> > converted after installation with Live CD / connecting HDD on different machine.

> > Therefore postponing Argon2 to another release means users will have it in 2+
> > years after 2.06 release (unless distros backport it).

> That cannot be helped, unfortunately. The current release has been
> taking far too long already, and delaying it even further will
> completely bar anybody from using LUKS2 with GRUB in the first place.
Sure, understand.

> I don't really know about the release cycle, but personally I wouldn't
> mind to accelerate it. That's only my two cents though as somebody who
> hasn't been involved in the project that deeply.
+1 (that would allow to greatly reduce number of patches in distros, but
understand the lack of maintainers time).

Kind regards,
Petr

> Patrick




^ permalink raw reply	[flat|nested] 41+ messages in thread

* IS: GRUB release cycle: WAS: Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2021-01-19 19:31           ` Petr Vorel
@ 2021-01-21 14:49             ` Daniel Kiper
  2021-01-21 21:30               ` Petr Vorel
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Kiper @ 2021-01-21 14:49 UTC (permalink / raw)
  To: Petr Vorel; +Cc: Patrick Steinhardt, Dmitry, The development of GNU GRUB

On Tue, Jan 19, 2021 at 08:31:03PM +0100, Petr Vorel wrote:
> Hi Patrick,
>
> > On Tue, Jan 19, 2021 at 02:06:15PM +0100, Petr Vorel wrote:
> > > Hi,
>
> > > > Please try to build only for the "efi-64" platform. (not "pc")
> > > right, I'll test it, but we need to support also legacy bios.
>
> > I wasn't aware it wouldn't build on the "pc" platform, but I never even
> > tried in the first place. The patch series definitely needs more
> > polishing anyway, but thanks for making me aware.
> Thanks!
> One more note: "Argon2 not supported" is not shown, instead there is
> "Invalid encryption" printed later in luks2_recover_key().
> It was trivial to modify sources to find it, but that will not be user friendly
> for users which will run grub2 from distro package.
>
> > > BTW as Argon2 is the default PBKDF algorithm in current cryptsetup, Debian
> > > installer (and probably other distros' installers) uses it and it has to be
> > > converted after installation with Live CD / connecting HDD on different machine.
>
> > > Therefore postponing Argon2 to another release means users will have it in 2+
> > > years after 2.06 release (unless distros backport it).
>
> > That cannot be helped, unfortunately. The current release has been
> > taking far too long already, and delaying it even further will
> > completely bar anybody from using LUKS2 with GRUB in the first place.
> Sure, understand.
>
> > I don't really know about the release cycle, but personally I wouldn't
> > mind to accelerate it. That's only my two cents though as somebody who
> > hasn't been involved in the project that deeply.
> +1 (that would allow to greatly reduce number of patches in distros, but
> understand the lack of maintainers time).

I hope we will be able to release 2.06 in 2-3 months. Now I am looking
at cutting rc1 shortly. Expect it in the following weeks.

Definitely I do not want to make current release cycle a norm. I am
going to work on improving it after 2.06 release. I think we will be
targeting something between 6-12 months.

Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: IS: GRUB release cycle: WAS: Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2021-01-21 14:49             ` IS: GRUB release cycle: WAS: " Daniel Kiper
@ 2021-01-21 21:30               ` Petr Vorel
  2021-01-26 13:00                 ` Daniel Kiper
  0 siblings, 1 reply; 41+ messages in thread
From: Petr Vorel @ 2021-01-21 21:30 UTC (permalink / raw)
  To: Daniel Kiper
  Cc: Patrick Steinhardt, Dmitry, The development of GNU GRUB,
	Vladimir Serbinenko

Hi Daniel,

[Cc Vladimir]
...
> > > I don't really know about the release cycle, but personally I wouldn't
> > > mind to accelerate it. That's only my two cents though as somebody who
> > > hasn't been involved in the project that deeply.
> > +1 (that would allow to greatly reduce number of patches in distros, but
> > understand the lack of maintainers time).

> I hope we will be able to release 2.06 in 2-3 months. Now I am looking
> at cutting rc1 shortly. Expect it in the following weeks.
That'd be great.

> Definitely I do not want to make current release cycle a norm. I am
> going to work on improving it after 2.06 release. I think we will be
> targeting something between 6-12 months.
Anything than current situation will be great.
One would say that releasing more often with smaller diff would be better even
for you as a maintainer, but maybe the amount work to test everything before the
release is huge (given that testing e.g. Adrian does are probably done manually).

Busy projects with enough maintainers and other community members which helps
with reviewing and with working CI and good test coverage release every 3-4
months. It's clear that Grub isn't in that state, I wonder what could the
community do to help you to improve the situation a bit.

Kind regards,
Petr

> Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: IS: GRUB release cycle: WAS: Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2021-01-21 21:30               ` Petr Vorel
@ 2021-01-26 13:00                 ` Daniel Kiper
  2021-01-26 19:57                   ` Petr Vorel
  0 siblings, 1 reply; 41+ messages in thread
From: Daniel Kiper @ 2021-01-26 13:00 UTC (permalink / raw)
  To: Petr Vorel
  Cc: Patrick Steinhardt, Dmitry, The development of GNU GRUB,
	Vladimir Serbinenko

On Thu, Jan 21, 2021 at 10:30:11PM +0100, Petr Vorel wrote:
> Hi Daniel,
>
> [Cc Vladimir]
> ...
> > > > I don't really know about the release cycle, but personally I wouldn't
> > > > mind to accelerate it. That's only my two cents though as somebody who
> > > > hasn't been involved in the project that deeply.
> > > +1 (that would allow to greatly reduce number of patches in distros, but
> > > understand the lack of maintainers time).
>
> > I hope we will be able to release 2.06 in 2-3 months. Now I am looking
> > at cutting rc1 shortly. Expect it in the following weeks.
> That'd be great.
>
> > Definitely I do not want to make current release cycle a norm. I am
> > going to work on improving it after 2.06 release. I think we will be
> > targeting something between 6-12 months.
> Anything than current situation will be great.
> One would say that releasing more often with smaller diff would be better even
> for you as a maintainer, but maybe the amount work to test everything before the
> release is huge (given that testing e.g. Adrian does are probably done manually).
>
> Busy projects with enough maintainers and other community members which helps
> with reviewing and with working CI and good test coverage release every 3-4
> months. It's clear that Grub isn't in that state, I wonder what could the
> community do to help you to improve the situation a bit.

At this point we need help with testing and reviews. We want to be sure
as much as possible that current code is in pretty good state and ready
for release. WRT reviews, if you can see something on the list which is
in the area of your expertise do not hesitate to review/comment. If you
are not sure the maintainers will be OK with your comment just say that.
We can add our comments later. These really help us to improve GRUB code.

I am also working on getting more time for GRUB maintainer work. I hope
I will manage to do that soon and will be able to clear current backlog
quickly.

Daniel


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: IS: GRUB release cycle: WAS: Re: [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup
  2021-01-26 13:00                 ` Daniel Kiper
@ 2021-01-26 19:57                   ` Petr Vorel
  0 siblings, 0 replies; 41+ messages in thread
From: Petr Vorel @ 2021-01-26 19:57 UTC (permalink / raw)
  To: Daniel Kiper
  Cc: Patrick Steinhardt, Dmitry, The development of GNU GRUB,
	Vladimir Serbinenko

> On Thu, Jan 21, 2021 at 10:30:11PM +0100, Petr Vorel wrote:
> > Hi Daniel,

> > [Cc Vladimir]
> > ...
> > > > > I don't really know about the release cycle, but personally I wouldn't
> > > > > mind to accelerate it. That's only my two cents though as somebody who
> > > > > hasn't been involved in the project that deeply.
> > > > +1 (that would allow to greatly reduce number of patches in distros, but
> > > > understand the lack of maintainers time).

> > > I hope we will be able to release 2.06 in 2-3 months. Now I am looking
> > > at cutting rc1 shortly. Expect it in the following weeks.
> > That'd be great.

> > > Definitely I do not want to make current release cycle a norm. I am
> > > going to work on improving it after 2.06 release. I think we will be
> > > targeting something between 6-12 months.
> > Anything than current situation will be great.
> > One would say that releasing more often with smaller diff would be better even
> > for you as a maintainer, but maybe the amount work to test everything before the
> > release is huge (given that testing e.g. Adrian does are probably done manually).

> > Busy projects with enough maintainers and other community members which helps
> > with reviewing and with working CI and good test coverage release every 3-4
> > months. It's clear that Grub isn't in that state, I wonder what could the
> > community do to help you to improve the situation a bit.

> At this point we need help with testing and reviews. We want to be sure
> as much as possible that current code is in pretty good state and ready
> for release. WRT reviews, if you can see something on the list which is
> in the area of your expertise do not hesitate to review/comment. If you
> are not sure the maintainers will be OK with your comment just say that.
> We can add our comments later. These really help us to improve GRUB code.
Thanks for info!

> I am also working on getting more time for GRUB maintainer work. I hope
> I will manage to do that soon and will be able to clear current backlog
> quickly.
Good luck!

> Daniel

Kind regards,
Petr


^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH v4 0/5] Support Argon2 KDF in LUKS2
  2020-03-10 18:58 ` [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
                     ` (2 preceding siblings ...)
  2021-01-19  0:07   ` Petr Vorel
@ 2021-08-08 13:58   ` Patrick Steinhardt
  2021-08-08 13:58     ` [PATCH v4 1/5] kern: dl: Allow modules under CC0 license Patrick Steinhardt
                       ` (4 more replies)
  3 siblings, 5 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2021-08-08 13:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Daniel Kiper, Leif Lindholm, agraf, pjones, mjg59, phcoder,
	Milan Broz, petr.vorel, Dmitry

[-- Attachment #1: Type: text/plain, Size: 29154 bytes --]

Hi,

this is the fourth version of my patch series to implement support for
the Argon2 key derival function in LUKS2. This patch series has been
rebased on the current master branch, with the following changes:

    - This series is now based on my pathc series which implements
      runtime allocation of memory regions on EFI [1]. Like this, we
      don't need to bump any memory allocation limits, but GRUB knows to
      request pages from the EFI firmware as required.

    - I've changed the license of the Argon2 module to CC0, and added a
      patch on top which allows CC0-licensed modules. This license is
      compatible with the GPL, so having both together shouldn't be a
      problem. If you think this is inacceptable, then I'll reach out
      the authors and ask them whether it's fine to include the code as
      GPLv3.

    - We're now always using `grub_memset ()` to wipe memory.

    - A bunch of smallish fixes left and right. I guess these are best
      to be seen via below range diff.

Patrick

[1]: <cover.1628429274.git.ps@pks.im>

Patrick Steinhardt (5):
  kern: dl: Allow modules under CC0 license
  types.h: Add UINT-related macros needed for Argon2
  argon2: Import reference implementation of Argon2
  luks2: Discern Argon2i and Argon2id
  luks2: Support key derival via Argon2

 Makefile.util.def                             |   6 +-
 docs/grub-dev.texi                            |  64 +++
 grub-core/Makefile.core.def                   |  10 +-
 grub-core/disk/luks2.c                        |  26 +-
 grub-core/kern/dl.c                           |   3 +-
 grub-core/lib/argon2/LICENSE                  | 314 +++++++++++
 grub-core/lib/argon2/argon2.c                 | 232 ++++++++
 grub-core/lib/argon2/argon2.h                 | 264 +++++++++
 grub-core/lib/argon2/blake2/blake2-impl.h     | 151 ++++++
 grub-core/lib/argon2/blake2/blake2.h          |  89 +++
 grub-core/lib/argon2/blake2/blake2b.c         | 388 ++++++++++++++
 .../lib/argon2/blake2/blamka-round-ref.h      |  56 ++
 grub-core/lib/argon2/core.c                   | 506 ++++++++++++++++++
 grub-core/lib/argon2/core.h                   | 228 ++++++++
 grub-core/lib/argon2/ref.c                    | 190 +++++++
 include/grub/types.h                          |   8 +
 util/grub-module-verifierXX.c                 |   3 +-
 17 files changed, 2527 insertions(+), 11 deletions(-)
 create mode 100644 grub-core/lib/argon2/LICENSE
 create mode 100644 grub-core/lib/argon2/argon2.c
 create mode 100644 grub-core/lib/argon2/argon2.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2-impl.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2b.c
 create mode 100644 grub-core/lib/argon2/blake2/blamka-round-ref.h
 create mode 100644 grub-core/lib/argon2/core.c
 create mode 100644 grub-core/lib/argon2/core.h
 create mode 100644 grub-core/lib/argon2/ref.c

Range-diff against v3:
1:  4c123e0a2 < -:  --------- efi: Always try to allocate heap size of 1.5GB
-:  --------- > 1:  e0a474cdc kern: dl: Allow modules under CC0 license
2:  6bfb385b4 ! 2:  c1c8f89ce types.h: add UINT-related macros needed for Argon2
    @@ Metadata
     Author: Patrick Steinhardt <ps@pks.im>
     
      ## Commit message ##
    -    types.h: add UINT-related macros needed for Argon2
    +    types.h: Add UINT-related macros needed for Argon2
     
         For the upcoming import of the Argon2 library, we need the macros
         GRUB_UINT32_MAX, GRUB_UINT32_C and GRUB_UINT64_C. Add them as a
    @@ include/grub/types.h: typedef grub_int32_t	grub_ssize_t;
      #define GRUB_INT_MIN (-GRUB_INT_MAX - 1)
      #define GRUB_INT32_MAX 2147483647
     @@ include/grub/types.h: typedef grub_int32_t	grub_ssize_t;
    - #endif
    - # define GRUB_LONG_MIN (-GRUB_LONG_MAX - 1)
    + #define GRUB_TYPE_U_MAX(type) ((unsigned long long)((typeof (type))(~0)))
    + #define GRUB_TYPE_U_MIN(type) 0ULL
      
     +# define GRUB_UINT32_C(x) x ## U
     +# if GRUB_ULONG_MAX >> 31 >> 31 >> 1 == 1
3:  bb6fa9cb5 ! 3:  18fa10a56 argon2: Import Argon2 from cryptsetup
    @@ Metadata
     Author: Patrick Steinhardt <ps@pks.im>
     
      ## Commit message ##
    -    argon2: Import Argon2 from cryptsetup
    +    argon2: Import reference implementation of Argon2
     
         In order to support the Argon2 key derival function for LUKS2, we
         obviously need to implement Argon2. It doesn't make a lot of sense to
    -    hand-code any crypto, which is why this commit instead imports Argon2
    -    from the cryptsetup project. This commit thus imports the code from the
    +    hand-code any crypto, which is why this commit imports Argon2 from the
         official reference implementation located at [1]. The code is licensed
         under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
         2.0 are compatible with GPLv3, it should be fine to import that code.
     
         The code is imported from commit 62358ba (Merge pull request #270 from
         bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
    -    several adjustments were required that have beed documented in
    +    several adjustments were required that have been documented in
         "grub-dev.texi".
     
         [1]: https://github.com/P-H-C/phc-winner-argon2
    @@ grub-core/Makefile.core.def: module = {
        name = afsplitter;
        common = disk/AFSplitter.c;
     
    + ## grub-core/lib/argon2/LICENSE (new) ##
    +@@
    ++Argon2 reference source code package - reference C implementations
    ++
    ++Copyright 2015
    ++Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
    ++
    ++You may use this work under the terms of a Creative Commons CC0 1.0 
    ++License/Waiver or the Apache Public License 2.0, at your option. The terms of
    ++these licenses can be found at:
    ++
    ++- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
    ++- Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
    ++
    ++The terms of the licenses are reproduced below.
    ++
    ++--------------------------------------------------------------------------------
    ++
    ++Creative Commons Legal Code
    ++
    ++CC0 1.0 Universal
    ++
    ++    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
    ++    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
    ++    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
    ++    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
    ++    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
    ++    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
    ++    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
    ++    HEREUNDER.
    ++
    ++Statement of Purpose
    ++
    ++The laws of most jurisdictions throughout the world automatically confer
    ++exclusive Copyright and Related Rights (defined below) upon the creator
    ++and subsequent owner(s) (each and all, an "owner") of an original work of
    ++authorship and/or a database (each, a "Work").
    ++
    ++Certain owners wish to permanently relinquish those rights to a Work for
    ++the purpose of contributing to a commons of creative, cultural and
    ++scientific works ("Commons") that the public can reliably and without fear
    ++of later claims of infringement build upon, modify, incorporate in other
    ++works, reuse and redistribute as freely as possible in any form whatsoever
    ++and for any purposes, including without limitation commercial purposes.
    ++These owners may contribute to the Commons to promote the ideal of a free
    ++culture and the further production of creative, cultural and scientific
    ++works, or to gain reputation or greater distribution for their Work in
    ++part through the use and efforts of others.
    ++
    ++For these and/or other purposes and motivations, and without any
    ++expectation of additional consideration or compensation, the person
    ++associating CC0 with a Work (the "Affirmer"), to the extent that he or she
    ++is an owner of Copyright and Related Rights in the Work, voluntarily
    ++elects to apply CC0 to the Work and publicly distribute the Work under its
    ++terms, with knowledge of his or her Copyright and Related Rights in the
    ++Work and the meaning and intended legal effect of CC0 on those rights.
    ++
    ++1. Copyright and Related Rights. A Work made available under CC0 may be
    ++protected by copyright and related or neighboring rights ("Copyright and
    ++Related Rights"). Copyright and Related Rights include, but are not
    ++limited to, the following:
    ++
    ++  i. the right to reproduce, adapt, distribute, perform, display,
    ++     communicate, and translate a Work;
    ++ ii. moral rights retained by the original author(s) and/or performer(s);
    ++iii. publicity and privacy rights pertaining to a person's image or
    ++     likeness depicted in a Work;
    ++ iv. rights protecting against unfair competition in regards to a Work,
    ++     subject to the limitations in paragraph 4(a), below;
    ++  v. rights protecting the extraction, dissemination, use and reuse of data
    ++     in a Work;
    ++ vi. database rights (such as those arising under Directive 96/9/EC of the
    ++     European Parliament and of the Council of 11 March 1996 on the legal
    ++     protection of databases, and under any national implementation
    ++     thereof, including any amended or successor version of such
    ++     directive); and
    ++vii. other similar, equivalent or corresponding rights throughout the
    ++     world based on applicable law or treaty, and any national
    ++     implementations thereof.
    ++
    ++2. Waiver. To the greatest extent permitted by, but not in contravention
    ++of, applicable law, Affirmer hereby overtly, fully, permanently,
    ++irrevocably and unconditionally waives, abandons, and surrenders all of
    ++Affirmer's Copyright and Related Rights and associated claims and causes
    ++of action, whether now known or unknown (including existing as well as
    ++future claims and causes of action), in the Work (i) in all territories
    ++worldwide, (ii) for the maximum duration provided by applicable law or
    ++treaty (including future time extensions), (iii) in any current or future
    ++medium and for any number of copies, and (iv) for any purpose whatsoever,
    ++including without limitation commercial, advertising or promotional
    ++purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
    ++member of the public at large and to the detriment of Affirmer's heirs and
    ++successors, fully intending that such Waiver shall not be subject to
    ++revocation, rescission, cancellation, termination, or any other legal or
    ++equitable action to disrupt the quiet enjoyment of the Work by the public
    ++as contemplated by Affirmer's express Statement of Purpose.
    ++
    ++3. Public License Fallback. Should any part of the Waiver for any reason
    ++be judged legally invalid or ineffective under applicable law, then the
    ++Waiver shall be preserved to the maximum extent permitted taking into
    ++account Affirmer's express Statement of Purpose. In addition, to the
    ++extent the Waiver is so judged Affirmer hereby grants to each affected
    ++person a royalty-free, non transferable, non sublicensable, non exclusive,
    ++irrevocable and unconditional license to exercise Affirmer's Copyright and
    ++Related Rights in the Work (i) in all territories worldwide, (ii) for the
    ++maximum duration provided by applicable law or treaty (including future
    ++time extensions), (iii) in any current or future medium and for any number
    ++of copies, and (iv) for any purpose whatsoever, including without
    ++limitation commercial, advertising or promotional purposes (the
    ++"License"). The License shall be deemed effective as of the date CC0 was
    ++applied by Affirmer to the Work. Should any part of the License for any
    ++reason be judged legally invalid or ineffective under applicable law, such
    ++partial invalidity or ineffectiveness shall not invalidate the remainder
    ++of the License, and in such case Affirmer hereby affirms that he or she
    ++will not (i) exercise any of his or her remaining Copyright and Related
    ++Rights in the Work or (ii) assert any associated claims and causes of
    ++action with respect to the Work, in either case contrary to Affirmer's
    ++express Statement of Purpose.
    ++
    ++4. Limitations and Disclaimers.
    ++
    ++ a. No trademark or patent rights held by Affirmer are waived, abandoned,
    ++    surrendered, licensed or otherwise affected by this document.
    ++ b. Affirmer offers the Work as-is and makes no representations or
    ++    warranties of any kind concerning the Work, express, implied,
    ++    statutory or otherwise, including without limitation warranties of
    ++    title, merchantability, fitness for a particular purpose, non
    ++    infringement, or the absence of latent or other defects, accuracy, or
    ++    the present or absence of errors, whether or not discoverable, all to
    ++    the greatest extent permissible under applicable law.
    ++ c. Affirmer disclaims responsibility for clearing rights of other persons
    ++    that may apply to the Work or any use thereof, including without
    ++    limitation any person's Copyright and Related Rights in the Work.
    ++    Further, Affirmer disclaims responsibility for obtaining any necessary
    ++    consents, permissions or other rights required for any use of the
    ++    Work.
    ++ d. Affirmer understands and acknowledges that Creative Commons is not a
    ++    party to this document and has no duty or obligation with respect to
    ++    this CC0 or use of the Work.
    ++
    ++--------------------------------------------------------------------------------
    ++
    ++                                 Apache License
    ++                           Version 2.0, January 2004
    ++                        http://www.apache.org/licenses/
    ++
    ++   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
    ++
    ++   1. Definitions.
    ++
    ++      "License" shall mean the terms and conditions for use, reproduction,
    ++      and distribution as defined by Sections 1 through 9 of this document.
    ++
    ++      "Licensor" shall mean the copyright owner or entity authorized by
    ++      the copyright owner that is granting the License.
    ++
    ++      "Legal Entity" shall mean the union of the acting entity and all
    ++      other entities that control, are controlled by, or are under common
    ++      control with that entity. For the purposes of this definition,
    ++      "control" means (i) the power, direct or indirect, to cause the
    ++      direction or management of such entity, whether by contract or
    ++      otherwise, or (ii) ownership of fifty percent (50%) or more of the
    ++      outstanding shares, or (iii) beneficial ownership of such entity.
    ++
    ++      "You" (or "Your") shall mean an individual or Legal Entity
    ++      exercising permissions granted by this License.
    ++
    ++      "Source" form shall mean the preferred form for making modifications,
    ++      including but not limited to software source code, documentation
    ++      source, and configuration files.
    ++
    ++      "Object" form shall mean any form resulting from mechanical
    ++      transformation or translation of a Source form, including but
    ++      not limited to compiled object code, generated documentation,
    ++      and conversions to other media types.
    ++
    ++      "Work" shall mean the work of authorship, whether in Source or
    ++      Object form, made available under the License, as indicated by a
    ++      copyright notice that is included in or attached to the work
    ++      (an example is provided in the Appendix below).
    ++
    ++      "Derivative Works" shall mean any work, whether in Source or Object
    ++      form, that is based on (or derived from) the Work and for which the
    ++      editorial revisions, annotations, elaborations, or other modifications
    ++      represent, as a whole, an original work of authorship. For the purposes
    ++      of this License, Derivative Works shall not include works that remain
    ++      separable from, or merely link (or bind by name) to the interfaces of,
    ++      the Work and Derivative Works thereof.
    ++
    ++      "Contribution" shall mean any work of authorship, including
    ++      the original version of the Work and any modifications or additions
    ++      to that Work or Derivative Works thereof, that is intentionally
    ++      submitted to Licensor for inclusion in the Work by the copyright owner
    ++      or by an individual or Legal Entity authorized to submit on behalf of
    ++      the copyright owner. For the purposes of this definition, "submitted"
    ++      means any form of electronic, verbal, or written communication sent
    ++      to the Licensor or its representatives, including but not limited to
    ++      communication on electronic mailing lists, source code control systems,
    ++      and issue tracking systems that are managed by, or on behalf of, the
    ++      Licensor for the purpose of discussing and improving the Work, but
    ++      excluding communication that is conspicuously marked or otherwise
    ++      designated in writing by the copyright owner as "Not a Contribution."
    ++
    ++      "Contributor" shall mean Licensor and any individual or Legal Entity
    ++      on behalf of whom a Contribution has been received by Licensor and
    ++      subsequently incorporated within the Work.
    ++
    ++   2. Grant of Copyright License. Subject to the terms and conditions of
    ++      this License, each Contributor hereby grants to You a perpetual,
    ++      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    ++      copyright license to reproduce, prepare Derivative Works of,
    ++      publicly display, publicly perform, sublicense, and distribute the
    ++      Work and such Derivative Works in Source or Object form.
    ++
    ++   3. Grant of Patent License. Subject to the terms and conditions of
    ++      this License, each Contributor hereby grants to You a perpetual,
    ++      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    ++      (except as stated in this section) patent license to make, have made,
    ++      use, offer to sell, sell, import, and otherwise transfer the Work,
    ++      where such license applies only to those patent claims licensable
    ++      by such Contributor that are necessarily infringed by their
    ++      Contribution(s) alone or by combination of their Contribution(s)
    ++      with the Work to which such Contribution(s) was submitted. If You
    ++      institute patent litigation against any entity (including a
    ++      cross-claim or counterclaim in a lawsuit) alleging that the Work
    ++      or a Contribution incorporated within the Work constitutes direct
    ++      or contributory patent infringement, then any patent licenses
    ++      granted to You under this License for that Work shall terminate
    ++      as of the date such litigation is filed.
    ++
    ++   4. Redistribution. You may reproduce and distribute copies of the
    ++      Work or Derivative Works thereof in any medium, with or without
    ++      modifications, and in Source or Object form, provided that You
    ++      meet the following conditions:
    ++
    ++      (a) You must give any other recipients of the Work or
    ++          Derivative Works a copy of this License; and
    ++
    ++      (b) You must cause any modified files to carry prominent notices
    ++          stating that You changed the files; and
    ++
    ++      (c) You must retain, in the Source form of any Derivative Works
    ++          that You distribute, all copyright, patent, trademark, and
    ++          attribution notices from the Source form of the Work,
    ++          excluding those notices that do not pertain to any part of
    ++          the Derivative Works; and
    ++
    ++      (d) If the Work includes a "NOTICE" text file as part of its
    ++          distribution, then any Derivative Works that You distribute must
    ++          include a readable copy of the attribution notices contained
    ++          within such NOTICE file, excluding those notices that do not
    ++          pertain to any part of the Derivative Works, in at least one
    ++          of the following places: within a NOTICE text file distributed
    ++          as part of the Derivative Works; within the Source form or
    ++          documentation, if provided along with the Derivative Works; or,
    ++          within a display generated by the Derivative Works, if and
    ++          wherever such third-party notices normally appear. The contents
    ++          of the NOTICE file are for informational purposes only and
    ++          do not modify the License. You may add Your own attribution
    ++          notices within Derivative Works that You distribute, alongside
    ++          or as an addendum to the NOTICE text from the Work, provided
    ++          that such additional attribution notices cannot be construed
    ++          as modifying the License.
    ++
    ++      You may add Your own copyright statement to Your modifications and
    ++      may provide additional or different license terms and conditions
    ++      for use, reproduction, or distribution of Your modifications, or
    ++      for any such Derivative Works as a whole, provided Your use,
    ++      reproduction, and distribution of the Work otherwise complies with
    ++      the conditions stated in this License.
    ++
    ++   5. Submission of Contributions. Unless You explicitly state otherwise,
    ++      any Contribution intentionally submitted for inclusion in the Work
    ++      by You to the Licensor shall be under the terms and conditions of
    ++      this License, without any additional terms or conditions.
    ++      Notwithstanding the above, nothing herein shall supersede or modify
    ++      the terms of any separate license agreement you may have executed
    ++      with Licensor regarding such Contributions.
    ++
    ++   6. Trademarks. This License does not grant permission to use the trade
    ++      names, trademarks, service marks, or product names of the Licensor,
    ++      except as required for reasonable and customary use in describing the
    ++      origin of the Work and reproducing the content of the NOTICE file.
    ++
    ++   7. Disclaimer of Warranty. Unless required by applicable law or
    ++      agreed to in writing, Licensor provides the Work (and each
    ++      Contributor provides its Contributions) on an "AS IS" BASIS,
    ++      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    ++      implied, including, without limitation, any warranties or conditions
    ++      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
    ++      PARTICULAR PURPOSE. You are solely responsible for determining the
    ++      appropriateness of using or redistributing the Work and assume any
    ++      risks associated with Your exercise of permissions under this License.
    ++
    ++   8. Limitation of Liability. In no event and under no legal theory,
    ++      whether in tort (including negligence), contract, or otherwise,
    ++      unless required by applicable law (such as deliberate and grossly
    ++      negligent acts) or agreed to in writing, shall any Contributor be
    ++      liable to You for damages, including any direct, indirect, special,
    ++      incidental, or consequential damages of any character arising as a
    ++      result of this License or out of the use or inability to use the
    ++      Work (including but not limited to damages for loss of goodwill,
    ++      work stoppage, computer failure or malfunction, or any and all
    ++      other commercial damages or losses), even if such Contributor
    ++      has been advised of the possibility of such damages.
    ++
    ++   9. Accepting Warranty or Additional Liability. While redistributing
    ++      the Work or Derivative Works thereof, You may choose to offer,
    ++      and charge a fee for, acceptance of support, warranty, indemnity,
    ++      or other liability obligations and/or rights consistent with this
    ++      License. However, in accepting such obligations, You may act only
    ++      on Your own behalf and on Your sole responsibility, not on behalf
    ++      of any other Contributor, and only if You agree to indemnify,
    ++      defend, and hold each Contributor harmless for any liability
    ++      incurred by, or claims asserted against, such Contributor by reason
    ++      of your accepting any such warranty or additional liability.
    +
      ## grub-core/lib/argon2/argon2.c (new) ##
     @@
     +/*
    @@ grub-core/lib/argon2/argon2.c (new)
     +#include "argon2.h"
     +#include "core.h"
     +
    -+GRUB_MOD_LICENSE ("GPLv3");
    ++GRUB_MOD_LICENSE ("CC0");
     +
     +static int argon2_ctx(argon2_context *context, argon2_type type) {
     +    /* 1. Validate all inputs */
    @@ grub-core/lib/argon2/core.c (new)
     +#endif
     +#define VC_GE_2005(version) (version >= 1400)
     +
    -+/* for explicit_bzero() on glibc */
    -+#define _DEFAULT_SOURCE
    -+
     +#include "core.h"
     +#include "blake2/blake2.h"
     +#include "blake2/blake2-impl.h"
    @@ grub-core/lib/argon2/core.c (new)
     +    }
     +}
     +
    -+#if defined(__OpenBSD__)
    -+#define HAVE_EXPLICIT_BZERO 1
    -+#elif defined(__GLIBC__) && defined(__GLIBC_PREREQ)
    -+#if __GLIBC_PREREQ(2,25)
    -+#define HAVE_EXPLICIT_BZERO 1
    -+#endif
    -+#endif
    -+
     +void NOT_OPTIMIZED secure_wipe_memory(void *v, grub_size_t n) {
    -+#if defined(_MSC_VER) && VC_GE_2005(_MSC_VER)
    -+    SecureZeroMemory(v, n);
    -+#elif defined grub_memset_s
    -+    grub_memset_s(v, n, 0, n);
    -+#elif defined(HAVE_EXPLICIT_BZERO)
    -+    explicit_bzero(v, n);
    -+#else
     +    static void *(*const volatile grub_memset_sec)(void *, int, grub_size_t) = &grub_memset;
     +    grub_memset_sec(v, 0, n);
    -+#endif
     +}
     +
     +/* Memory clear flag defaults to true. */
    @@ grub-core/lib/argon2/core.c (new)
     +     */
     +    grub_uint32_t reference_area_size;
     +    grub_uint64_t relative_position;
    -+    grub_uint32_t start_position, absolute_position;
    ++    grub_uint64_t start_position, absolute_position;
     +
     +    if (0 == position->pass) {
     +        /* First pass */
    @@ grub-core/lib/argon2/core.c (new)
     +    }
     +
     +    /* 1.2.6. Computing absolute position */
    -+    absolute_position = (start_position + relative_position) %
    -+                        instance->lane_length; /* absolute position */
    ++    grub_divmod64 (start_position + relative_position, instance->lane_length,
    ++                   &absolute_position); /* absolute position */
     +    return absolute_position;
     +}
     +
    @@ grub-core/lib/argon2/ref.c (new)
     +        }
     +
     +        /* 1.2.2 Computing the lane of the reference block */
    -+        ref_lane = ((pseudo_rand >> 32)) % instance->lanes;
    ++        grub_divmod64 (pseudo_rand >> 32, instance->lanes, &ref_lane);
     +
     +        if ((position.pass == 0) && (position.slice == 0)) {
     +            /* Can not reference other lanes yet */
4:  81c347d62 ! 4:  e40635878 luks2: Discern Argon2i and Argon2id
    @@ Commit message
         accordingly.
     
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
    -    Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
     
      ## grub-core/disk/luks2.c ##
     @@ grub-core/disk/luks2.c: GRUB_MOD_LICENSE ("GPLv3+");
5:  11c2a26a8 ! 5:  f733e61bd luks2: Support key derival via Argon2
    @@ Commit message
         now trivial.
     
         Signed-off-by: Patrick Steinhardt <ps@pks.im>
    -    Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
     
      ## Makefile.util.def ##
     @@ Makefile.util.def: AutoGen definitions Makefile.tpl;
-- 
2.32.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [PATCH v4 1/5] kern: dl: Allow modules under CC0 license
  2021-08-08 13:58   ` [PATCH v4 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
@ 2021-08-08 13:58     ` Patrick Steinhardt
  2021-08-08 15:03       ` Petr Vorel
  2021-08-08 13:58     ` [PATCH v4 2/5] types.h: Add UINT-related macros needed for Argon2 Patrick Steinhardt
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 41+ messages in thread
From: Patrick Steinhardt @ 2021-08-08 13:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Daniel Kiper, Leif Lindholm, agraf, pjones, mjg59, phcoder,
	Milan Broz, petr.vorel, Dmitry

[-- Attachment #1: Type: text/plain, Size: 2077 bytes --]

We're about to import the reference implementation of Argon2, which is
licensed under CC0. Given that this license is compatible with the GPL
according to [1], having code under this license alongside with GPL'd
code is perfectly fine.

[1]: https://www.gnu.org/licenses/license-list.en.html#CC0

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 grub-core/kern/dl.c           | 3 ++-
 util/grub-module-verifierXX.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c
index 48f8a7907..7d395096f 100644
--- a/grub-core/kern/dl.c
+++ b/grub-core/kern/dl.c
@@ -462,7 +462,8 @@ grub_dl_check_license (Elf_Ehdr *e)
   Elf_Shdr *s = grub_dl_find_section (e, ".module_license");
   if (s && (grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3") == 0
 	    || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv3+") == 0
-	    || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0))
+	    || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=GPLv2+") == 0
+	    || grub_strcmp ((char *) e + s->sh_offset, "LICENSE=CC0") == 0))
     return GRUB_ERR_NONE;
   return grub_error (GRUB_ERR_BAD_MODULE, "incompatible license");
 }
diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c
index ceb24309a..284f9026e 100644
--- a/util/grub-module-verifierXX.c
+++ b/util/grub-module-verifierXX.c
@@ -157,7 +157,8 @@ check_license (const char * const filename,
   Elf_Shdr *s = find_section (arch, e, ".module_license");
   if (s && (strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3") == 0
 	    || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv3+") == 0
-	    || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv2+") == 0))
+	    || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=GPLv2+") == 0
+	    || strcmp ((char *) e + grub_target_to_host(s->sh_offset), "LICENSE=CC0") == 0))
     return;
   grub_util_error ("%s: incompatible license", filename);
 }
-- 
2.32.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v4 2/5] types.h: Add UINT-related macros needed for Argon2
  2021-08-08 13:58   ` [PATCH v4 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
  2021-08-08 13:58     ` [PATCH v4 1/5] kern: dl: Allow modules under CC0 license Patrick Steinhardt
@ 2021-08-08 13:58     ` Patrick Steinhardt
  2021-08-08 13:58     ` [PATCH v4 3/5] argon2: Import reference implementation of Argon2 Patrick Steinhardt
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2021-08-08 13:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Daniel Kiper, Leif Lindholm, agraf, pjones, mjg59, phcoder,
	Milan Broz, petr.vorel, Dmitry

[-- Attachment #1: Type: text/plain, Size: 1322 bytes --]

For the upcoming import of the Argon2 library, we need the macros
GRUB_UINT32_MAX, GRUB_UINT32_C and GRUB_UINT64_C. Add them as a
preparatory step.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 include/grub/types.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/grub/types.h b/include/grub/types.h
index 0a3ff1591..13b0c46b3 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -153,6 +153,7 @@ typedef grub_int32_t	grub_ssize_t;
 #define GRUB_SHRT_MAX 0x7fff
 #define GRUB_SHRT_MIN (-GRUB_SHRT_MAX - 1)
 #define GRUB_UINT_MAX 4294967295U
+#define GRUB_UINT32_MAX 4294967295U
 #define GRUB_INT_MAX 0x7fffffff
 #define GRUB_INT_MIN (-GRUB_INT_MAX - 1)
 #define GRUB_INT32_MAX 2147483647
@@ -174,6 +175,13 @@ typedef grub_int32_t	grub_ssize_t;
 #define GRUB_TYPE_U_MAX(type) ((unsigned long long)((typeof (type))(~0)))
 #define GRUB_TYPE_U_MIN(type) 0ULL
 
+# define GRUB_UINT32_C(x) x ## U
+# if GRUB_ULONG_MAX >> 31 >> 31 >> 1 == 1
+#  define GRUB_UINT64_C(x) x##UL
+# elif 1
+#  define GRUB_UINT64_C(x) x##ULL
+# endif
+
 typedef grub_uint64_t grub_properly_aligned_t;
 
 #define GRUB_PROPERLY_ALIGNED_ARRAY(name, size) grub_properly_aligned_t name[((size) + sizeof (grub_properly_aligned_t) - 1) / sizeof (grub_properly_aligned_t)]
-- 
2.32.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v4 3/5] argon2: Import reference implementation of Argon2
  2021-08-08 13:58   ` [PATCH v4 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
  2021-08-08 13:58     ` [PATCH v4 1/5] kern: dl: Allow modules under CC0 license Patrick Steinhardt
  2021-08-08 13:58     ` [PATCH v4 2/5] types.h: Add UINT-related macros needed for Argon2 Patrick Steinhardt
@ 2021-08-08 13:58     ` Patrick Steinhardt
  2021-08-08 13:58     ` [PATCH v4 4/5] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
  2021-08-08 13:59     ` [PATCH v4 5/5] luks2: Support key derival via Argon2 Patrick Steinhardt
  4 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2021-08-08 13:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Daniel Kiper, Leif Lindholm, agraf, pjones, mjg59, phcoder,
	Milan Broz, petr.vorel, Dmitry

[-- Attachment #1: Type: text/plain, Size: 101910 bytes --]

In order to support the Argon2 key derival function for LUKS2, we
obviously need to implement Argon2. It doesn't make a lot of sense to
hand-code any crypto, which is why this commit imports Argon2 from the
official reference implementation located at [1]. The code is licensed
under CC0 1.0 Universal/Apache 2.0. Given that both LGPLv2.1+ and Apache
2.0 are compatible with GPLv3, it should be fine to import that code.

The code is imported from commit 62358ba (Merge pull request #270 from
bitmark-property-system/master, 2019-05-20). To make it work for GRUB,
several adjustments were required that have been documented in
"grub-dev.texi".

[1]: https://github.com/P-H-C/phc-winner-argon2

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 docs/grub-dev.texi                            |  64 +++
 grub-core/Makefile.core.def                   |   8 +
 grub-core/lib/argon2/LICENSE                  | 314 +++++++++++
 grub-core/lib/argon2/argon2.c                 | 232 ++++++++
 grub-core/lib/argon2/argon2.h                 | 264 +++++++++
 grub-core/lib/argon2/blake2/blake2-impl.h     | 151 ++++++
 grub-core/lib/argon2/blake2/blake2.h          |  89 +++
 grub-core/lib/argon2/blake2/blake2b.c         | 388 ++++++++++++++
 .../lib/argon2/blake2/blamka-round-ref.h      |  56 ++
 grub-core/lib/argon2/core.c                   | 506 ++++++++++++++++++
 grub-core/lib/argon2/core.h                   | 228 ++++++++
 grub-core/lib/argon2/ref.c                    | 190 +++++++
 12 files changed, 2490 insertions(+)
 create mode 100644 grub-core/lib/argon2/LICENSE
 create mode 100644 grub-core/lib/argon2/argon2.c
 create mode 100644 grub-core/lib/argon2/argon2.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2-impl.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2.h
 create mode 100644 grub-core/lib/argon2/blake2/blake2b.c
 create mode 100644 grub-core/lib/argon2/blake2/blamka-round-ref.h
 create mode 100644 grub-core/lib/argon2/core.c
 create mode 100644 grub-core/lib/argon2/core.h
 create mode 100644 grub-core/lib/argon2/ref.c

diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index 6c629a23e..ead2a8259 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -490,11 +490,75 @@ GRUB includes some code from other projects, and it is sometimes necessary
 to update it.
 
 @menu
+* Argon2::
 * Gnulib::
 * jsmn::
 * minilzo::
 @end menu
 
+@node Argon2
+@section Argon2
+
+Argon2 is a key derivation function used by LUKS2 in order to derive encryption
+keys from a user-provided password. GRUB imports the official reference
+implementation of Argon2 from @url{https://github.com/P-H-C/phc-winner-argon2}.
+In order to make the library usable for GRUB, we need to perform various
+conversions. This is mainly due to the fact that the imported code makes use of
+types and functions defined in the C standard library, which isn't available.
+Furthermore, using the POSIX wrapper library is not possible as the code needs
+to be part of the kernel.
+
+Updating the code can thus be performed like following:
+
+@example
+$ git clone https://github.com/P-H-C/phc-winner-argon2 argon2
+$ cp argon2/include/argon2.h argon2/src/@{argon2.c,core.c,core.h,ref.c@} \
+    grub-core/lib/argon2/
+$ cp argon2/src/blake2/@{blake2-impl.h,blake2.h,blake2b.c,blamka-round-ref.h@} \
+    grub-core/lib/argon2/blake2/
+$ sed -e 's/UINT32_C/GRUB_UINT32_C/g' \
+      -e 's/UINT64_C/GRUB_UINT64_C/g' \
+      -e 's/UINT32_MAX/GRUB_UINT32_MAX/g' \
+      -e 's/CHAR_BIT/GRUB_CHAR_BIT/g' \
+      -e 's/UINT_MAX/GRUB_UINT_MAX/g' \
+      -e 's/uintptr_t/grub_addr_t/g' \
+      -e 's/size_t/grub_size_t/g' \
+      -e 's/uint32_t/grub_uint32_t/g' \
+      -e 's/uint64_t/grub_uint64_t/g' \
+      -e 's/uint8_t/grub_uint8_t/g' \
+      -e 's/memset/grub_memset/g' \
+      -e 's/memcpy/grub_memcpy/g' \
+      -e 's/malloc/grub_malloc/g' \
+      -e 's/free/grub_free/g' \
+      -e 's/#elif _MSC_VER/#elif defined(_MSC_VER)/' \
+      grub-core/lib/argon2/@{*,blake2/*@}.@{c,h@} -i
+@end example
+
+Afterwards, you need to perform the following manual steps:
+
+@enumerate
+@item Remove all includes of standard library headers, "encoding.h" and
+      "thread.h".
+@item Add includes <grub/mm.h> and <grub/misc.h> to "argon2.h".
+@item Add include <grub/dl.h> and module license declaration to "argon2.c".
+@item Remove the following declarations and functions from "argon2.h" and
+     "argon2.c": argon2_type2string, argon2i_hash_encoded, argon2i_hash_raw,
+     argon2d_hash_encoded, argon2d_hash_raw, argon2id_hash_encoded,
+     argon2id_hash_raw, argon2_compare, argon2_verify, argon2i_verify,
+     argon2d_verify, argon2id_verify, argon2d_ctx, argon2i_ctx, argon2id_ctx,
+     argon2_verify_ctx, argon2d_verify_ctx, argon2i_verify_ctx,
+     argon2id_verify_ctx, argon2_encodedlen.
+@item Move the declaration of `clear_internal_memory()` in "blake2-impl.h" to
+      "blake2b.c".
+@item Remove code guarded by the ARGON2_NO_THREADS macro.
+@item Remove parameters `encoded` and `encodedlen` from `argon2_hash` and remove
+      the encoding block in that function.
+@item Remove parameter verifications in `validate_inputs()` for
+      ARGON2_MIN_PWD_LENGTH, ARGON2_MIN_SECRET, ARGON2_MIN_AD_LENGTH and
+      ARGON2_MAX_MEMORY to fix compiler warnings.
+@item Mark the function argon2_ctx as static.
+@end enumerate
+
 @node Gnulib
 @section Gnulib
 
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 8022e1c0a..3a004e88c 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1174,6 +1174,14 @@ module = {
   common = lib/json/json.c;
 };
 
+module = {
+  name = argon2;
+  common = lib/argon2/argon2.c;
+  common = lib/argon2/core.c;
+  common = lib/argon2/ref.c;
+  common = lib/argon2/blake2/blake2b.c;
+};
+
 module = {
   name = afsplitter;
   common = disk/AFSplitter.c;
diff --git a/grub-core/lib/argon2/LICENSE b/grub-core/lib/argon2/LICENSE
new file mode 100644
index 000000000..fa611f7ac
--- /dev/null
+++ b/grub-core/lib/argon2/LICENSE
@@ -0,0 +1,314 @@
+Argon2 reference source code package - reference C implementations
+
+Copyright 2015
+Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+
+You may use this work under the terms of a Creative Commons CC0 1.0 
+License/Waiver or the Apache Public License 2.0, at your option. The terms of
+these licenses can be found at:
+
+- CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+- Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+
+The terms of the licenses are reproduced below.
+
+--------------------------------------------------------------------------------
+
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+    CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+    LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+    ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+    INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+    REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+    PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+    THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+    HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+  i. the right to reproduce, adapt, distribute, perform, display,
+     communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+     likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+     subject to the limitations in paragraph 4(a), below;
+  v. rights protecting the extraction, dissemination, use and reuse of data
+     in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+     European Parliament and of the Council of 11 March 1996 on the legal
+     protection of databases, and under any national implementation
+     thereof, including any amended or successor version of such
+     directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+     world based on applicable law or treaty, and any national
+     implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+    surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+    warranties of any kind concerning the Work, express, implied,
+    statutory or otherwise, including without limitation warranties of
+    title, merchantability, fitness for a particular purpose, non
+    infringement, or the absence of latent or other defects, accuracy, or
+    the present or absence of errors, whether or not discoverable, all to
+    the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+    that may apply to the Work or any use thereof, including without
+    limitation any person's Copyright and Related Rights in the Work.
+    Further, Affirmer disclaims responsibility for obtaining any necessary
+    consents, permissions or other rights required for any use of the
+    Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+    party to this document and has no duty or obligation with respect to
+    this CC0 or use of the Work.
+
+--------------------------------------------------------------------------------
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
new file mode 100644
index 000000000..49532fe80
--- /dev/null
+++ b/grub-core/lib/argon2/argon2.c
@@ -0,0 +1,232 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#include <grub/dl.h>
+
+#include "argon2.h"
+#include "core.h"
+
+GRUB_MOD_LICENSE ("CC0");
+
+static int argon2_ctx(argon2_context *context, argon2_type type) {
+    /* 1. Validate all inputs */
+    int result = validate_inputs(context);
+    grub_uint32_t memory_blocks, segment_length;
+    argon2_instance_t instance;
+
+    if (ARGON2_OK != result) {
+        return result;
+    }
+
+    if (Argon2_d != type && Argon2_i != type && Argon2_id != type) {
+        return ARGON2_INCORRECT_TYPE;
+    }
+
+    /* 2. Align memory size */
+    /* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
+    memory_blocks = context->m_cost;
+
+    if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context->lanes) {
+        memory_blocks = 2 * ARGON2_SYNC_POINTS * context->lanes;
+    }
+
+    segment_length = memory_blocks / (context->lanes * ARGON2_SYNC_POINTS);
+    /* Ensure that all segments have equal length */
+    memory_blocks = segment_length * (context->lanes * ARGON2_SYNC_POINTS);
+
+    instance.version = context->version;
+    instance.memory = NULL;
+    instance.passes = context->t_cost;
+    instance.memory_blocks = memory_blocks;
+    instance.segment_length = segment_length;
+    instance.lane_length = segment_length * ARGON2_SYNC_POINTS;
+    instance.lanes = context->lanes;
+    instance.threads = context->threads;
+    instance.type = type;
+
+    if (instance.threads > instance.lanes) {
+        instance.threads = instance.lanes;
+    }
+
+    /* 3. Initialization: Hashing inputs, allocating memory, filling first
+     * blocks
+     */
+    result = initialize(&instance, context);
+
+    if (ARGON2_OK != result) {
+        return result;
+    }
+
+    /* 4. Filling memory */
+    result = fill_memory_blocks(&instance);
+
+    if (ARGON2_OK != result) {
+        return result;
+    }
+    /* 5. Finalization */
+    finalize(context, &instance);
+
+    return ARGON2_OK;
+}
+
+int argon2_hash(const grub_uint32_t t_cost, const grub_uint32_t m_cost,
+                const grub_uint32_t parallelism, const void *pwd,
+                const grub_size_t pwdlen, const void *salt, const grub_size_t saltlen,
+                void *hash, const grub_size_t hashlen, argon2_type type,
+                const grub_uint32_t version){
+
+    argon2_context context;
+    int result;
+    grub_uint8_t *out;
+
+    if (pwdlen > ARGON2_MAX_PWD_LENGTH) {
+        return ARGON2_PWD_TOO_LONG;
+    }
+
+    if (saltlen > ARGON2_MAX_SALT_LENGTH) {
+        return ARGON2_SALT_TOO_LONG;
+    }
+
+    if (hashlen > ARGON2_MAX_OUTLEN) {
+        return ARGON2_OUTPUT_TOO_LONG;
+    }
+
+    if (hashlen < ARGON2_MIN_OUTLEN) {
+        return ARGON2_OUTPUT_TOO_SHORT;
+    }
+
+    out = grub_malloc(hashlen);
+    if (!out) {
+        return ARGON2_MEMORY_ALLOCATION_ERROR;
+    }
+
+    context.out = (grub_uint8_t *)out;
+    context.outlen = (grub_uint32_t)hashlen;
+    context.pwd = CONST_CAST(grub_uint8_t *)pwd;
+    context.pwdlen = (grub_uint32_t)pwdlen;
+    context.salt = CONST_CAST(grub_uint8_t *)salt;
+    context.saltlen = (grub_uint32_t)saltlen;
+    context.secret = NULL;
+    context.secretlen = 0;
+    context.ad = NULL;
+    context.adlen = 0;
+    context.t_cost = t_cost;
+    context.m_cost = m_cost;
+    context.lanes = parallelism;
+    context.threads = parallelism;
+    context.allocate_cbk = NULL;
+    context.grub_free_cbk = NULL;
+    context.flags = ARGON2_DEFAULT_FLAGS;
+    context.version = version;
+
+    result = argon2_ctx(&context, type);
+
+    if (result != ARGON2_OK) {
+        clear_internal_memory(out, hashlen);
+        grub_free(out);
+        return result;
+    }
+
+    /* if raw hash requested, write it */
+    if (hash) {
+        grub_memcpy(hash, out, hashlen);
+    }
+
+    clear_internal_memory(out, hashlen);
+    grub_free(out);
+
+    return ARGON2_OK;
+}
+
+const char *argon2_error_message(int error_code) {
+    switch (error_code) {
+    case ARGON2_OK:
+        return "OK";
+    case ARGON2_OUTPUT_PTR_NULL:
+        return "Output pointer is NULL";
+    case ARGON2_OUTPUT_TOO_SHORT:
+        return "Output is too short";
+    case ARGON2_OUTPUT_TOO_LONG:
+        return "Output is too long";
+    case ARGON2_PWD_TOO_SHORT:
+        return "Password is too short";
+    case ARGON2_PWD_TOO_LONG:
+        return "Password is too long";
+    case ARGON2_SALT_TOO_SHORT:
+        return "Salt is too short";
+    case ARGON2_SALT_TOO_LONG:
+        return "Salt is too long";
+    case ARGON2_AD_TOO_SHORT:
+        return "Associated data is too short";
+    case ARGON2_AD_TOO_LONG:
+        return "Associated data is too long";
+    case ARGON2_SECRET_TOO_SHORT:
+        return "Secret is too short";
+    case ARGON2_SECRET_TOO_LONG:
+        return "Secret is too long";
+    case ARGON2_TIME_TOO_SMALL:
+        return "Time cost is too small";
+    case ARGON2_TIME_TOO_LARGE:
+        return "Time cost is too large";
+    case ARGON2_MEMORY_TOO_LITTLE:
+        return "Memory cost is too small";
+    case ARGON2_MEMORY_TOO_MUCH:
+        return "Memory cost is too large";
+    case ARGON2_LANES_TOO_FEW:
+        return "Too few lanes";
+    case ARGON2_LANES_TOO_MANY:
+        return "Too many lanes";
+    case ARGON2_PWD_PTR_MISMATCH:
+        return "Password pointer is NULL, but password length is not 0";
+    case ARGON2_SALT_PTR_MISMATCH:
+        return "Salt pointer is NULL, but salt length is not 0";
+    case ARGON2_SECRET_PTR_MISMATCH:
+        return "Secret pointer is NULL, but secret length is not 0";
+    case ARGON2_AD_PTR_MISMATCH:
+        return "Associated data pointer is NULL, but ad length is not 0";
+    case ARGON2_MEMORY_ALLOCATION_ERROR:
+        return "Memory allocation error";
+    case ARGON2_FREE_MEMORY_CBK_NULL:
+        return "The grub_free memory callback is NULL";
+    case ARGON2_ALLOCATE_MEMORY_CBK_NULL:
+        return "The allocate memory callback is NULL";
+    case ARGON2_INCORRECT_PARAMETER:
+        return "Argon2_Context context is NULL";
+    case ARGON2_INCORRECT_TYPE:
+        return "There is no such version of Argon2";
+    case ARGON2_OUT_PTR_MISMATCH:
+        return "Output pointer mismatch";
+    case ARGON2_THREADS_TOO_FEW:
+        return "Not enough threads";
+    case ARGON2_THREADS_TOO_MANY:
+        return "Too many threads";
+    case ARGON2_MISSING_ARGS:
+        return "Missing arguments";
+    case ARGON2_ENCODING_FAIL:
+        return "Encoding failed";
+    case ARGON2_DECODING_FAIL:
+        return "Decoding failed";
+    case ARGON2_THREAD_FAIL:
+        return "Threading failure";
+    case ARGON2_DECODING_LENGTH_FAIL:
+        return "Some of encoded parameters are too long or too short";
+    case ARGON2_VERIFY_MISMATCH:
+        return "The password does not match the supplied hash";
+    default:
+        return "Unknown error code";
+    }
+}
diff --git a/grub-core/lib/argon2/argon2.h b/grub-core/lib/argon2/argon2.h
new file mode 100644
index 000000000..129f7efbd
--- /dev/null
+++ b/grub-core/lib/argon2/argon2.h
@@ -0,0 +1,264 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef ARGON2_H
+#define ARGON2_H
+
+#include <grub/misc.h>
+#include <grub/mm.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Symbols visibility control */
+#ifdef A2_VISCTL
+#define ARGON2_PUBLIC __attribute__((visibility("default")))
+#define ARGON2_LOCAL __attribute__ ((visibility ("hidden")))
+#elif defined(_MSC_VER)
+#define ARGON2_PUBLIC __declspec(dllexport)
+#define ARGON2_LOCAL
+#else
+#define ARGON2_PUBLIC
+#define ARGON2_LOCAL
+#endif
+
+/*
+ * Argon2 input parameter restrictions
+ */
+
+/* Minimum and maximum number of lanes (degree of parallelism) */
+#define ARGON2_MIN_LANES GRUB_UINT32_C(1)
+#define ARGON2_MAX_LANES GRUB_UINT32_C(0xFFFFFF)
+
+/* Minimum and maximum number of threads */
+#define ARGON2_MIN_THREADS GRUB_UINT32_C(1)
+#define ARGON2_MAX_THREADS GRUB_UINT32_C(0xFFFFFF)
+
+/* Number of synchronization points between lanes per pass */
+#define ARGON2_SYNC_POINTS GRUB_UINT32_C(4)
+
+/* Minimum and maximum digest size in bytes */
+#define ARGON2_MIN_OUTLEN GRUB_UINT32_C(4)
+#define ARGON2_MAX_OUTLEN GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum number of memory blocks (each of BLOCK_SIZE bytes) */
+#define ARGON2_MIN_MEMORY (2 * ARGON2_SYNC_POINTS) /* 2 blocks per slice */
+
+#define ARGON2_MIN(a, b) ((a) < (b) ? (a) : (b))
+/* Max memory size is addressing-space/2, topping at 2^32 blocks (4 TB) */
+#define ARGON2_MAX_MEMORY_BITS                                                 \
+    ARGON2_MIN(GRUB_UINT32_C(32), (sizeof(void *) * GRUB_CHAR_BIT - 10 - 1))
+#define ARGON2_MAX_MEMORY                                                      \
+    ARGON2_MIN(GRUB_UINT32_C(0xFFFFFFFF), GRUB_UINT64_C(1) << ARGON2_MAX_MEMORY_BITS)
+
+/* Minimum and maximum number of passes */
+#define ARGON2_MIN_TIME GRUB_UINT32_C(1)
+#define ARGON2_MAX_TIME GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum password length in bytes */
+#define ARGON2_MIN_PWD_LENGTH GRUB_UINT32_C(0)
+#define ARGON2_MAX_PWD_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum associated data length in bytes */
+#define ARGON2_MIN_AD_LENGTH GRUB_UINT32_C(0)
+#define ARGON2_MAX_AD_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum salt length in bytes */
+#define ARGON2_MIN_SALT_LENGTH GRUB_UINT32_C(8)
+#define ARGON2_MAX_SALT_LENGTH GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Minimum and maximum key length in bytes */
+#define ARGON2_MIN_SECRET GRUB_UINT32_C(0)
+#define ARGON2_MAX_SECRET GRUB_UINT32_C(0xFFFFFFFF)
+
+/* Flags to determine which fields are securely wiped (default = no wipe). */
+#define ARGON2_DEFAULT_FLAGS GRUB_UINT32_C(0)
+#define ARGON2_FLAG_CLEAR_PASSWORD (GRUB_UINT32_C(1) << 0)
+#define ARGON2_FLAG_CLEAR_SECRET (GRUB_UINT32_C(1) << 1)
+
+/* Global flag to determine if we are wiping internal memory buffers. This flag
+ * is defined in core.c and defaults to 1 (wipe internal memory). */
+extern int FLAG_clear_internal_memory;
+
+/* Error codes */
+typedef enum Argon2_ErrorCodes {
+    ARGON2_OK = 0,
+
+    ARGON2_OUTPUT_PTR_NULL = -1,
+
+    ARGON2_OUTPUT_TOO_SHORT = -2,
+    ARGON2_OUTPUT_TOO_LONG = -3,
+
+    ARGON2_PWD_TOO_SHORT = -4,
+    ARGON2_PWD_TOO_LONG = -5,
+
+    ARGON2_SALT_TOO_SHORT = -6,
+    ARGON2_SALT_TOO_LONG = -7,
+
+    ARGON2_AD_TOO_SHORT = -8,
+    ARGON2_AD_TOO_LONG = -9,
+
+    ARGON2_SECRET_TOO_SHORT = -10,
+    ARGON2_SECRET_TOO_LONG = -11,
+
+    ARGON2_TIME_TOO_SMALL = -12,
+    ARGON2_TIME_TOO_LARGE = -13,
+
+    ARGON2_MEMORY_TOO_LITTLE = -14,
+    ARGON2_MEMORY_TOO_MUCH = -15,
+
+    ARGON2_LANES_TOO_FEW = -16,
+    ARGON2_LANES_TOO_MANY = -17,
+
+    ARGON2_PWD_PTR_MISMATCH = -18,    /* NULL ptr with non-zero length */
+    ARGON2_SALT_PTR_MISMATCH = -19,   /* NULL ptr with non-zero length */
+    ARGON2_SECRET_PTR_MISMATCH = -20, /* NULL ptr with non-zero length */
+    ARGON2_AD_PTR_MISMATCH = -21,     /* NULL ptr with non-zero length */
+
+    ARGON2_MEMORY_ALLOCATION_ERROR = -22,
+
+    ARGON2_FREE_MEMORY_CBK_NULL = -23,
+    ARGON2_ALLOCATE_MEMORY_CBK_NULL = -24,
+
+    ARGON2_INCORRECT_PARAMETER = -25,
+    ARGON2_INCORRECT_TYPE = -26,
+
+    ARGON2_OUT_PTR_MISMATCH = -27,
+
+    ARGON2_THREADS_TOO_FEW = -28,
+    ARGON2_THREADS_TOO_MANY = -29,
+
+    ARGON2_MISSING_ARGS = -30,
+
+    ARGON2_ENCODING_FAIL = -31,
+
+    ARGON2_DECODING_FAIL = -32,
+
+    ARGON2_THREAD_FAIL = -33,
+
+    ARGON2_DECODING_LENGTH_FAIL = -34,
+
+    ARGON2_VERIFY_MISMATCH = -35
+} argon2_error_codes;
+
+/* Memory allocator types --- for external allocation */
+typedef int (*allocate_fptr)(grub_uint8_t **memory, grub_size_t bytes_to_allocate);
+typedef void (*deallocate_fptr)(grub_uint8_t *memory, grub_size_t bytes_to_allocate);
+
+/* Argon2 external data structures */
+
+/*
+ *****
+ * Context: structure to hold Argon2 inputs:
+ *  output array and its length,
+ *  password and its length,
+ *  salt and its length,
+ *  secret and its length,
+ *  associated data and its length,
+ *  number of passes, amount of used memory (in KBytes, can be rounded up a bit)
+ *  number of parallel threads that will be run.
+ * All the parameters above affect the output hash value.
+ * Additionally, two function pointers can be provided to allocate and
+ * deallocate the memory (if NULL, memory will be allocated internally).
+ * Also, three flags indicate whether to erase password, secret as soon as they
+ * are pre-hashed (and thus not needed anymore), and the entire memory
+ *****
+ * Simplest situation: you have output array out[8], password is stored in
+ * pwd[32], salt is stored in salt[16], you do not have keys nor associated
+ * data. You need to spend 1 GB of RAM and you run 5 passes of Argon2d with
+ * 4 parallel lanes.
+ * You want to erase the password, but you're OK with last pass not being
+ * erased. You want to use the default memory allocator.
+ * Then you initialize:
+ Argon2_Context(out,8,pwd,32,salt,16,NULL,0,NULL,0,5,1<<20,4,4,NULL,NULL,true,false,false,false)
+ */
+typedef struct Argon2_Context {
+    grub_uint8_t *out;    /* output array */
+    grub_uint32_t outlen; /* digest length */
+
+    grub_uint8_t *pwd;    /* password array */
+    grub_uint32_t pwdlen; /* password length */
+
+    grub_uint8_t *salt;    /* salt array */
+    grub_uint32_t saltlen; /* salt length */
+
+    grub_uint8_t *secret;    /* key array */
+    grub_uint32_t secretlen; /* key length */
+
+    grub_uint8_t *ad;    /* associated data array */
+    grub_uint32_t adlen; /* associated data length */
+
+    grub_uint32_t t_cost;  /* number of passes */
+    grub_uint32_t m_cost;  /* amount of memory requested (KB) */
+    grub_uint32_t lanes;   /* number of lanes */
+    grub_uint32_t threads; /* maximum number of threads */
+
+    grub_uint32_t version; /* version number */
+
+    allocate_fptr allocate_cbk; /* pointer to memory allocator */
+    deallocate_fptr grub_free_cbk;   /* pointer to memory deallocator */
+
+    grub_uint32_t flags; /* array of bool options */
+} argon2_context;
+
+/* Argon2 primitive type */
+typedef enum Argon2_type {
+  Argon2_d = 0,
+  Argon2_i = 1,
+  Argon2_id = 2
+} argon2_type;
+
+/* Version of the algorithm */
+typedef enum Argon2_version {
+    ARGON2_VERSION_10 = 0x10,
+    ARGON2_VERSION_13 = 0x13,
+    ARGON2_VERSION_NUMBER = ARGON2_VERSION_13
+} argon2_version;
+
+/**
+ * Hashes a password with Argon2, producing a raw hash at @hash
+ * @param t_cost Number of iterations
+ * @param m_cost Sets memory usage to m_cost kibibytes
+ * @param parallelism Number of threads and compute lanes
+ * @param pwd Pointer to password
+ * @param pwdlen Password size in bytes
+ * @param salt Pointer to salt
+ * @param saltlen Salt size in bytes
+ * @param hash Buffer where to write the raw hash - updated by the function
+ * @param hashlen Desired length of the hash in bytes
+ * @pre   Different parallelism levels will give different results
+ * @pre   Returns ARGON2_OK if successful
+ */
+ARGON2_PUBLIC int argon2_hash(const grub_uint32_t t_cost, const grub_uint32_t m_cost,
+                              const grub_uint32_t parallelism, const void *pwd,
+                              const grub_size_t pwdlen, const void *salt,
+                              const grub_size_t saltlen, void *hash,
+                              const grub_size_t hashlen, argon2_type type,
+                              const grub_uint32_t version);
+
+/**
+ * Get the associated error message for given error code
+ * @return  The error message associated with the given error code
+ */
+ARGON2_PUBLIC const char *argon2_error_message(int error_code);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/grub-core/lib/argon2/blake2/blake2-impl.h b/grub-core/lib/argon2/blake2/blake2-impl.h
new file mode 100644
index 000000000..3a795680b
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blake2-impl.h
@@ -0,0 +1,151 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef PORTABLE_BLAKE2_IMPL_H
+#define PORTABLE_BLAKE2_IMPL_H
+
+#if defined(_MSC_VER)
+#define BLAKE2_INLINE __inline
+#elif defined(__GNUC__) || defined(__clang__)
+#define BLAKE2_INLINE __inline__
+#else
+#define BLAKE2_INLINE
+#endif
+
+/* Argon2 Team - Begin Code */
+/*
+   Not an exhaustive list, but should cover the majority of modern platforms
+   Additionally, the code will always be correct---this is only a performance
+   tweak.
+*/
+#if (defined(__BYTE_ORDER__) &&                                                \
+     (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) ||                           \
+    defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \
+    defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) ||       \
+    defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) ||                \
+    defined(_M_ARM)
+#define NATIVE_LITTLE_ENDIAN
+#endif
+/* Argon2 Team - End Code */
+
+static BLAKE2_INLINE grub_uint32_t load32(const void *src) {
+#if defined(NATIVE_LITTLE_ENDIAN)
+    grub_uint32_t w;
+    grub_memcpy(&w, src, sizeof w);
+    return w;
+#else
+    const grub_uint8_t *p = (const grub_uint8_t *)src;
+    grub_uint32_t w = *p++;
+    w |= (grub_uint32_t)(*p++) << 8;
+    w |= (grub_uint32_t)(*p++) << 16;
+    w |= (grub_uint32_t)(*p++) << 24;
+    return w;
+#endif
+}
+
+static BLAKE2_INLINE grub_uint64_t load64(const void *src) {
+#if defined(NATIVE_LITTLE_ENDIAN)
+    grub_uint64_t w;
+    grub_memcpy(&w, src, sizeof w);
+    return w;
+#else
+    const grub_uint8_t *p = (const grub_uint8_t *)src;
+    grub_uint64_t w = *p++;
+    w |= (grub_uint64_t)(*p++) << 8;
+    w |= (grub_uint64_t)(*p++) << 16;
+    w |= (grub_uint64_t)(*p++) << 24;
+    w |= (grub_uint64_t)(*p++) << 32;
+    w |= (grub_uint64_t)(*p++) << 40;
+    w |= (grub_uint64_t)(*p++) << 48;
+    w |= (grub_uint64_t)(*p++) << 56;
+    return w;
+#endif
+}
+
+static BLAKE2_INLINE void store32(void *dst, grub_uint32_t w) {
+#if defined(NATIVE_LITTLE_ENDIAN)
+    grub_memcpy(dst, &w, sizeof w);
+#else
+    grub_uint8_t *p = (grub_uint8_t *)dst;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+#endif
+}
+
+static BLAKE2_INLINE void store64(void *dst, grub_uint64_t w) {
+#if defined(NATIVE_LITTLE_ENDIAN)
+    grub_memcpy(dst, &w, sizeof w);
+#else
+    grub_uint8_t *p = (grub_uint8_t *)dst;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+#endif
+}
+
+static BLAKE2_INLINE grub_uint64_t load48(const void *src) {
+    const grub_uint8_t *p = (const grub_uint8_t *)src;
+    grub_uint64_t w = *p++;
+    w |= (grub_uint64_t)(*p++) << 8;
+    w |= (grub_uint64_t)(*p++) << 16;
+    w |= (grub_uint64_t)(*p++) << 24;
+    w |= (grub_uint64_t)(*p++) << 32;
+    w |= (grub_uint64_t)(*p++) << 40;
+    return w;
+}
+
+static BLAKE2_INLINE void store48(void *dst, grub_uint64_t w) {
+    grub_uint8_t *p = (grub_uint8_t *)dst;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+    w >>= 8;
+    *p++ = (grub_uint8_t)w;
+}
+
+static BLAKE2_INLINE grub_uint32_t rotr32(const grub_uint32_t w, const unsigned c) {
+    return (w >> c) | (w << (32 - c));
+}
+
+static BLAKE2_INLINE grub_uint64_t rotr64(const grub_uint64_t w, const unsigned c) {
+    return (w >> c) | (w << (64 - c));
+}
+
+#endif
diff --git a/grub-core/lib/argon2/blake2/blake2.h b/grub-core/lib/argon2/blake2/blake2.h
new file mode 100644
index 000000000..4e8efeb22
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blake2.h
@@ -0,0 +1,89 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef PORTABLE_BLAKE2_H
+#define PORTABLE_BLAKE2_H
+
+#include "../argon2.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+enum blake2b_constant {
+    BLAKE2B_BLOCKBYTES = 128,
+    BLAKE2B_OUTBYTES = 64,
+    BLAKE2B_KEYBYTES = 64,
+    BLAKE2B_SALTBYTES = 16,
+    BLAKE2B_PERSONALBYTES = 16
+};
+
+#pragma pack(push, 1)
+typedef struct __blake2b_param {
+    grub_uint8_t digest_length;                   /* 1 */
+    grub_uint8_t key_length;                      /* 2 */
+    grub_uint8_t fanout;                          /* 3 */
+    grub_uint8_t depth;                           /* 4 */
+    grub_uint32_t leaf_length;                    /* 8 */
+    grub_uint64_t node_offset;                    /* 16 */
+    grub_uint8_t node_depth;                      /* 17 */
+    grub_uint8_t inner_length;                    /* 18 */
+    grub_uint8_t reserved[14];                    /* 32 */
+    grub_uint8_t salt[BLAKE2B_SALTBYTES];         /* 48 */
+    grub_uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
+} blake2b_param;
+#pragma pack(pop)
+
+typedef struct __blake2b_state {
+    grub_uint64_t h[8];
+    grub_uint64_t t[2];
+    grub_uint64_t f[2];
+    grub_uint8_t buf[BLAKE2B_BLOCKBYTES];
+    unsigned buflen;
+    unsigned outlen;
+    grub_uint8_t last_node;
+} blake2b_state;
+
+/* Ensure param structs have not been wrongly padded */
+/* Poor man's static_assert */
+enum {
+    blake2_size_check_0 = 1 / !!(GRUB_CHAR_BIT == 8),
+    blake2_size_check_2 =
+        1 / !!(sizeof(blake2b_param) == sizeof(grub_uint64_t) * GRUB_CHAR_BIT)
+};
+
+/* Streaming API */
+ARGON2_LOCAL int blake2b_init(blake2b_state *S, grub_size_t outlen);
+ARGON2_LOCAL int blake2b_init_key(blake2b_state *S, grub_size_t outlen, const void *key,
+                     grub_size_t keylen);
+ARGON2_LOCAL int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
+ARGON2_LOCAL int blake2b_update(blake2b_state *S, const void *in, grub_size_t inlen);
+ARGON2_LOCAL int blake2b_final(blake2b_state *S, void *out, grub_size_t outlen);
+
+/* Simple API */
+ARGON2_LOCAL int blake2b(void *out, grub_size_t outlen, const void *in, grub_size_t inlen,
+                         const void *key, grub_size_t keylen);
+
+/* Argon2 Team - Begin Code */
+ARGON2_LOCAL int blake2b_long(void *out, grub_size_t outlen, const void *in, grub_size_t inlen);
+/* Argon2 Team - End Code */
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/grub-core/lib/argon2/blake2/blake2b.c b/grub-core/lib/argon2/blake2/blake2b.c
new file mode 100644
index 000000000..53abd7bef
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blake2b.c
@@ -0,0 +1,388 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#include "blake2.h"
+#include "blake2-impl.h"
+
+static const grub_uint64_t blake2b_IV[8] = {
+    GRUB_UINT64_C(0x6a09e667f3bcc908), GRUB_UINT64_C(0xbb67ae8584caa73b),
+    GRUB_UINT64_C(0x3c6ef372fe94f82b), GRUB_UINT64_C(0xa54ff53a5f1d36f1),
+    GRUB_UINT64_C(0x510e527fade682d1), GRUB_UINT64_C(0x9b05688c2b3e6c1f),
+    GRUB_UINT64_C(0x1f83d9abfb41bd6b), GRUB_UINT64_C(0x5be0cd19137e2179)};
+
+static const unsigned int blake2b_sigma[12][16] = {
+    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
+    {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
+    {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
+    {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
+    {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
+    {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
+    {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
+    {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
+    {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
+    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+    {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
+};
+
+void clear_internal_memory(void *v, grub_size_t n);
+
+static BLAKE2_INLINE void blake2b_set_lastnode(blake2b_state *S) {
+    S->f[1] = (grub_uint64_t)-1;
+}
+
+static BLAKE2_INLINE void blake2b_set_lastblock(blake2b_state *S) {
+    if (S->last_node) {
+        blake2b_set_lastnode(S);
+    }
+    S->f[0] = (grub_uint64_t)-1;
+}
+
+static BLAKE2_INLINE void blake2b_increment_counter(blake2b_state *S,
+                                                    grub_uint64_t inc) {
+    S->t[0] += inc;
+    S->t[1] += (S->t[0] < inc);
+}
+
+static BLAKE2_INLINE void blake2b_invalidate_state(blake2b_state *S) {
+    clear_internal_memory(S, sizeof(*S));      /* wipe */
+    blake2b_set_lastblock(S); /* invalidate for further use */
+}
+
+static BLAKE2_INLINE void blake2b_init0(blake2b_state *S) {
+    grub_memset(S, 0, sizeof(*S));
+    grub_memcpy(S->h, blake2b_IV, sizeof(S->h));
+}
+
+int blake2b_init_param(blake2b_state *S, const blake2b_param *P) {
+    const unsigned char *p = (const unsigned char *)P;
+    unsigned int i;
+
+    if (NULL == P || NULL == S) {
+        return -1;
+    }
+
+    blake2b_init0(S);
+    /* IV XOR Parameter Block */
+    for (i = 0; i < 8; ++i) {
+        S->h[i] ^= load64(&p[i * sizeof(S->h[i])]);
+    }
+    S->outlen = P->digest_length;
+    return 0;
+}
+
+/* Sequential blake2b initialization */
+int blake2b_init(blake2b_state *S, grub_size_t outlen) {
+    blake2b_param P;
+
+    if (S == NULL) {
+        return -1;
+    }
+
+    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
+        blake2b_invalidate_state(S);
+        return -1;
+    }
+
+    /* Setup Parameter Block for unkeyed BLAKE2 */
+    P.digest_length = (grub_uint8_t)outlen;
+    P.key_length = 0;
+    P.fanout = 1;
+    P.depth = 1;
+    P.leaf_length = 0;
+    P.node_offset = 0;
+    P.node_depth = 0;
+    P.inner_length = 0;
+    grub_memset(P.reserved, 0, sizeof(P.reserved));
+    grub_memset(P.salt, 0, sizeof(P.salt));
+    grub_memset(P.personal, 0, sizeof(P.personal));
+
+    return blake2b_init_param(S, &P);
+}
+
+int blake2b_init_key(blake2b_state *S, grub_size_t outlen, const void *key,
+                     grub_size_t keylen) {
+    blake2b_param P;
+
+    if (S == NULL) {
+        return -1;
+    }
+
+    if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) {
+        blake2b_invalidate_state(S);
+        return -1;
+    }
+
+    if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) {
+        blake2b_invalidate_state(S);
+        return -1;
+    }
+
+    /* Setup Parameter Block for keyed BLAKE2 */
+    P.digest_length = (grub_uint8_t)outlen;
+    P.key_length = (grub_uint8_t)keylen;
+    P.fanout = 1;
+    P.depth = 1;
+    P.leaf_length = 0;
+    P.node_offset = 0;
+    P.node_depth = 0;
+    P.inner_length = 0;
+    grub_memset(P.reserved, 0, sizeof(P.reserved));
+    grub_memset(P.salt, 0, sizeof(P.salt));
+    grub_memset(P.personal, 0, sizeof(P.personal));
+
+    if (blake2b_init_param(S, &P) < 0) {
+        blake2b_invalidate_state(S);
+        return -1;
+    }
+
+    {
+        grub_uint8_t block[BLAKE2B_BLOCKBYTES];
+        grub_memset(block, 0, BLAKE2B_BLOCKBYTES);
+        grub_memcpy(block, key, keylen);
+        blake2b_update(S, block, BLAKE2B_BLOCKBYTES);
+        /* Burn the key from stack */
+        clear_internal_memory(block, BLAKE2B_BLOCKBYTES);
+    }
+    return 0;
+}
+
+static void blake2b_compress(blake2b_state *S, const grub_uint8_t *block) {
+    grub_uint64_t m[16];
+    grub_uint64_t v[16];
+    unsigned int i, r;
+
+    for (i = 0; i < 16; ++i) {
+        m[i] = load64(block + i * sizeof(m[i]));
+    }
+
+    for (i = 0; i < 8; ++i) {
+        v[i] = S->h[i];
+    }
+
+    v[8] = blake2b_IV[0];
+    v[9] = blake2b_IV[1];
+    v[10] = blake2b_IV[2];
+    v[11] = blake2b_IV[3];
+    v[12] = blake2b_IV[4] ^ S->t[0];
+    v[13] = blake2b_IV[5] ^ S->t[1];
+    v[14] = blake2b_IV[6] ^ S->f[0];
+    v[15] = blake2b_IV[7] ^ S->f[1];
+
+#define G(r, i, a, b, c, d)                                                    \
+    do {                                                                       \
+        a = a + b + m[blake2b_sigma[r][2 * i + 0]];                            \
+        d = rotr64(d ^ a, 32);                                                 \
+        c = c + d;                                                             \
+        b = rotr64(b ^ c, 24);                                                 \
+        a = a + b + m[blake2b_sigma[r][2 * i + 1]];                            \
+        d = rotr64(d ^ a, 16);                                                 \
+        c = c + d;                                                             \
+        b = rotr64(b ^ c, 63);                                                 \
+    } while ((void)0, 0)
+
+#define ROUND(r)                                                               \
+    do {                                                                       \
+        G(r, 0, v[0], v[4], v[8], v[12]);                                      \
+        G(r, 1, v[1], v[5], v[9], v[13]);                                      \
+        G(r, 2, v[2], v[6], v[10], v[14]);                                     \
+        G(r, 3, v[3], v[7], v[11], v[15]);                                     \
+        G(r, 4, v[0], v[5], v[10], v[15]);                                     \
+        G(r, 5, v[1], v[6], v[11], v[12]);                                     \
+        G(r, 6, v[2], v[7], v[8], v[13]);                                      \
+        G(r, 7, v[3], v[4], v[9], v[14]);                                      \
+    } while ((void)0, 0)
+
+    for (r = 0; r < 12; ++r) {
+        ROUND(r);
+    }
+
+    for (i = 0; i < 8; ++i) {
+        S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
+    }
+
+#undef G
+#undef ROUND
+}
+
+int blake2b_update(blake2b_state *S, const void *in, grub_size_t inlen) {
+    const grub_uint8_t *pin = (const grub_uint8_t *)in;
+
+    if (inlen == 0) {
+        return 0;
+    }
+
+    /* Sanity check */
+    if (S == NULL || in == NULL) {
+        return -1;
+    }
+
+    /* Is this a reused state? */
+    if (S->f[0] != 0) {
+        return -1;
+    }
+
+    if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) {
+        /* Complete current block */
+        grub_size_t left = S->buflen;
+        grub_size_t fill = BLAKE2B_BLOCKBYTES - left;
+        grub_memcpy(&S->buf[left], pin, fill);
+        blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
+        blake2b_compress(S, S->buf);
+        S->buflen = 0;
+        inlen -= fill;
+        pin += fill;
+        /* Avoid buffer copies when possible */
+        while (inlen > BLAKE2B_BLOCKBYTES) {
+            blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
+            blake2b_compress(S, pin);
+            inlen -= BLAKE2B_BLOCKBYTES;
+            pin += BLAKE2B_BLOCKBYTES;
+        }
+    }
+    grub_memcpy(&S->buf[S->buflen], pin, inlen);
+    S->buflen += (unsigned int)inlen;
+    return 0;
+}
+
+int blake2b_final(blake2b_state *S, void *out, grub_size_t outlen) {
+    grub_uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
+    unsigned int i;
+
+    /* Sanity checks */
+    if (S == NULL || out == NULL || outlen < S->outlen) {
+        return -1;
+    }
+
+    /* Is this a reused state? */
+    if (S->f[0] != 0) {
+        return -1;
+    }
+
+    blake2b_increment_counter(S, S->buflen);
+    blake2b_set_lastblock(S);
+    grub_memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */
+    blake2b_compress(S, S->buf);
+
+    for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */
+        store64(buffer + sizeof(S->h[i]) * i, S->h[i]);
+    }
+
+    grub_memcpy(out, buffer, S->outlen);
+    clear_internal_memory(buffer, sizeof(buffer));
+    clear_internal_memory(S->buf, sizeof(S->buf));
+    clear_internal_memory(S->h, sizeof(S->h));
+    return 0;
+}
+
+int blake2b(void *out, grub_size_t outlen, const void *in, grub_size_t inlen,
+            const void *key, grub_size_t keylen) {
+    blake2b_state S;
+    int ret = -1;
+
+    /* Verify parameters */
+    if (NULL == in && inlen > 0) {
+        goto fail;
+    }
+
+    if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) {
+        goto fail;
+    }
+
+    if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) {
+        goto fail;
+    }
+
+    if (keylen > 0) {
+        if (blake2b_init_key(&S, outlen, key, keylen) < 0) {
+            goto fail;
+        }
+    } else {
+        if (blake2b_init(&S, outlen) < 0) {
+            goto fail;
+        }
+    }
+
+    if (blake2b_update(&S, in, inlen) < 0) {
+        goto fail;
+    }
+    ret = blake2b_final(&S, out, outlen);
+
+fail:
+    clear_internal_memory(&S, sizeof(S));
+    return ret;
+}
+
+/* Argon2 Team - Begin Code */
+int blake2b_long(void *pout, grub_size_t outlen, const void *in, grub_size_t inlen) {
+    grub_uint8_t *out = (grub_uint8_t *)pout;
+    blake2b_state blake_state;
+    grub_uint8_t outlen_bytes[sizeof(grub_uint32_t)] = {0};
+    int ret = -1;
+
+    if (outlen > GRUB_UINT32_MAX) {
+        goto fail;
+    }
+
+    /* Ensure little-endian byte order! */
+    store32(outlen_bytes, (grub_uint32_t)outlen);
+
+#define TRY(statement)                                                         \
+    do {                                                                       \
+        ret = statement;                                                       \
+        if (ret < 0) {                                                         \
+            goto fail;                                                         \
+        }                                                                      \
+    } while ((void)0, 0)
+
+    if (outlen <= BLAKE2B_OUTBYTES) {
+        TRY(blake2b_init(&blake_state, outlen));
+        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
+        TRY(blake2b_update(&blake_state, in, inlen));
+        TRY(blake2b_final(&blake_state, out, outlen));
+    } else {
+        grub_uint32_t toproduce;
+        grub_uint8_t out_buffer[BLAKE2B_OUTBYTES];
+        grub_uint8_t in_buffer[BLAKE2B_OUTBYTES];
+        TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES));
+        TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes)));
+        TRY(blake2b_update(&blake_state, in, inlen));
+        TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES));
+        grub_memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
+        out += BLAKE2B_OUTBYTES / 2;
+        toproduce = (grub_uint32_t)outlen - BLAKE2B_OUTBYTES / 2;
+
+        while (toproduce > BLAKE2B_OUTBYTES) {
+            grub_memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
+            TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer,
+                        BLAKE2B_OUTBYTES, NULL, 0));
+            grub_memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2);
+            out += BLAKE2B_OUTBYTES / 2;
+            toproduce -= BLAKE2B_OUTBYTES / 2;
+        }
+
+        grub_memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES);
+        TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL,
+                    0));
+        grub_memcpy(out, out_buffer, toproduce);
+    }
+fail:
+    clear_internal_memory(&blake_state, sizeof(blake_state));
+    return ret;
+#undef TRY
+}
+/* Argon2 Team - End Code */
diff --git a/grub-core/lib/argon2/blake2/blamka-round-ref.h b/grub-core/lib/argon2/blake2/blamka-round-ref.h
new file mode 100644
index 000000000..7f0071ada
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blamka-round-ref.h
@@ -0,0 +1,56 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef BLAKE_ROUND_MKA_H
+#define BLAKE_ROUND_MKA_H
+
+#include "blake2.h"
+#include "blake2-impl.h"
+
+/* designed by the Lyra PHC team */
+static BLAKE2_INLINE grub_uint64_t fBlaMka(grub_uint64_t x, grub_uint64_t y) {
+    const grub_uint64_t m = GRUB_UINT64_C(0xFFFFFFFF);
+    const grub_uint64_t xy = (x & m) * (y & m);
+    return x + y + 2 * xy;
+}
+
+#define G(a, b, c, d)                                                          \
+    do {                                                                       \
+        a = fBlaMka(a, b);                                                     \
+        d = rotr64(d ^ a, 32);                                                 \
+        c = fBlaMka(c, d);                                                     \
+        b = rotr64(b ^ c, 24);                                                 \
+        a = fBlaMka(a, b);                                                     \
+        d = rotr64(d ^ a, 16);                                                 \
+        c = fBlaMka(c, d);                                                     \
+        b = rotr64(b ^ c, 63);                                                 \
+    } while ((void)0, 0)
+
+#define BLAKE2_ROUND_NOMSG(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,   \
+                           v12, v13, v14, v15)                                 \
+    do {                                                                       \
+        G(v0, v4, v8, v12);                                                    \
+        G(v1, v5, v9, v13);                                                    \
+        G(v2, v6, v10, v14);                                                   \
+        G(v3, v7, v11, v15);                                                   \
+        G(v0, v5, v10, v15);                                                   \
+        G(v1, v6, v11, v12);                                                   \
+        G(v2, v7, v8, v13);                                                    \
+        G(v3, v4, v9, v14);                                                    \
+    } while ((void)0, 0)
+
+#endif
diff --git a/grub-core/lib/argon2/core.c b/grub-core/lib/argon2/core.c
new file mode 100644
index 000000000..0fe5b74cb
--- /dev/null
+++ b/grub-core/lib/argon2/core.c
@@ -0,0 +1,506 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+/*For memory wiping*/
+#ifdef _MSC_VER
+#include <windows.h>
+#include <winbase.h> /* For SecureZeroMemory */
+#endif
+#if defined __STDC_LIB_EXT1__
+#define __STDC_WANT_LIB_EXT1__ 1
+#endif
+#define VC_GE_2005(version) (version >= 1400)
+
+#include "core.h"
+#include "blake2/blake2.h"
+#include "blake2/blake2-impl.h"
+
+#ifdef GENKAT
+#include "genkat.h"
+#endif
+
+#if defined(__clang__)
+#if __has_attribute(optnone)
+#define NOT_OPTIMIZED __attribute__((optnone))
+#endif
+#elif defined(__GNUC__)
+#define GCC_VERSION                                                            \
+    (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#if GCC_VERSION >= 40400
+#define NOT_OPTIMIZED __attribute__((optimize("O0")))
+#endif
+#endif
+#ifndef NOT_OPTIMIZED
+#define NOT_OPTIMIZED
+#endif
+
+/***************Instance and Position constructors**********/
+void init_block_value(block *b, grub_uint8_t in) { grub_memset(b->v, in, sizeof(b->v)); }
+
+void copy_block(block *dst, const block *src) {
+    grub_memcpy(dst->v, src->v, sizeof(grub_uint64_t) * ARGON2_QWORDS_IN_BLOCK);
+}
+
+void xor_block(block *dst, const block *src) {
+    int i;
+    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
+        dst->v[i] ^= src->v[i];
+    }
+}
+
+static void load_block(block *dst, const void *input) {
+    unsigned i;
+    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
+        dst->v[i] = load64((const grub_uint8_t *)input + i * sizeof(dst->v[i]));
+    }
+}
+
+static void store_block(void *output, const block *src) {
+    unsigned i;
+    for (i = 0; i < ARGON2_QWORDS_IN_BLOCK; ++i) {
+        store64((grub_uint8_t *)output + i * sizeof(src->v[i]), src->v[i]);
+    }
+}
+
+/***************Memory functions*****************/
+
+int allocate_memory(const argon2_context *context, grub_uint8_t **memory,
+                    grub_size_t num, grub_size_t size) {
+    grub_size_t memory_size = num*size;
+    if (memory == NULL) {
+        return ARGON2_MEMORY_ALLOCATION_ERROR;
+    }
+
+    /* 1. Check for multiplication overflow */
+    if (size != 0 && memory_size / size != num) {
+        return ARGON2_MEMORY_ALLOCATION_ERROR;
+    }
+
+    /* 2. Try to allocate with appropriate allocator */
+    if (context->allocate_cbk) {
+        (context->allocate_cbk)(memory, memory_size);
+    } else {
+        *memory = grub_malloc(memory_size);
+    }
+
+    if (*memory == NULL) {
+        return ARGON2_MEMORY_ALLOCATION_ERROR;
+    }
+
+    return ARGON2_OK;
+}
+
+void grub_free_memory(const argon2_context *context, grub_uint8_t *memory,
+                 grub_size_t num, grub_size_t size) {
+    grub_size_t memory_size = num*size;
+    clear_internal_memory(memory, memory_size);
+    if (context->grub_free_cbk) {
+        (context->grub_free_cbk)(memory, memory_size);
+    } else {
+        grub_free(memory);
+    }
+}
+
+void NOT_OPTIMIZED secure_wipe_memory(void *v, grub_size_t n) {
+    static void *(*const volatile grub_memset_sec)(void *, int, grub_size_t) = &grub_memset;
+    grub_memset_sec(v, 0, n);
+}
+
+/* Memory clear flag defaults to true. */
+int FLAG_clear_internal_memory = 1;
+void clear_internal_memory(void *v, grub_size_t n) {
+  if (FLAG_clear_internal_memory && v) {
+    secure_wipe_memory(v, n);
+  }
+}
+
+void finalize(const argon2_context *context, argon2_instance_t *instance) {
+    if (context != NULL && instance != NULL) {
+        block blockhash;
+        grub_uint32_t l;
+
+        copy_block(&blockhash, instance->memory + instance->lane_length - 1);
+
+        /* XOR the last blocks */
+        for (l = 1; l < instance->lanes; ++l) {
+            grub_uint32_t last_block_in_lane =
+                l * instance->lane_length + (instance->lane_length - 1);
+            xor_block(&blockhash, instance->memory + last_block_in_lane);
+        }
+
+        /* Hash the result */
+        {
+            grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
+            store_block(blockhash_bytes, &blockhash);
+            blake2b_long(context->out, context->outlen, blockhash_bytes,
+                         ARGON2_BLOCK_SIZE);
+            /* clear blockhash and blockhash_bytes */
+            clear_internal_memory(blockhash.v, ARGON2_BLOCK_SIZE);
+            clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
+        }
+
+#ifdef GENKAT
+        print_tag(context->out, context->outlen);
+#endif
+
+        grub_free_memory(context, (grub_uint8_t *)instance->memory,
+                    instance->memory_blocks, sizeof(block));
+    }
+}
+
+grub_uint32_t index_alpha(const argon2_instance_t *instance,
+                     const argon2_position_t *position, grub_uint32_t pseudo_rand,
+                     int same_lane) {
+    /*
+     * Pass 0:
+     *      This lane : all already finished segments plus already constructed
+     * blocks in this segment
+     *      Other lanes : all already finished segments
+     * Pass 1+:
+     *      This lane : (SYNC_POINTS - 1) last segments plus already constructed
+     * blocks in this segment
+     *      Other lanes : (SYNC_POINTS - 1) last segments
+     */
+    grub_uint32_t reference_area_size;
+    grub_uint64_t relative_position;
+    grub_uint64_t start_position, absolute_position;
+
+    if (0 == position->pass) {
+        /* First pass */
+        if (0 == position->slice) {
+            /* First slice */
+            reference_area_size =
+                position->index - 1; /* all but the previous */
+        } else {
+            if (same_lane) {
+                /* The same lane => add current segment */
+                reference_area_size =
+                    position->slice * instance->segment_length +
+                    position->index - 1;
+            } else {
+                reference_area_size =
+                    position->slice * instance->segment_length +
+                    ((position->index == 0) ? (-1) : 0);
+            }
+        }
+    } else {
+        /* Second pass */
+        if (same_lane) {
+            reference_area_size = instance->lane_length -
+                                  instance->segment_length + position->index -
+                                  1;
+        } else {
+            reference_area_size = instance->lane_length -
+                                  instance->segment_length +
+                                  ((position->index == 0) ? (-1) : 0);
+        }
+    }
+
+    /* 1.2.4. Mapping pseudo_rand to 0..<reference_area_size-1> and produce
+     * relative position */
+    relative_position = pseudo_rand;
+    relative_position = relative_position * relative_position >> 32;
+    relative_position = reference_area_size - 1 -
+                        (reference_area_size * relative_position >> 32);
+
+    /* 1.2.5 Computing starting position */
+    start_position = 0;
+
+    if (0 != position->pass) {
+        start_position = (position->slice == ARGON2_SYNC_POINTS - 1)
+                             ? 0
+                             : (position->slice + 1) * instance->segment_length;
+    }
+
+    /* 1.2.6. Computing absolute position */
+    grub_divmod64 (start_position + relative_position, instance->lane_length,
+                   &absolute_position); /* absolute position */
+    return absolute_position;
+}
+
+/* Single-threaded version for p=1 case */
+static int fill_memory_blocks_st(argon2_instance_t *instance) {
+    grub_uint32_t r, s, l;
+
+    for (r = 0; r < instance->passes; ++r) {
+        for (s = 0; s < ARGON2_SYNC_POINTS; ++s) {
+            for (l = 0; l < instance->lanes; ++l) {
+                argon2_position_t position = {r, l, (grub_uint8_t)s, 0};
+                fill_segment(instance, position);
+            }
+        }
+#ifdef GENKAT
+        internal_kat(instance, r); /* Print all memory blocks */
+#endif
+    }
+    return ARGON2_OK;
+}
+
+int fill_memory_blocks(argon2_instance_t *instance) {
+	if (instance == NULL || instance->lanes == 0) {
+	    return ARGON2_INCORRECT_PARAMETER;
+    }
+    return fill_memory_blocks_st(instance);
+}
+
+int validate_inputs(const argon2_context *context) {
+    if (NULL == context) {
+        return ARGON2_INCORRECT_PARAMETER;
+    }
+
+    if (NULL == context->out) {
+        return ARGON2_OUTPUT_PTR_NULL;
+    }
+
+    /* Validate output length */
+    if (ARGON2_MIN_OUTLEN > context->outlen) {
+        return ARGON2_OUTPUT_TOO_SHORT;
+    }
+
+    if (ARGON2_MAX_OUTLEN < context->outlen) {
+        return ARGON2_OUTPUT_TOO_LONG;
+    }
+
+    /* Validate password (required param) */
+    if (NULL == context->pwd) {
+        if (0 != context->pwdlen) {
+            return ARGON2_PWD_PTR_MISMATCH;
+        }
+    }
+
+    if (ARGON2_MAX_PWD_LENGTH < context->pwdlen) {
+        return ARGON2_PWD_TOO_LONG;
+    }
+
+    /* Validate salt (required param) */
+    if (NULL == context->salt) {
+        if (0 != context->saltlen) {
+            return ARGON2_SALT_PTR_MISMATCH;
+        }
+    }
+
+    if (ARGON2_MIN_SALT_LENGTH > context->saltlen) {
+        return ARGON2_SALT_TOO_SHORT;
+    }
+
+    if (ARGON2_MAX_SALT_LENGTH < context->saltlen) {
+        return ARGON2_SALT_TOO_LONG;
+    }
+
+    /* Validate secret (optional param) */
+    if (NULL == context->secret) {
+        if (0 != context->secretlen) {
+            return ARGON2_SECRET_PTR_MISMATCH;
+        }
+    } else {
+        if (ARGON2_MAX_SECRET < context->secretlen) {
+            return ARGON2_SECRET_TOO_LONG;
+        }
+    }
+
+    /* Validate associated data (optional param) */
+    if (NULL == context->ad) {
+        if (0 != context->adlen) {
+            return ARGON2_AD_PTR_MISMATCH;
+        }
+    } else {
+        if (ARGON2_MAX_AD_LENGTH < context->adlen) {
+            return ARGON2_AD_TOO_LONG;
+        }
+    }
+
+    /* Validate memory cost */
+    if (ARGON2_MIN_MEMORY > context->m_cost) {
+        return ARGON2_MEMORY_TOO_LITTLE;
+    }
+
+    if (context->m_cost < 8 * context->lanes) {
+        return ARGON2_MEMORY_TOO_LITTLE;
+    }
+
+    /* Validate time cost */
+    if (ARGON2_MIN_TIME > context->t_cost) {
+        return ARGON2_TIME_TOO_SMALL;
+    }
+
+    if (ARGON2_MAX_TIME < context->t_cost) {
+        return ARGON2_TIME_TOO_LARGE;
+    }
+
+    /* Validate lanes */
+    if (ARGON2_MIN_LANES > context->lanes) {
+        return ARGON2_LANES_TOO_FEW;
+    }
+
+    if (ARGON2_MAX_LANES < context->lanes) {
+        return ARGON2_LANES_TOO_MANY;
+    }
+
+    /* Validate threads */
+    if (ARGON2_MIN_THREADS > context->threads) {
+        return ARGON2_THREADS_TOO_FEW;
+    }
+
+    if (ARGON2_MAX_THREADS < context->threads) {
+        return ARGON2_THREADS_TOO_MANY;
+    }
+
+    if (NULL != context->allocate_cbk && NULL == context->grub_free_cbk) {
+        return ARGON2_FREE_MEMORY_CBK_NULL;
+    }
+
+    if (NULL == context->allocate_cbk && NULL != context->grub_free_cbk) {
+        return ARGON2_ALLOCATE_MEMORY_CBK_NULL;
+    }
+
+    return ARGON2_OK;
+}
+
+void fill_first_blocks(grub_uint8_t *blockhash, const argon2_instance_t *instance) {
+    grub_uint32_t l;
+    /* Make the first and second block in each lane as G(H0||0||i) or
+       G(H0||1||i) */
+    grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
+    for (l = 0; l < instance->lanes; ++l) {
+
+        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0);
+        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l);
+        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
+                     ARGON2_PREHASH_SEED_LENGTH);
+        load_block(&instance->memory[l * instance->lane_length + 0],
+                   blockhash_bytes);
+
+        store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1);
+        blake2b_long(blockhash_bytes, ARGON2_BLOCK_SIZE, blockhash,
+                     ARGON2_PREHASH_SEED_LENGTH);
+        load_block(&instance->memory[l * instance->lane_length + 1],
+                   blockhash_bytes);
+    }
+    clear_internal_memory(blockhash_bytes, ARGON2_BLOCK_SIZE);
+}
+
+void initial_hash(grub_uint8_t *blockhash, argon2_context *context,
+                  argon2_type type) {
+    blake2b_state BlakeHash;
+    grub_uint8_t value[sizeof(grub_uint32_t)];
+
+    if (NULL == context || NULL == blockhash) {
+        return;
+    }
+
+    blake2b_init(&BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH);
+
+    store32(&value, context->lanes);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->outlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->m_cost);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->t_cost);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->version);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, (grub_uint32_t)type);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    store32(&value, context->pwdlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    if (context->pwd != NULL) {
+        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->pwd,
+                       context->pwdlen);
+
+        if (context->flags & ARGON2_FLAG_CLEAR_PASSWORD) {
+            secure_wipe_memory(context->pwd, context->pwdlen);
+            context->pwdlen = 0;
+        }
+    }
+
+    store32(&value, context->saltlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    if (context->salt != NULL) {
+        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->salt,
+                       context->saltlen);
+    }
+
+    store32(&value, context->secretlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    if (context->secret != NULL) {
+        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->secret,
+                       context->secretlen);
+
+        if (context->flags & ARGON2_FLAG_CLEAR_SECRET) {
+            secure_wipe_memory(context->secret, context->secretlen);
+            context->secretlen = 0;
+        }
+    }
+
+    store32(&value, context->adlen);
+    blake2b_update(&BlakeHash, (const grub_uint8_t *)&value, sizeof(value));
+
+    if (context->ad != NULL) {
+        blake2b_update(&BlakeHash, (const grub_uint8_t *)context->ad,
+                       context->adlen);
+    }
+
+    blake2b_final(&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH);
+}
+
+int initialize(argon2_instance_t *instance, argon2_context *context) {
+    grub_uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH];
+    int result = ARGON2_OK;
+
+    if (instance == NULL || context == NULL)
+        return ARGON2_INCORRECT_PARAMETER;
+    instance->context_ptr = context;
+
+    /* 1. Memory allocation */
+    result = allocate_memory(context, (grub_uint8_t **)&(instance->memory),
+                             instance->memory_blocks, sizeof(block));
+    if (result != ARGON2_OK) {
+        return result;
+    }
+
+    /* 2. Initial hashing */
+    /* H_0 + 8 extra bytes to produce the first blocks */
+    /* grub_uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */
+    /* Hashing all inputs */
+    initial_hash(blockhash, context, instance->type);
+    /* Zeroing 8 extra bytes */
+    clear_internal_memory(blockhash + ARGON2_PREHASH_DIGEST_LENGTH,
+                          ARGON2_PREHASH_SEED_LENGTH -
+                              ARGON2_PREHASH_DIGEST_LENGTH);
+
+#ifdef GENKAT
+    initial_kat(blockhash, context, instance->type);
+#endif
+
+    /* 3. Creating first blocks, we always have at least two blocks in a slice
+     */
+    fill_first_blocks(blockhash, instance);
+    /* Clearing the hash */
+    clear_internal_memory(blockhash, ARGON2_PREHASH_SEED_LENGTH);
+
+    return ARGON2_OK;
+}
diff --git a/grub-core/lib/argon2/core.h b/grub-core/lib/argon2/core.h
new file mode 100644
index 000000000..bbcd56998
--- /dev/null
+++ b/grub-core/lib/argon2/core.h
@@ -0,0 +1,228 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#ifndef ARGON2_CORE_H
+#define ARGON2_CORE_H
+
+#include "argon2.h"
+
+#define CONST_CAST(x) (x)(grub_addr_t)
+
+/**********************Argon2 internal constants*******************************/
+
+enum argon2_core_constants {
+    /* Memory block size in bytes */
+    ARGON2_BLOCK_SIZE = 1024,
+    ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8,
+    ARGON2_OWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 16,
+    ARGON2_HWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 32,
+    ARGON2_512BIT_WORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 64,
+
+    /* Number of pseudo-random values generated by one call to Blake in Argon2i
+       to
+       generate reference block positions */
+    ARGON2_ADDRESSES_IN_BLOCK = 128,
+
+    /* Pre-hashing digest length and its extension*/
+    ARGON2_PREHASH_DIGEST_LENGTH = 64,
+    ARGON2_PREHASH_SEED_LENGTH = 72
+};
+
+/*************************Argon2 internal data types***********************/
+
+/*
+ * Structure for the (1KB) memory block implemented as 128 64-bit words.
+ * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no
+ * bounds checking).
+ */
+typedef struct block_ { grub_uint64_t v[ARGON2_QWORDS_IN_BLOCK]; } block;
+
+/*****************Functions that work with the block******************/
+
+/* Initialize each byte of the block with @in */
+void init_block_value(block *b, grub_uint8_t in);
+
+/* Copy block @src to block @dst */
+void copy_block(block *dst, const block *src);
+
+/* XOR @src onto @dst bytewise */
+void xor_block(block *dst, const block *src);
+
+/*
+ * Argon2 instance: memory pointer, number of passes, amount of memory, type,
+ * and derived values.
+ * Used to evaluate the number and location of blocks to construct in each
+ * thread
+ */
+typedef struct Argon2_instance_t {
+    block *memory;          /* Memory pointer */
+    grub_uint32_t version;
+    grub_uint32_t passes;        /* Number of passes */
+    grub_uint32_t memory_blocks; /* Number of blocks in memory */
+    grub_uint32_t segment_length;
+    grub_uint32_t lane_length;
+    grub_uint32_t lanes;
+    grub_uint32_t threads;
+    argon2_type type;
+    int print_internals; /* whether to print the memory blocks */
+    argon2_context *context_ptr; /* points back to original context */
+} argon2_instance_t;
+
+/*
+ * Argon2 position: where we construct the block right now. Used to distribute
+ * work between threads.
+ */
+typedef struct Argon2_position_t {
+    grub_uint32_t pass;
+    grub_uint32_t lane;
+    grub_uint8_t slice;
+    grub_uint32_t index;
+} argon2_position_t;
+
+/*Struct that holds the inputs for thread handling FillSegment*/
+typedef struct Argon2_thread_data {
+    argon2_instance_t *instance_ptr;
+    argon2_position_t pos;
+} argon2_thread_data;
+
+/*************************Argon2 core functions********************************/
+
+/* Allocates memory to the given pointer, uses the appropriate allocator as
+ * specified in the context. Total allocated memory is num*size.
+ * @param context argon2_context which specifies the allocator
+ * @param memory pointer to the pointer to the memory
+ * @param size the size in bytes for each element to be allocated
+ * @param num the number of elements to be allocated
+ * @return ARGON2_OK if @memory is a valid pointer and memory is allocated
+ */
+int allocate_memory(const argon2_context *context, grub_uint8_t **memory,
+                    grub_size_t num, grub_size_t size);
+
+/*
+ * Frees memory at the given pointer, uses the appropriate deallocator as
+ * specified in the context. Also cleans the memory using clear_internal_memory.
+ * @param context argon2_context which specifies the deallocator
+ * @param memory pointer to buffer to be grub_freed
+ * @param size the size in bytes for each element to be deallocated
+ * @param num the number of elements to be deallocated
+ */
+void grub_free_memory(const argon2_context *context, grub_uint8_t *memory,
+                 grub_size_t num, grub_size_t size);
+
+/* Function that securely cleans the memory. This ignores any flags set
+ * regarding clearing memory. Usually one just calls clear_internal_memory.
+ * @param mem Pointer to the memory
+ * @param s Memory size in bytes
+ */
+void secure_wipe_memory(void *v, grub_size_t n);
+
+/* Function that securely clears the memory if FLAG_clear_internal_memory is
+ * set. If the flag isn't set, this function does nothing.
+ * @param mem Pointer to the memory
+ * @param s Memory size in bytes
+ */
+void clear_internal_memory(void *v, grub_size_t n);
+
+/*
+ * Computes absolute position of reference block in the lane following a skewed
+ * distribution and using a pseudo-random value as input
+ * @param instance Pointer to the current instance
+ * @param position Pointer to the current position
+ * @param pseudo_rand 32-bit pseudo-random value used to determine the position
+ * @param same_lane Indicates if the block will be taken from the current lane.
+ * If so we can reference the current segment
+ * @pre All pointers must be valid
+ */
+grub_uint32_t index_alpha(const argon2_instance_t *instance,
+                     const argon2_position_t *position, grub_uint32_t pseudo_rand,
+                     int same_lane);
+
+/*
+ * Function that validates all inputs against predefined restrictions and return
+ * an error code
+ * @param context Pointer to current Argon2 context
+ * @return ARGON2_OK if everything is all right, otherwise one of error codes
+ * (all defined in <argon2.h>
+ */
+int validate_inputs(const argon2_context *context);
+
+/*
+ * Hashes all the inputs into @a blockhash[PREHASH_DIGEST_LENGTH], clears
+ * password and secret if needed
+ * @param  context  Pointer to the Argon2 internal structure containing memory
+ * pointer, and parameters for time and space requirements.
+ * @param  blockhash Buffer for pre-hashing digest
+ * @param  type Argon2 type
+ * @pre    @a blockhash must have at least @a PREHASH_DIGEST_LENGTH bytes
+ * allocated
+ */
+void initial_hash(grub_uint8_t *blockhash, argon2_context *context,
+                  argon2_type type);
+
+/*
+ * Function creates first 2 blocks per lane
+ * @param instance Pointer to the current instance
+ * @param blockhash Pointer to the pre-hashing digest
+ * @pre blockhash must point to @a PREHASH_SEED_LENGTH allocated values
+ */
+void fill_first_blocks(grub_uint8_t *blockhash, const argon2_instance_t *instance);
+
+/*
+ * Function allocates memory, hashes the inputs with Blake,  and creates first
+ * two blocks. Returns the pointer to the main memory with 2 blocks per lane
+ * initialized
+ * @param  context  Pointer to the Argon2 internal structure containing memory
+ * pointer, and parameters for time and space requirements.
+ * @param  instance Current Argon2 instance
+ * @return Zero if successful, -1 if memory failed to allocate. @context->state
+ * will be modified if successful.
+ */
+int initialize(argon2_instance_t *instance, argon2_context *context);
+
+/*
+ * XORing the last block of each lane, hashing it, making the tag. Deallocates
+ * the memory.
+ * @param context Pointer to current Argon2 context (use only the out parameters
+ * from it)
+ * @param instance Pointer to current instance of Argon2
+ * @pre instance->state must point to necessary amount of memory
+ * @pre context->out must point to outlen bytes of memory
+ * @pre if context->grub_free_cbk is not NULL, it should point to a function that
+ * deallocates memory
+ */
+void finalize(const argon2_context *context, argon2_instance_t *instance);
+
+/*
+ * Function that fills the segment using previous segments also from other
+ * threads
+ * @param context current context
+ * @param instance Pointer to the current instance
+ * @param position Current position
+ * @pre all block pointers must be valid
+ */
+void fill_segment(const argon2_instance_t *instance,
+                  argon2_position_t position);
+
+/*
+ * Function that fills the entire memory t_cost times based on the first two
+ * blocks in each lane
+ * @param instance Pointer to the current instance
+ * @return ARGON2_OK if successful, @context->state
+ */
+int fill_memory_blocks(argon2_instance_t *instance);
+
+#endif
diff --git a/grub-core/lib/argon2/ref.c b/grub-core/lib/argon2/ref.c
new file mode 100644
index 000000000..c933df80d
--- /dev/null
+++ b/grub-core/lib/argon2/ref.c
@@ -0,0 +1,190 @@
+/*
+ * Argon2 reference source code package - reference C implementations
+ *
+ * Copyright 2015
+ * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
+ *
+ * You may use this work under the terms of a Creative Commons CC0 1.0
+ * License/Waiver or the Apache Public License 2.0, at your option. The terms of
+ * these licenses can be found at:
+ *
+ * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ * - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * You should have received a copy of both of these licenses along with this
+ * software. If not, they may be obtained at the above URLs.
+ */
+
+#include "argon2.h"
+#include "core.h"
+
+#include "blake2/blamka-round-ref.h"
+#include "blake2/blake2-impl.h"
+#include "blake2/blake2.h"
+
+
+/*
+ * Function fills a new memory block and optionally XORs the old block over the new one.
+ * @next_block must be initialized.
+ * @param prev_block Pointer to the previous block
+ * @param ref_block Pointer to the reference block
+ * @param next_block Pointer to the block to be constructed
+ * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
+ * @pre all block pointers must be valid
+ */
+static void fill_block(const block *prev_block, const block *ref_block,
+                       block *next_block, int with_xor) {
+    block blockR, block_tmp;
+    unsigned i;
+
+    copy_block(&blockR, ref_block);
+    xor_block(&blockR, prev_block);
+    copy_block(&block_tmp, &blockR);
+    /* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */
+    if (with_xor) {
+        /* Saving the next block contents for XOR over: */
+        xor_block(&block_tmp, next_block);
+        /* Now blockR = ref_block + prev_block and
+           block_tmp = ref_block + prev_block + next_block */
+    }
+
+    /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
+       (16,17,..31)... finally (112,113,...127) */
+    for (i = 0; i < 8; ++i) {
+        BLAKE2_ROUND_NOMSG(
+            blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],
+            blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],
+            blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],
+            blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],
+            blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],
+            blockR.v[16 * i + 15]);
+    }
+
+    /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then
+       (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */
+    for (i = 0; i < 8; i++) {
+        BLAKE2_ROUND_NOMSG(
+            blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],
+            blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],
+            blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],
+            blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],
+            blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],
+            blockR.v[2 * i + 113]);
+    }
+
+    copy_block(next_block, &block_tmp);
+    xor_block(next_block, &blockR);
+}
+
+static void next_addresses(block *address_block, block *input_block,
+                           const block *zero_block) {
+    input_block->v[6]++;
+    fill_block(zero_block, input_block, address_block, 0);
+    fill_block(zero_block, address_block, address_block, 0);
+}
+
+void fill_segment(const argon2_instance_t *instance,
+                  argon2_position_t position) {
+    block *ref_block = NULL, *curr_block = NULL;
+    block address_block, input_block, zero_block;
+    grub_uint64_t pseudo_rand, ref_index, ref_lane;
+    grub_uint32_t prev_offset, curr_offset;
+    grub_uint32_t starting_index;
+    grub_uint32_t i;
+    int data_independent_addressing;
+
+    if (instance == NULL) {
+        return;
+    }
+
+    data_independent_addressing =
+        (instance->type == Argon2_i) ||
+        (instance->type == Argon2_id && (position.pass == 0) &&
+         (position.slice < ARGON2_SYNC_POINTS / 2));
+
+    if (data_independent_addressing) {
+        init_block_value(&zero_block, 0);
+        init_block_value(&input_block, 0);
+
+        input_block.v[0] = position.pass;
+        input_block.v[1] = position.lane;
+        input_block.v[2] = position.slice;
+        input_block.v[3] = instance->memory_blocks;
+        input_block.v[4] = instance->passes;
+        input_block.v[5] = instance->type;
+    }
+
+    starting_index = 0;
+
+    if ((0 == position.pass) && (0 == position.slice)) {
+        starting_index = 2; /* we have already generated the first two blocks */
+
+        /* Don't forget to generate the first block of addresses: */
+        if (data_independent_addressing) {
+            next_addresses(&address_block, &input_block, &zero_block);
+        }
+    }
+
+    /* Offset of the current block */
+    curr_offset = position.lane * instance->lane_length +
+                  position.slice * instance->segment_length + starting_index;
+
+    if (0 == curr_offset % instance->lane_length) {
+        /* Last block in this lane */
+        prev_offset = curr_offset + instance->lane_length - 1;
+    } else {
+        /* Previous block */
+        prev_offset = curr_offset - 1;
+    }
+
+    for (i = starting_index; i < instance->segment_length;
+         ++i, ++curr_offset, ++prev_offset) {
+        /*1.1 Rotating prev_offset if needed */
+        if (curr_offset % instance->lane_length == 1) {
+            prev_offset = curr_offset - 1;
+        }
+
+        /* 1.2 Computing the index of the reference block */
+        /* 1.2.1 Taking pseudo-random value from the previous block */
+        if (data_independent_addressing) {
+            if (i % ARGON2_ADDRESSES_IN_BLOCK == 0) {
+                next_addresses(&address_block, &input_block, &zero_block);
+            }
+            pseudo_rand = address_block.v[i % ARGON2_ADDRESSES_IN_BLOCK];
+        } else {
+            pseudo_rand = instance->memory[prev_offset].v[0];
+        }
+
+        /* 1.2.2 Computing the lane of the reference block */
+        grub_divmod64 (pseudo_rand >> 32, instance->lanes, &ref_lane);
+
+        if ((position.pass == 0) && (position.slice == 0)) {
+            /* Can not reference other lanes yet */
+            ref_lane = position.lane;
+        }
+
+        /* 1.2.3 Computing the number of possible reference block within the
+         * lane.
+         */
+        position.index = i;
+        ref_index = index_alpha(instance, &position, pseudo_rand & 0xFFFFFFFF,
+                                ref_lane == position.lane);
+
+        /* 2 Creating a new block */
+        ref_block =
+            instance->memory + instance->lane_length * ref_lane + ref_index;
+        curr_block = instance->memory + curr_offset;
+        if (ARGON2_VERSION_10 == instance->version) {
+            /* version 1.2.1 and earlier: overwrite, not XOR */
+            fill_block(instance->memory + prev_offset, ref_block, curr_block, 0);
+        } else {
+            if(0 == position.pass) {
+                fill_block(instance->memory + prev_offset, ref_block,
+                           curr_block, 0);
+            } else {
+                fill_block(instance->memory + prev_offset, ref_block,
+                           curr_block, 1);
+            }
+        }
+    }
+}
-- 
2.32.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v4 4/5] luks2: Discern Argon2i and Argon2id
  2021-08-08 13:58   ` [PATCH v4 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
                       ` (2 preceding siblings ...)
  2021-08-08 13:58     ` [PATCH v4 3/5] argon2: Import reference implementation of Argon2 Patrick Steinhardt
@ 2021-08-08 13:58     ` Patrick Steinhardt
  2021-08-08 13:59     ` [PATCH v4 5/5] luks2: Support key derival via Argon2 Patrick Steinhardt
  4 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2021-08-08 13:58 UTC (permalink / raw)
  To: grub-devel
  Cc: Daniel Kiper, Leif Lindholm, agraf, pjones, mjg59, phcoder,
	Milan Broz, petr.vorel, Dmitry

[-- Attachment #1: Type: text/plain, Size: 2241 bytes --]

While GRUB is already able to parse both Argon2i and Argon2id parameters
from the LUKS2 header, it doesn't discern both types. This commit
introduces a new KDF type for Argon2id and sets up the parsed KDF's type
accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 grub-core/disk/luks2.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 371a53b83..02822c777 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -40,6 +40,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
 enum grub_luks2_kdf_type
 {
   LUKS2_KDF_TYPE_ARGON2I,
+  LUKS2_KDF_TYPE_ARGON2ID,
   LUKS2_KDF_TYPE_PBKDF2
 };
 typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t;
@@ -92,7 +93,7 @@ struct grub_luks2_keyslot
 	grub_int64_t time;
 	grub_int64_t memory;
 	grub_int64_t cpus;
-      } argon2i;
+      } argon2;
       struct
       {
 	const char   *hash;
@@ -162,10 +163,11 @@ luks2_parse_keyslot (grub_luks2_keyslot_t *out, const grub_json_t *keyslot)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing or invalid KDF");
   else if (!grub_strcmp (type, "argon2i") || !grub_strcmp (type, "argon2id"))
     {
-      out->kdf.type = LUKS2_KDF_TYPE_ARGON2I;
-      if (grub_json_getint64 (&out->kdf.u.argon2i.time, &kdf, "time") ||
-	  grub_json_getint64 (&out->kdf.u.argon2i.memory, &kdf, "memory") ||
-	  grub_json_getint64 (&out->kdf.u.argon2i.cpus, &kdf, "cpus"))
+      out->kdf.type = !grub_strcmp (type, "argon2i")
+		      ? LUKS2_KDF_TYPE_ARGON2I : LUKS2_KDF_TYPE_ARGON2ID;
+      if (grub_json_getint64 (&out->kdf.u.argon2.time, &kdf, "time") ||
+	  grub_json_getint64 (&out->kdf.u.argon2.memory, &kdf, "memory") ||
+	  grub_json_getint64 (&out->kdf.u.argon2.cpus, &kdf, "cpus"))
 	return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing Argon2i parameters");
     }
   else if (!grub_strcmp (type, "pbkdf2"))
@@ -445,6 +447,7 @@ luks2_decrypt_key (grub_uint8_t *out_key,
   switch (k->kdf.type)
     {
       case LUKS2_KDF_TYPE_ARGON2I:
+      case LUKS2_KDF_TYPE_ARGON2ID:
 	ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported");
 	goto err;
       case LUKS2_KDF_TYPE_PBKDF2:
-- 
2.32.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* [PATCH v4 5/5] luks2: Support key derival via Argon2
  2021-08-08 13:58   ` [PATCH v4 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
                       ` (3 preceding siblings ...)
  2021-08-08 13:58     ` [PATCH v4 4/5] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
@ 2021-08-08 13:59     ` Patrick Steinhardt
  4 siblings, 0 replies; 41+ messages in thread
From: Patrick Steinhardt @ 2021-08-08 13:59 UTC (permalink / raw)
  To: grub-devel
  Cc: Daniel Kiper, Leif Lindholm, agraf, pjones, mjg59, phcoder,
	Milan Broz, petr.vorel, Dmitry

[-- Attachment #1: Type: text/plain, Size: 3269 bytes --]

One addition with LUKS2 was support of the key derival function Argon2
in addition to the previously supported PBKDF2 algortihm. In order to
ease getting in initial support for LUKS2, we only reused infrastructure
to support LUKS2 with PBKDF2, but left out Argon2.

This commit now introduces support for Argon2 to enable decryption of
LUKS2 partitions using this key derival function. As the code for Argon2
has been added in a previous commit in this series, adding support is
now trivial.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 Makefile.util.def           |  6 +++++-
 grub-core/Makefile.core.def |  2 +-
 grub-core/disk/luks2.c      | 13 +++++++++++--
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/Makefile.util.def b/Makefile.util.def
index f8b356cc1..39fe9cb7c 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -3,7 +3,7 @@ AutoGen definitions Makefile.tpl;
 library = {
   name = libgrubkern.a;
   cflags = '$(CFLAGS_GNULIB)';
-  cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/grub-core/lib/json';
+  cppflags = '$(CPPFLAGS_GNULIB) -I$(srcdir)/grub-core/lib/json -I$(srcdir)/grub-core/lib/argon2';
 
   common = util/misc.c;
   common = grub-core/kern/command.c;
@@ -36,6 +36,10 @@ library = {
   common = grub-core/kern/misc.c;
   common = grub-core/kern/partition.c;
   common = grub-core/lib/crypto.c;
+  common = grub-core/lib/argon2/argon2.c;
+  common = grub-core/lib/argon2/core.c;
+  common = grub-core/lib/argon2/ref.c;
+  common = grub-core/lib/argon2/blake2/blake2b.c;
   common = grub-core/lib/json/json.c;
   common = grub-core/disk/luks.c;
   common = grub-core/disk/luks2.c;
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 3a004e88c..e5e5b216b 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1197,7 +1197,7 @@ module = {
   common = disk/luks2.c;
   common = lib/gnulib/base64.c;
   cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
-  cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json';
+  cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB) -I$(srcdir)/lib/json -I$(srcdir)/lib/argon2';
 };
 
 module = {
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 02822c777..2ec0d4116 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -27,6 +27,7 @@
 #include <grub/partition.h>
 #include <grub/i18n.h>
 
+#include <argon2.h>
 #include <base64.h>
 #include <json.h>
 
@@ -448,8 +449,16 @@ luks2_decrypt_key (grub_uint8_t *out_key,
     {
       case LUKS2_KDF_TYPE_ARGON2I:
       case LUKS2_KDF_TYPE_ARGON2ID:
-	ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported");
-	goto err;
+	ret = argon2_hash (k->kdf.u.argon2.time, k->kdf.u.argon2.memory, k->kdf.u.argon2.cpus,
+			   passphrase, passphraselen, salt, saltlen, area_key, k->area.key_size,
+			   k->kdf.type == LUKS2_KDF_TYPE_ARGON2I ? Argon2_i : Argon2_id,
+			   ARGON2_VERSION_NUMBER);
+        if (ret)
+	  {
+	    grub_dprintf ("luks2", "Argon2 failed: %s\n", argon2_error_message (ret));
+	    goto err;
+	  }
+        break;
       case LUKS2_KDF_TYPE_PBKDF2:
 	hash = grub_crypto_lookup_md_by_name (k->kdf.u.pbkdf2.hash);
 	if (!hash)
-- 
2.32.0


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply related	[flat|nested] 41+ messages in thread

* Re: [PATCH v4 1/5] kern: dl: Allow modules under CC0 license
  2021-08-08 13:58     ` [PATCH v4 1/5] kern: dl: Allow modules under CC0 license Patrick Steinhardt
@ 2021-08-08 15:03       ` Petr Vorel
  0 siblings, 0 replies; 41+ messages in thread
From: Petr Vorel @ 2021-08-08 15:03 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, Leif Lindholm, agraf, pjones, mjg59,
	phcoder, Milan Broz, Dmitry

Hi Patrick,

Reviewed-by: Petr Vorel <petr.vorel@gmail.com>

Kind regards,
Petr


^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2021-08-08 15:03 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-10 18:58 [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
2020-03-10 18:58 ` [PATCH v3 1/5] efi: Always try to allocate heap size of 1.6GB Patrick Steinhardt
2020-03-13 12:42   ` Daniel Kiper
2020-03-13 12:55   ` Leif Lindholm
2020-03-13 13:59     ` Daniel Kiper
2020-03-15 14:01       ` Patrick Steinhardt
2020-03-15 10:14     ` Patrick Steinhardt
2020-03-15 10:41     ` Patrick Steinhardt
2020-03-10 18:58 ` [PATCH v3 2/5] types.h: add UINT-related macros needed for Argon2 Patrick Steinhardt
2020-03-13 12:49   ` Daniel Kiper
2020-03-10 18:58 ` [PATCH v3 3/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
2020-03-10 20:44   ` Eli Schwartz
2020-03-10 21:42     ` Patrick Steinhardt
2020-03-13 13:13   ` Daniel Kiper
2020-03-16 17:21     ` Daniel Kiper
2020-03-16 17:52       ` Patrick Steinhardt
2020-03-16 20:03         ` Daniel Kiper
2020-03-17  5:51           ` Patrick Steinhardt
2020-03-17 10:45             ` Leif Lindholm
2020-03-16 19:57       ` Konrad Rzeszutek Wilk
2020-03-18 11:52         ` Patrick Steinhardt
2021-01-19  0:07   ` Petr Vorel
2021-01-19 11:10     ` Dmitry
2021-01-19 13:06       ` Petr Vorel
2021-01-19 15:42         ` Matt Turner
2021-01-19 19:03         ` Patrick Steinhardt
2021-01-19 19:31           ` Petr Vorel
2021-01-21 14:49             ` IS: GRUB release cycle: WAS: " Daniel Kiper
2021-01-21 21:30               ` Petr Vorel
2021-01-26 13:00                 ` Daniel Kiper
2021-01-26 19:57                   ` Petr Vorel
2021-08-08 13:58   ` [PATCH v4 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
2021-08-08 13:58     ` [PATCH v4 1/5] kern: dl: Allow modules under CC0 license Patrick Steinhardt
2021-08-08 15:03       ` Petr Vorel
2021-08-08 13:58     ` [PATCH v4 2/5] types.h: Add UINT-related macros needed for Argon2 Patrick Steinhardt
2021-08-08 13:58     ` [PATCH v4 3/5] argon2: Import reference implementation of Argon2 Patrick Steinhardt
2021-08-08 13:58     ` [PATCH v4 4/5] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
2021-08-08 13:59     ` [PATCH v4 5/5] luks2: Support key derival via Argon2 Patrick Steinhardt
2020-03-10 18:58 ` [PATCH v3 4/5] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
2020-03-10 18:58 ` [PATCH v3 5/5] luks2: Support key derival via Argon2 Patrick Steinhardt
2020-03-25 17:12 ` [PATCH v3 0/5] Support Argon2 KDF in LUKS2 Daniel Kiper

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.