All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Support Argon2 KDF in LUKS2
@ 2020-02-06 14:27 Patrick Steinhardt
  2020-02-06 14:27 ` [PATCH 1/5] efi: Allocate half of available memory by default Patrick Steinhardt
                   ` (6 more replies)
  0 siblings, 7 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-06 14:27 UTC (permalink / raw)
  To: grub-devel; +Cc: Patrick Steinhardt, Daniel Kiper

Hi,

as promised back when LUKS2 support was merged, here's the code that
enables decrypting LUKS2 partitions that use Argon2 as their key derival
function. Most of this is simple legwork, but I expect two things to be
potentially controversial:

    - I've changed how EFI allocates memory. On my test systems, I was
      only able to allocate roughly 800MB, which isn't enough for the
      default of 1GB memory parameter that cryptsetup uses with Argon2.
      Instead of taking a quarter of available memory, we now take half
      of it, which amounts to ~1.6GB on 32 bit systems.

    - The import of Argon2 itself. I've imported code from the
      cryptsetup project, but I've modified it quite a bit to fit into
      GRUB's codebase. This included both stripping off unneeded
      functionality as well as converting the code to use our own coding
      style. While it makes importing upstream fixes harder, I'd argue
      the code is still very similar in its structure and thus
      backporting should be easy enough.

Anyway. With these changes I'm able to successfully decrypt LUKS2
partitions making use of either PBKDF2, Argon2i or Argon2id.

Regards
Patrick

Patrick Steinhardt (5):
  efi: Allocate half of available memory by default
  argon2: Import Argon2 from cryptsetup
  disk: luks2: Add missing newline to debug message
  disk: luks2: Discern Argon2i and Argon2id
  disk: luks2: Support key derival via Argon2

 Makefile.util.def                             |   4 +-
 grub-core/Makefile.core.def                   |   8 +-
 grub-core/disk/luks2.c                        |  29 +-
 grub-core/kern/efi/mm.c                       |   4 +-
 grub-core/lib/argon2/argon2.c                 | 614 ++++++++++++++++++
 grub-core/lib/argon2/argon2.h                 |  65 ++
 grub-core/lib/argon2/blake2/blake2-impl.h     | 143 ++++
 grub-core/lib/argon2/blake2/blake2.h          |  81 +++
 grub-core/lib/argon2/blake2/blake2b.c         | 384 +++++++++++
 .../lib/argon2/blake2/blamka-round-ref.h      |  56 ++
 10 files changed, 1376 insertions(+), 12 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

-- 
2.25.0



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

* [PATCH 1/5] efi: Allocate half of available memory by default
  2020-02-06 14:27 [PATCH 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
@ 2020-02-06 14:27 ` Patrick Steinhardt
  2020-02-13 11:47   ` Leif Lindholm
  2020-02-06 14:27 ` [PATCH 2/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-06 14:27 UTC (permalink / raw)
  To: grub-devel; +Cc: Patrick Steinhardt, Daniel Kiper

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, let's thus increase the default and make half of
memory available, instead of a quarter only. This amounts to about
1600MB on above systems, which is sufficient for Argon2.

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

diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index b02fab1b1..d1f9d046b 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -599,10 +599,10 @@ 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 half of the available memory.  */
   total_pages = get_total_pages (filtered_memory_map, desc_size,
 				 filtered_memory_map_end);
-  required_pages = (total_pages >> 2);
+  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))
-- 
2.25.0



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

* [PATCH 2/5] argon2: Import Argon2 from cryptsetup
  2020-02-06 14:27 [PATCH 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
  2020-02-06 14:27 ` [PATCH 1/5] efi: Allocate half of available memory by default Patrick Steinhardt
@ 2020-02-06 14:27 ` Patrick Steinhardt
  2020-02-08 11:30   ` Milan Broz
  2020-02-06 14:27 ` [PATCH 3/5] disk: luks2: Add missing newline to debug message Patrick Steinhardt
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-06 14:27 UTC (permalink / raw)
  To: grub-devel; +Cc: Patrick Steinhardt, Daniel Kiper

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. The cryptsetup project was chosen as
upstream simply because it is the de-facto home of LUKS2, making us
bug-to-bug compatible with their Argon2 implementation.

As the cryptsetup project imported the code themselves from the
repository hosted at https://github.com/P-H-C/phc-winner-argon2, it is
licensed under a mixture of LGPLv2.1+ and 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 https://gitlab.com/cryptsetup/cryptsetup, tag
v2.3.0-rc0 (517da0dc6942b8a6038ada3c2fec7e20c2c0335c). It's not a 1:1
copy though, but instead the code was trimmed and adjusted to match
GRUB's needs and coding style. Most importantly:

    - Unneeded functionality like reading and writing encoded hashes
      was removed.

    - Optimized versions of both Argon2 and Blake2 were removed as they
      require AVX, which isn't necessarily available on all platforms.

    - The code was converted to use our own data types like
      grub_uint32_t and functions like grub_memset.

    - The code was adjusted to match our coding style.

That being said, the structure of functions themselves remains the same
and is easily recognized from upstream, so it should be trivial to
backport any upstream fixes.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 grub-core/Makefile.core.def                   |   6 +
 grub-core/lib/argon2/argon2.c                 | 614 ++++++++++++++++++
 grub-core/lib/argon2/argon2.h                 |  65 ++
 grub-core/lib/argon2/blake2/blake2-impl.h     | 143 ++++
 grub-core/lib/argon2/blake2/blake2.h          |  81 +++
 grub-core/lib/argon2/blake2/blake2b.c         | 384 +++++++++++
 .../lib/argon2/blake2/blamka-round-ref.h      |  56 ++
 7 files changed, 1349 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

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index a0507a1fa..b9e7a4171 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1181,6 +1181,12 @@ module = {
   common = lib/json/json.c;
 };
 
+module = {
+  name = argon2;
+  common = lib/argon2/argon2.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..1b8b092ae
--- /dev/null
+++ b/grub-core/lib/argon2/argon2.c
@@ -0,0 +1,614 @@
+/*
+ * Argon2 PBKDF2 library wrapper
+ *
+ * Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2016-2020 Milan Broz
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "argon2.h"
+#include "blake2/blamka-round-ref.h"
+#include "blake2/blake2-impl.h"
+#include "blake2/blake2.h"
+
+#include <grub/dl.h>
+#include <grub/mm.h>
+
+GRUB_MOD_LICENSE ("GPLv3");
+
+/* Minimum and maximum number of lanes (degree of parallelism) */
+#define ARGON2_MIN_LANES 1u
+#define ARGON2_MAX_LANES 0xFFFFFFu
+/* Minimum and maximum number of threads */
+#define ARGON2_MIN_THREADS 1u
+#define ARGON2_MAX_THREADS 0xFFFFFFu
+/* Number of synchronization points between lanes per pass */
+#define ARGON2_SYNC_POINTS 4u
+/* Minimum and maximum digest size in bytes */
+#define ARGON2_MIN_OUTLEN 4u
+/* Minimum and maximum number of passes */
+#define ARGON2_MIN_TIME 1u
+#define ARGON2_MAX_TIME 0xFFFFFFFFu
+/* Minimum and maximum password length in bytes */
+#define ARGON2_MAX_PWD_LENGTH 0xFFFFFFFFu
+/* Minimum and maximum salt length in bytes */
+#define ARGON2_MIN_SALT_LENGTH 8u
+
+/* Memory block size in bytes */
+#define ARGON2_BLOCK_SIZE 1024
+#define ARGON2_QWORDS_IN_BLOCK (ARGON2_BLOCK_SIZE / 8)
+/* Number of pseudo-random values generated by one call to Blake in Argon2i to generate reference block positions */
+#define ARGON2_ADDRESSES_IN_BLOCK 128
+/* Pre-hashing digest length and its extension*/
+#define ARGON2_PREHASH_DIGEST_LENGTH 64
+#define ARGON2_PREHASH_SEED_LENGTH 72
+
+typedef struct
+  {
+    grub_uint8_t       *out;      /* output array */
+    grub_uint32_t      outlen;    /* digest length */
+    const grub_uint8_t *pwd;      /* password array */
+    grub_uint32_t      pwdlen;    /* password length */
+    const 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 */
+  } argon2_context;
+
+typedef struct
+  {
+    grub_uint64_t v[ARGON2_QWORDS_IN_BLOCK];
+  } block;
+
+typedef struct
+  {
+    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;
+    grub_argon2_type type;
+  } argon2_instance_t;
+
+typedef struct
+  {
+    grub_uint32_t pass;
+    grub_uint32_t lane;
+    grub_uint8_t  slice;
+    grub_uint32_t index;
+  } argon2_position_t;
+
+static void init_block_value(block *b, grub_uint8_t in)
+  {
+    grub_memset (b->v, in, sizeof (b->v));
+  }
+
+static void copy_block(block *dst, const block *src)
+  {
+    grub_memcpy (dst->v, src->v, sizeof (grub_uint64_t) * ARGON2_QWORDS_IN_BLOCK);
+  }
+
+static 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]);
+  }
+
+static void finalize(const argon2_context *context, argon2_instance_t *instance)
+  {
+    grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
+    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 */
+    store_block (blockhash_bytes, &blockhash);
+    blake2b_long (context->out, context->outlen, blockhash_bytes, ARGON2_BLOCK_SIZE);
+    /* clear blockhash and blockhash_bytes */
+    grub_memset (blockhash.v, 0, ARGON2_BLOCK_SIZE);
+    grub_memset (blockhash_bytes, 0, ARGON2_BLOCK_SIZE);
+
+    grub_free (instance->memory);
+  }
+
+static grub_uint32_t index_alpha(const argon2_instance_t *instance,
+    const argon2_position_t *position, grub_uint32_t pseudo_rand,
+    int same_lane)
+  {
+    grub_uint32_t reference_area_size;
+    grub_uint64_t relative_position;
+    grub_uint32_t start_position, absolute_position;
+
+    /*
+     * 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
+     */
+    if (!position->pass)
+      {
+        /* First pass */
+        if (!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 (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;
+  }
+
+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);
+  }
+
+static 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;
+
+    data_independent_addressing =
+      (instance->type == GRUB_ARGON2_I) ||
+      (instance->type == GRUB_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 (!position.pass && !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 ((curr_offset % instance->lane_length) == 0)
+	/* 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 && !position.slice)
+	    /* 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 (instance->version == GRUB_ARGON2_VERSION_10)
+	  /* version 1.2.1 and earlier: overwrite, not XOR */
+	  fill_block (instance->memory + prev_offset, ref_block, curr_block, 0);
+	else
+	  {
+	    if (!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);
+	  }
+      }
+  }
+
+static void fill_memory_blocks(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);
+	      }
+  }
+
+static void fill_first_blocks(grub_uint8_t *blockhash, const argon2_instance_t *instance)
+  {
+    grub_uint8_t blockhash_bytes[ARGON2_BLOCK_SIZE];
+    grub_uint32_t l;
+
+    /* Make the first and second block in each lane as G(H0||0||i) or G(H0||1||i) */
+    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);
+      }
+    grub_memset(blockhash_bytes, 0, ARGON2_BLOCK_SIZE);
+  }
+
+static void initial_hash(grub_uint8_t *blockhash, argon2_context *context, grub_argon2_type type)
+  {
+    blake2b_state BlakeHash;
+    grub_uint8_t value[sizeof (grub_uint32_t)];
+
+    if (!context || !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)
+      blake2b_update (&BlakeHash, (const grub_uint8_t *)context->pwd, context->pwdlen);
+
+    store32 (&value, context->saltlen);
+    blake2b_update (&BlakeHash, (const grub_uint8_t *)&value, sizeof (value));
+
+    if (context->salt)
+      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)
+      blake2b_update (&BlakeHash, (const grub_uint8_t *)context->secret, context->secretlen);
+
+    store32 (&value, context->adlen);
+    blake2b_update (&BlakeHash, (const grub_uint8_t *)&value, sizeof (value));
+
+    if (context->ad)
+      blake2b_update (&BlakeHash, (const grub_uint8_t *)context->ad, context->adlen);
+
+    blake2b_final (&BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH);
+  }
+
+static int initialize(argon2_instance_t *instance, argon2_context *context)
+  {
+    grub_uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH];
+
+    /* 1. Memory allocation */
+    instance->memory = grub_malloc (instance->memory_blocks * sizeof (block));
+    if (!instance->memory)
+        return grub_error (GRUB_ERR_OUT_OF_MEMORY, "Could not allocate memory blocks for Argon2");
+
+    /* 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 */
+    grub_memset (blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0,
+		 ARGON2_PREHASH_SEED_LENGTH - ARGON2_PREHASH_DIGEST_LENGTH);
+
+    /* 3. Creating first blocks, we always have at least two blocks in a slice */
+    fill_first_blocks (blockhash, instance);
+    /* Clearing the hash */
+    grub_memset(blockhash, 0, ARGON2_PREHASH_SEED_LENGTH);
+
+    return GRUB_ERR_NONE;
+  }
+
+static int validate_inputs(const argon2_context *context)
+  {
+    if (!context->out || context->outlen < ARGON2_MIN_OUTLEN)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid out pointer passed to Argon2");
+    if (context->pwdlen > ARGON2_MAX_PWD_LENGTH)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid password passed to Argon2");
+    if (context->saltlen < ARGON2_MIN_SALT_LENGTH)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid salt passed to Argon2");
+    if (!context->secret && context->secretlen)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid secret passed to Argon2");
+    if (context->ad && !context->adlen)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid authenticated data passed to Argon2");
+    if (context->t_cost < ARGON2_MIN_TIME || context->t_cost > ARGON2_MAX_TIME)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid iteration count passed to Argon2");
+    if (context->lanes < ARGON2_MIN_LANES || context->lanes > ARGON2_MAX_LANES)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of lanes passed to Argon2");
+    if (context->threads < ARGON2_MIN_THREADS || context->threads > ARGON2_MAX_THREADS)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of threads passed to Argon2");
+    return GRUB_ERR_NONE;
+  }
+
+static int argon2_ctx(argon2_context *context, grub_argon2_type type)
+  {
+    grub_uint32_t memory_blocks, segment_length;
+    argon2_instance_t instance;
+    int result;
+
+    /* 1. Validate all inputs */
+    result = validate_inputs(context);
+    if (result != GRUB_ERR_NONE)
+      return result;
+
+    /* 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 (result != GRUB_ERR_NONE)
+      return result;
+
+    /* 4. Filling memory */
+    fill_memory_blocks(&instance);
+
+    /* 5. Finalization */
+    finalize(context, &instance);
+
+    return GRUB_ERR_NONE;
+  }
+
+grub_err_t grub_crypto_argon2(
+    const void *pwd, const grub_size_t pwdlen,
+    const void *salt, const grub_size_t saltlen,
+    grub_uint32_t iterations,
+    grub_uint32_t memory,
+    grub_uint32_t parallelism,
+    grub_argon2_type type,
+    grub_argon2_version version,
+    void *hash, const grub_size_t hashlen)
+  {
+    argon2_context context;
+
+    context.out = hash;
+    context.outlen = (grub_uint32_t)hashlen;
+    context.pwd = (grub_uint8_t *)pwd;
+    context.pwdlen = (grub_uint32_t)pwdlen;
+    context.salt = (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 = iterations;
+    context.m_cost = memory;
+    context.lanes = parallelism;
+    context.threads = parallelism;
+    context.version = version;
+
+    return argon2_ctx(&context, type);
+  }
diff --git a/grub-core/lib/argon2/argon2.h b/grub-core/lib/argon2/argon2.h
new file mode 100644
index 000000000..f8c149de7
--- /dev/null
+++ b/grub-core/lib/argon2/argon2.h
@@ -0,0 +1,65 @@
+/*
+ * 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 GRUB_ARGON2_H
+#define GRUB_ARGON2_H
+
+#include <grub/misc.h>
+
+/* Argon2 primitive type */
+typedef enum
+  {
+    GRUB_ARGON2_D  = 0,
+    GRUB_ARGON2_I  = 1,
+    GRUB_ARGON2_ID = 2
+  } grub_argon2_type;
+
+/* Version of the algorithm */
+typedef enum
+  {
+    GRUB_ARGON2_VERSION_10     = 0x10,
+    GRUB_ARGON2_VERSION_13     = 0x13,
+    GRUB_ARGON2_VERSION_NUMBER = GRUB_ARGON2_VERSION_13
+  } grub_argon2_version;
+
+/**
+ * Hashes a password with Argon2, producing a raw hash at @hash
+ * @param pwd Pointer to password
+ * @param pwdlen Password size in bytes
+ * @param salt Pointer to salt
+ * @param saltlen Salt size in bytes
+ * @param iterations Number of iterations
+ * @param memory Sets memory usage to memory kibibytes
+ * @param parallelism Number of threads and compute lanes
+ * @param type Type of Argon2 to use
+ * @param version Version of Argon2 to use
+ * @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 GRUB_ERR_NONE if successful
+ */
+grub_err_t grub_crypto_argon2(
+    const void *pwd, const grub_size_t pwdlen,
+    const void *salt, const grub_size_t saltlen,
+    grub_uint32_t iterations,
+    grub_uint32_t memory,
+    grub_uint32_t parallelism,
+    grub_argon2_type type,
+    grub_argon2_version version,
+    void *hash, const grub_size_t hashlen);
+
+#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..4f28741bc
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blake2-impl.h
@@ -0,0 +1,143 @@
+/*
+ * 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
+
+/* 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 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 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 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 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 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 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 inline grub_uint32_t rotr32(const grub_uint32_t w, const unsigned c) {
+    return (w >> c) | (w << (32 - c));
+}
+
+static 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..23a4fcd1f
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blake2.h
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+/* Streaming API */
+int blake2b_init(blake2b_state *S, grub_size_t outlen);
+int blake2b_init_key(blake2b_state *S, grub_size_t outlen, const void *key,
+                     grub_size_t keylen);
+int blake2b_init_param(blake2b_state *S, const blake2b_param *P);
+int blake2b_update(blake2b_state *S, const void *in, grub_size_t inlen);
+int blake2b_final(blake2b_state *S, void *out, grub_size_t outlen);
+
+/* Simple API */
+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 */
+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..580678cee
--- /dev/null
+++ b/grub-core/lib/argon2/blake2/blake2b.c
@@ -0,0 +1,384 @@
+/*
+ * 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/mm.h>
+
+#include "blake2.h"
+#include "blake2-impl.h"
+
+static const grub_uint64_t blake2b_IV[8] = {
+    0x6a09e667f3bcc908llu, 0xbb67ae8584caa73bllu,
+    0x3c6ef372fe94f82bllu, 0xa54ff53a5f1d36f1llu,
+    0x510e527fade682d1llu, 0x9b05688c2b3e6c1fllu,
+    0x1f83d9abfb41bd6bllu, 0x5be0cd19137e2179llu};
+
+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},
+};
+
+static inline void blake2b_set_lastnode(blake2b_state *S) {
+    S->f[1] = (grub_uint64_t)-1;
+}
+
+static inline void blake2b_set_lastblock(blake2b_state *S) {
+    if (S->last_node) {
+        blake2b_set_lastnode(S);
+    }
+    S->f[0] = (grub_uint64_t)-1;
+}
+
+static inline void blake2b_increment_counter(blake2b_state *S,
+                                                    grub_uint64_t inc) {
+    S->t[0] += inc;
+    S->t[1] += (S->t[0] < inc);
+}
+
+static inline void blake2b_invalidate_state(blake2b_state *S) {
+    grub_memset(S, 0, sizeof(*S));      /* wipe */
+    blake2b_set_lastblock(S); /* invalidate for further use */
+}
+
+static 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 */
+        grub_memset(block, 0, 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);
+    grub_memset(buffer, 0, sizeof(buffer));
+    grub_memset(S->buf, 0, sizeof(S->buf));
+    grub_memset(S->h, 0, 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:
+    grub_memset(&S, 0, 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;
+
+    /* 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:
+    grub_memset(&blake_state, 0, 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..e9fc90df6
--- /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 inline grub_uint64_t fBlaMka(grub_uint64_t x, grub_uint64_t y) {
+    const grub_uint64_t m = 0xFFFFFFFFu;
+    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
-- 
2.25.0



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

* [PATCH 3/5] disk: luks2: Add missing newline to debug message
  2020-02-06 14:27 [PATCH 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
  2020-02-06 14:27 ` [PATCH 1/5] efi: Allocate half of available memory by default Patrick Steinhardt
  2020-02-06 14:27 ` [PATCH 2/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
@ 2020-02-06 14:27 ` Patrick Steinhardt
  2020-02-11 21:36   ` Daniel Kiper
  2020-02-06 14:27 ` [PATCH 4/5] disk: luks2: Discern Argon2i and Argon2id Patrick Steinhardt
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-06 14:27 UTC (permalink / raw)
  To: grub-devel; +Cc: Patrick Steinhardt, Daniel Kiper

The debug message printed when decryption with a keyslot fails is
missing its trailing newline. Add it to avoid mangling it with
subsequent output.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 grub-core/disk/luks2.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 49ee9c862..65c4f0aac 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -610,7 +610,7 @@ luks2_recover_key (grub_disk_t disk,
 			       (const grub_uint8_t *) passphrase, grub_strlen (passphrase));
       if (ret)
 	{
-	  grub_dprintf ("luks2", "Decryption with keyslot %"PRIuGRUB_SIZE" failed", i);
+	  grub_dprintf ("luks2", "Decryption with keyslot %"PRIuGRUB_SIZE" failed\n", i);
 	  continue;
 	}
 
-- 
2.25.0



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

* [PATCH 4/5] disk: luks2: Discern Argon2i and Argon2id
  2020-02-06 14:27 [PATCH 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
                   ` (2 preceding siblings ...)
  2020-02-06 14:27 ` [PATCH 3/5] disk: luks2: Add missing newline to debug message Patrick Steinhardt
@ 2020-02-06 14:27 ` Patrick Steinhardt
  2020-02-06 14:27 ` [PATCH 5/5] disk: luks2: Support key derival via Argon2 Patrick Steinhardt
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-06 14:27 UTC (permalink / raw)
  To: grub-devel; +Cc: Patrick Steinhardt, 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>
---
 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.0



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

* [PATCH 5/5] disk: luks2: Support key derival via Argon2
  2020-02-06 14:27 [PATCH 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
                   ` (3 preceding siblings ...)
  2020-02-06 14:27 ` [PATCH 4/5] disk: luks2: Discern Argon2i and Argon2id Patrick Steinhardt
@ 2020-02-06 14:27 ` Patrick Steinhardt
  2020-02-11 21:53 ` [PATCH 0/5] Support Argon2 KDF in LUKS2 Daniel Kiper
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
  6 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-06 14:27 UTC (permalink / raw)
  To: grub-devel; +Cc: Patrick Steinhardt, 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>
---
 Makefile.util.def           |  4 +++-
 grub-core/Makefile.core.def |  2 +-
 grub-core/disk/luks2.c      | 14 ++++++++++++--
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/Makefile.util.def b/Makefile.util.def
index 94336392b..e0c98aa1c 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,8 @@ 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/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 b9e7a4171..914325369 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1202,7 +1202,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..9c5b416c4 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,17 @@ 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 = grub_crypto_argon2 (passphrase, passphraselen, salt, saltlen,
+				  k->kdf.u.argon2.time, k->kdf.u.argon2.memory, k->kdf.u.argon2.cpus,
+				  k->kdf.type == LUKS2_KDF_TYPE_ARGON2I ? GRUB_ARGON2_I : GRUB_ARGON2_ID,
+				  GRUB_ARGON2_VERSION_NUMBER,
+				  area_key, k->area.key_size);
+        if (ret)
+	  {
+	    grub_dprintf ("luks2", "Argon2 failed: %s\n", grub_errmsg);
+	    goto err;
+	  }
+        break;
       case LUKS2_KDF_TYPE_PBKDF2:
 	hash = grub_crypto_lookup_md_by_name (k->kdf.u.pbkdf2.hash);
 	if (!hash)
-- 
2.25.0



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

* Re: [PATCH 2/5] argon2: Import Argon2 from cryptsetup
  2020-02-06 14:27 ` [PATCH 2/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
@ 2020-02-08 11:30   ` Milan Broz
  2020-02-08 22:25     ` Patrick Steinhardt
  0 siblings, 1 reply; 32+ messages in thread
From: Milan Broz @ 2020-02-08 11:30 UTC (permalink / raw)
  To: The development of GNU GRUB, Patrick Steinhardt; +Cc: Daniel Kiper

Hi,

On 06/02/2020 15:27, 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. The cryptsetup project was chosen as
> upstream simply because it is the de-facto home of LUKS2, making us
> bug-to-bug compatible with their Argon2 implementation.
> 
> As the cryptsetup project imported the code themselves from the
> repository hosted at https://github.com/P-H-C/phc-winner-argon2, it is
> licensed under a mixture of LGPLv2.1+ and 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.

Well, it was a temporary solution as we (cryptsetup developers) are trying
to include Argon2 in OpenSSL (default crypto backend for cryptsetup) - and
perhaps in gcrypt later.

So if gcrypt includes Argon2 implementation in future, what is your plan?
Switch to it or keep this embedded copy still in place? Just asking :)
...

> diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
> new file mode 100644
> index 000000000..1b8b092ae
> --- /dev/null
> +++ b/grub-core/lib/argon2/argon2.c
> @@ -0,0 +1,614 @@
> +/*
> + * Argon2 PBKDF2 library wrapper
> + *
> + * Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
> + * Copyright (C) 2016-2020 Milan Broz

You are missing copyright of the original Argon2 authors here.
(This is apparently not the original wrapper code only but internal argon2 implementation.)

Anyway, this is interesting addition to GRUB2 (and people often asks
cryptsetup upstream about this). Thanks!

Milan


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

* Re: [PATCH 2/5] argon2: Import Argon2 from cryptsetup
  2020-02-08 11:30   ` Milan Broz
@ 2020-02-08 22:25     ` Patrick Steinhardt
  0 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-08 22:25 UTC (permalink / raw)
  To: Milan Broz; +Cc: The development of GNU GRUB, Daniel Kiper

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

On Sat, Feb 08, 2020 at 12:30:54PM +0100, Milan Broz wrote:
> On 06/02/2020 15:27, 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. The cryptsetup project was chosen as
> > upstream simply because it is the de-facto home of LUKS2, making us
> > bug-to-bug compatible with their Argon2 implementation.
> > 
> > As the cryptsetup project imported the code themselves from the
> > repository hosted at https://github.com/P-H-C/phc-winner-argon2, it is
> > licensed under a mixture of LGPLv2.1+ and 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.
> 
> Well, it was a temporary solution as we (cryptsetup developers) are trying
> to include Argon2 in OpenSSL (default crypto backend for cryptsetup) - and
> perhaps in gcrypt later.
> 
> So if gcrypt includes Argon2 implementation in future, what is your plan?
> Switch to it or keep this embedded copy still in place? Just asking :)
> ...

GRUB already uses libgcrypt for some stuff, so switching to an
implementation provided by it would most likely be the way to go as soon
as it got support for it.

> > diff --git a/grub-core/lib/argon2/argon2.c b/grub-core/lib/argon2/argon2.c
> > new file mode 100644
> > index 000000000..1b8b092ae
> > --- /dev/null
> > +++ b/grub-core/lib/argon2/argon2.c
> > @@ -0,0 +1,614 @@
> > +/*
> > + * Argon2 PBKDF2 library wrapper
> > + *
> > + * Copyright (C) 2016-2020 Red Hat, Inc. All rights reserved.
> > + * Copyright (C) 2016-2020 Milan Broz
> 
> You are missing copyright of the original Argon2 authors here.
> (This is apparently not the original wrapper code only but internal argon2 implementation.)

Oops, definitely, forgot to merge them in while collapsing files into
one. Thanks for the hint.

> Anyway, this is interesting addition to GRUB2 (and people often asks
> cryptsetup upstream about this). Thanks!
> 
> Milan

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

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

* Re: [PATCH 3/5] disk: luks2: Add missing newline to debug message
  2020-02-06 14:27 ` [PATCH 3/5] disk: luks2: Add missing newline to debug message Patrick Steinhardt
@ 2020-02-11 21:36   ` Daniel Kiper
  2020-02-12  7:48     ` Patrick Steinhardt
  0 siblings, 1 reply; 32+ messages in thread
From: Daniel Kiper @ 2020-02-11 21:36 UTC (permalink / raw)
  To: Patrick Steinhardt; +Cc: grub-devel, Daniel Kiper

On Thu, Feb 06, 2020 at 03:27:31PM +0100, Patrick Steinhardt wrote:
> The debug message printed when decryption with a keyslot fails is
> missing its trailing newline. Add it to avoid mangling it with
> subsequent output.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>

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

I will take it as a separate patch.

By the way, please use "luks2:" instead of "disk: luks2:" in the subject.

Daniel


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

* Re: [PATCH 0/5] Support Argon2 KDF in LUKS2
  2020-02-06 14:27 [PATCH 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
                   ` (4 preceding siblings ...)
  2020-02-06 14:27 ` [PATCH 5/5] disk: luks2: Support key derival via Argon2 Patrick Steinhardt
@ 2020-02-11 21:53 ` Daniel Kiper
  2020-02-12  7:18   ` Milan Broz
  2020-02-12  7:47   ` Patrick Steinhardt
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
  6 siblings, 2 replies; 32+ messages in thread
From: Daniel Kiper @ 2020-02-11 21:53 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

Adding Milan, Leif, Alex, Peter, Mathew and Vladimir.

On Thu, Feb 06, 2020 at 03:27:28PM +0100, Patrick Steinhardt wrote:
> Hi,
>
> as promised back when LUKS2 support was merged, here's the code that
> enables decrypting LUKS2 partitions that use Argon2 as their key derival
> function. Most of this is simple legwork, but I expect two things to be
> potentially controversial:
>
>     - I've changed how EFI allocates memory. On my test systems, I was
>       only able to allocate roughly 800MB, which isn't enough for the
>       default of 1GB memory parameter that cryptsetup uses with Argon2.
>       Instead of taking a quarter of available memory, we now take half
>       of it, which amounts to ~1.6GB on 32 bit systems.

That is huge for the bootloader. What about systems with less than 3 GiB of RAM?
Could we reduce amount of RAM required by Argon2?

>     - The import of Argon2 itself. I've imported code from the
>       cryptsetup project, but I've modified it quite a bit to fit into

Milan mentioned something about libgcrypt. Milan, when the Argon2 code
may land in libgcrypt?

>       GRUB's codebase. This included both stripping off unneeded
>       functionality as well as converting the code to use our own coding

Stripping unneeded functionality is OK. However, I think that it does
not make sense to convert coding style to the GRUB one. Especially if we
do not do that for other modules. So, I would leave coding style in
Argon2 module as is and save your precious minutes for something more
productive... ;-)

>       style. While it makes importing upstream fixes harder, I'd argue
>       the code is still very similar in its structure and thus
>       backporting should be easy enough.
>
> Anyway. With these changes I'm able to successfully decrypt LUKS2
> partitions making use of either PBKDF2, Argon2i or Argon2id.

I will take deeper dive into the code if we hammer out things listed above.

Daniel


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

* Re: [PATCH 0/5] Support Argon2 KDF in LUKS2
  2020-02-11 21:53 ` [PATCH 0/5] Support Argon2 KDF in LUKS2 Daniel Kiper
@ 2020-02-12  7:18   ` Milan Broz
  2020-02-20 19:34     ` Patrick Steinhardt
  2020-02-12  7:47   ` Patrick Steinhardt
  1 sibling, 1 reply; 32+ messages in thread
From: Milan Broz @ 2020-02-12  7:18 UTC (permalink / raw)
  To: Daniel Kiper, Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

On 11/02/2020 22:53, Daniel Kiper wrote:
> Adding Milan, Leif, Alex, Peter, Mathew and Vladimir.
> 
> On Thu, Feb 06, 2020 at 03:27:28PM +0100, Patrick Steinhardt wrote:
>> Hi,
>>
>> as promised back when LUKS2 support was merged, here's the code that
>> enables decrypting LUKS2 partitions that use Argon2 as their key derival
>> function. Most of this is simple legwork, but I expect two things to be
>> potentially controversial:
>>
>>     - I've changed how EFI allocates memory. On my test systems, I was
>>       only able to allocate roughly 800MB, which isn't enough for the
>>       default of 1GB memory parameter that cryptsetup uses with Argon2.
>>       Instead of taking a quarter of available memory, we now take half
>>       of it, which amounts to ~1.6GB on 32 bit systems.
> 
> That is huge for the bootloader. What about systems with less than 3 GiB of RAM?
> Could we reduce amount of RAM required by Argon2?

No, this is the principle of memory-hard function :)
The primary reason is to increase attacker cost for dictionary attacks.

Anyway, there are some limits in cryptsetup - we try to never use
more than half of physical memory and maximum is hard-compiled to 4GiB.

(But physical memory limit applies when formatting device, then
is stored in the LUKS2 keyslot header. So if you format it on device with
much larger RAM and it is later not available, it fails to open.
It is more complicated though - we have benchmark during format that prioritize
unlocking time, so PBKDF memory is usually decreased on low-memory systems anyway.)

> 
>>     - The import of Argon2 itself. I've imported code from the
>>       cryptsetup project, but I've modified it quite a bit to fit into
> 
> Milan mentioned something about libgcrypt. Milan, when the Argon2 code
> may land in libgcrypt?

Once we have volunteer to implement it / port it to gcrypt :-)

BTW if you have embedded Argon2 code, you should also add some test vectors
to your testsuite.
(You can use these we have in cryptsetup - see tests/crypto-vectors.c)

Milan


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

* Re: [PATCH 0/5] Support Argon2 KDF in LUKS2
  2020-02-11 21:53 ` [PATCH 0/5] Support Argon2 KDF in LUKS2 Daniel Kiper
  2020-02-12  7:18   ` Milan Broz
@ 2020-02-12  7:47   ` Patrick Steinhardt
  2020-02-13 11:42     ` Daniel Kiper
  1 sibling, 1 reply; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-12  7:47 UTC (permalink / raw)
  To: Daniel Kiper
  Cc: grub-devel, Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

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

On Tue, Feb 11, 2020 at 10:53:59PM +0100, Daniel Kiper wrote:
> >       GRUB's codebase. This included both stripping off unneeded
> >       functionality as well as converting the code to use our own coding
> 
> Stripping unneeded functionality is OK. However, I think that it does
> not make sense to convert coding style to the GRUB one. Especially if we
> do not do that for other modules. So, I would leave coding style in
> Argon2 module as is and save your precious minutes for something more
> productive... ;-)


Fair enough, I'll send out a v2 with the original coding style. I
thought as much when I was ready with v1, but was too lazy to do the
work and change back the coding style.

Anyway, to save myself another roundtrip: would you prefer to merge
Argon2 functionality into a single file like I've done it right now or
to retain the original set of files? The reason why I've opted for the
latter is mainly to be able to annotate more functions as static.

> >       style. While it makes importing upstream fixes harder, I'd argue
> >       the code is still very similar in its structure and thus
> >       backporting should be easy enough.
> >
> > Anyway. With these changes I'm able to successfully decrypt LUKS2
> > partitions making use of either PBKDF2, Argon2i or Argon2id.
> 
> I will take deeper dive into the code if we hammer out things listed above.

Cool, thanks!

Patrick

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

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

* Re: [PATCH 3/5] disk: luks2: Add missing newline to debug message
  2020-02-11 21:36   ` Daniel Kiper
@ 2020-02-12  7:48     ` Patrick Steinhardt
  0 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-12  7:48 UTC (permalink / raw)
  To: Daniel Kiper; +Cc: grub-devel, Daniel Kiper

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

On Tue, Feb 11, 2020 at 10:36:22PM +0100, Daniel Kiper wrote:
> On Thu, Feb 06, 2020 at 03:27:31PM +0100, Patrick Steinhardt wrote:
> > The debug message printed when decryption with a keyslot fails is
> > missing its trailing newline. Add it to avoid mangling it with
> > subsequent output.
> >
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> 
> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
> 
> I will take it as a separate patch.
> 
> By the way, please use "luks2:" instead of "disk: luks2:" in the subject.

Will do!

Patrick

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

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

* Re: [PATCH 0/5] Support Argon2 KDF in LUKS2
  2020-02-12  7:47   ` Patrick Steinhardt
@ 2020-02-13 11:42     ` Daniel Kiper
  2020-02-20 14:50       ` Patrick Steinhardt
  0 siblings, 1 reply; 32+ messages in thread
From: Daniel Kiper @ 2020-02-13 11:42 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

On Wed, Feb 12, 2020 at 08:47:49AM +0100, Patrick Steinhardt wrote:
> On Tue, Feb 11, 2020 at 10:53:59PM +0100, Daniel Kiper wrote:
> > >       GRUB's codebase. This included both stripping off unneeded
> > >       functionality as well as converting the code to use our own coding
> >
> > Stripping unneeded functionality is OK. However, I think that it does
> > not make sense to convert coding style to the GRUB one. Especially if we
> > do not do that for other modules. So, I would leave coding style in
> > Argon2 module as is and save your precious minutes for something more
> > productive... ;-)
>
>
> Fair enough, I'll send out a v2 with the original coding style. I
> thought as much when I was ready with v1, but was too lazy to do the
> work and change back the coding style.
>
> Anyway, to save myself another roundtrip: would you prefer to merge
> Argon2 functionality into a single file like I've done it right now or
> to retain the original set of files? The reason why I've opted for the
> latter is mainly to be able to annotate more functions as static.

I think that you should retain original set of files. And please add
a description to the docs/grub-dev.texi how to update Argon2 lib in
the future.

Daniel


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

* Re: [PATCH 1/5] efi: Allocate half of available memory by default
  2020-02-06 14:27 ` [PATCH 1/5] efi: Allocate half of available memory by default Patrick Steinhardt
@ 2020-02-13 11:47   ` Leif Lindholm
  2020-02-20 19:29     ` Patrick Steinhardt
  0 siblings, 1 reply; 32+ messages in thread
From: Leif Lindholm @ 2020-02-13 11:47 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Patrick Steinhardt, Daniel Kiper

On Thu, Feb 06, 2020 at 15:27:29 +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, let's thus increase the default and make half of
> memory available, instead of a quarter only. This amounts to about
> 1600MB on above systems, which is sufficient for Argon2.

I was never a huge fan of the "grab a percentage of RAM" in the first
place, and I think "grab twice that" is not the best solution here.

(Real) corner cases that would be affected by this are:
1) chainloading grub from grub
2) OS loaders (loaded by GRUB) requiring large amounts of RAM before
   ExitBootsevices().

If you have a known minimum requirement, can we work towards that
instead?
For a least-invasive approach, that could be something like
- rename required_pages target_heap_pages
- add a required_pages var initialized to ... something real
and then

  if (target_heap_size < required_pages)
    target_heap_pages = required_pages.

The MIN/MAX heap size could move into the "something real"
calculation, getting rid of the current (arbitrary) clamping of
MAX_HEAP_SIZE to 1.6G..

/
    Leif

> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  grub-core/kern/efi/mm.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
> index b02fab1b1..d1f9d046b 100644
> --- a/grub-core/kern/efi/mm.c
> +++ b/grub-core/kern/efi/mm.c
> @@ -599,10 +599,10 @@ 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 half of the available memory.  */
>    total_pages = get_total_pages (filtered_memory_map, desc_size,
>  				 filtered_memory_map_end);
> -  required_pages = (total_pages >> 2);
> +  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))
> -- 
> 2.25.0
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


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

* Re: [PATCH 0/5] Support Argon2 KDF in LUKS2
  2020-02-13 11:42     ` Daniel Kiper
@ 2020-02-20 14:50       ` Patrick Steinhardt
  0 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 14:50 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

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

On Thu, Feb 13, 2020 at 12:42:59PM +0100, Daniel Kiper wrote:
> On Wed, Feb 12, 2020 at 08:47:49AM +0100, Patrick Steinhardt wrote:
> > On Tue, Feb 11, 2020 at 10:53:59PM +0100, Daniel Kiper wrote:
> > > >       GRUB's codebase. This included both stripping off unneeded
> > > >       functionality as well as converting the code to use our own coding
> > >
> > > Stripping unneeded functionality is OK. However, I think that it does
> > > not make sense to convert coding style to the GRUB one. Especially if we
> > > do not do that for other modules. So, I would leave coding style in
> > > Argon2 module as is and save your precious minutes for something more
> > > productive... ;-)
> >
> >
> > Fair enough, I'll send out a v2 with the original coding style. I
> > thought as much when I was ready with v1, but was too lazy to do the
> > work and change back the coding style.
> >
> > Anyway, to save myself another roundtrip: would you prefer to merge
> > Argon2 functionality into a single file like I've done it right now or
> > to retain the original set of files? The reason why I've opted for the
> > latter is mainly to be able to annotate more functions as static.
> 
> I think that you should retain original set of files. And please add
> a description to the docs/grub-dev.texi how to update Argon2 lib in
> the future.
> 
> Daniel

In the ideal case, we'd just compile Argon2 with the POSIX compat layer
so that we wouldn't need to modify most of the types and functions used
by it, like uint32, malloc, etc. As a result, libgrubkern.a would grow a
dependency on C{,PP}FLAGS_POSIX, though. I did notice compilation errors
in other modules when trying that, so my question is which path to go:
fix resulting incompatibilities when adding POSIX includes or just
replace types and function calls in Argon2 code?

Patrick

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

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

* [PATCH v2 0/6] Support Argon2 KDF in LUKS2
  2020-02-06 14:27 [PATCH 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
                   ` (5 preceding siblings ...)
  2020-02-11 21:53 ` [PATCH 0/5] Support Argon2 KDF in LUKS2 Daniel Kiper
@ 2020-02-20 18:00 ` Patrick Steinhardt
  2020-02-20 18:00   ` [PATCH v2 1/6] efi: Allocate half of available memory by default Patrick Steinhardt
                     ` (7 more replies)
  6 siblings, 8 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 18:00 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, gmazyland, leif, agraf, pjones,
	mjg59, phcoder

Hi,

this is the second version of my patchset to add support for Argon2
encryption keys for LUKS2.

The most important change is that I've now verbosely imported the argon2
code from the official reference implementation instead of from the
cryptsetup project. The diff between both isn't that big in the end, and
including from crypsetup's upstream seems a bit cleaner to me. There
were several transformations required to use GRUB's types and functions
as well as stripping of unused stuff, which I've now documented the dev
manual. This also fixes my previously mistaken license headers.

One thing I'm not sure about here is whether it's fine to declare the
argon2 mod's license as GPLv3. The code is licensed under CC0/Apache
2.0, where the latter is compatible with GPLv3. But I don't know whether
it's legit to just say "Yeah, this mod is a GPLv3 one".

I didn't address the comment made by Leif yet with regards to grabbing
memory. I ain't got much of a clue of GRUB's memory subsystem, so I'd
gladly accept help there. Otherwise I'll have to dig a bit deeper.

The range diff compared to the previous version of this patch set is
attached to this mail.

Patrick


Patrick Steinhardt (6):
  efi: Allocate half of available memory by default
  types.h: add UINT-related macros needed for Argon2
  argon2: Import Argon2 from cryptsetup
  luks2: Add missing newline to debug message
  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                        |  28 +-
 grub-core/kern/efi/mm.c                       |   4 +-
 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, 2231 insertions(+), 12 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 v1:
1:  53cdfdc27 = 1:  15bdf830e efi: Allocate half of available memory by default
2:  c55946ca5 < -:  --------- argon2: Import Argon2 from cryptsetup
-:  --------- > 2:  e81db7d95 types.h: add UINT-related macros needed for Argon2
-:  --------- > 3:  50aff9670 argon2: Import Argon2 from cryptsetup
3:  c17cd2197 ! 4:  af3f85665 disk: luks2: Add missing newline to debug message
    @@ Metadata
     Author: Patrick Steinhardt <ps@pks.im>
     
      ## Commit message ##
    -    disk: luks2: Add missing newline to debug message
    +    luks2: Add missing newline to debug message
     
         The debug message printed when decryption with a keyslot fails is
         missing its trailing newline. Add it to avoid mangling it with
         subsequent output.
     
         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: luks2_recover_key (grub_disk_t disk,
4:  390728cea ! 5:  89abe827b disk: luks2: Discern Argon2i and Argon2id
    @@ Metadata
     Author: Patrick Steinhardt <ps@pks.im>
     
      ## Commit message ##
    -    disk: luks2: Discern Argon2i and Argon2id
    +    luks2: Discern Argon2i and Argon2id
     
         While GRUB is already able to parse both Argon2i and Argon2id parameters
         from the LUKS2 header, it doesn't discern both types. This commit
5:  ec4389627 ! 6:  70a354e0b disk: luks2: Support key derival via Argon2
    @@ Metadata
     Author: Patrick Steinhardt <ps@pks.im>
     
      ## Commit message ##
    -    disk: luks2: Support key derival via Argon2
    +    luks2: Support key derival via Argon2
     
         One addition with LUKS2 was support of the key derival function Argon2
         in addition to the previously supported PBKDF2 algortihm. In order to
    @@ Makefile.util.def: library = {
        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;
    @@ grub-core/disk/luks2.c: luks2_decrypt_key (grub_uint8_t *out_key,
            case LUKS2_KDF_TYPE_ARGON2ID:
     -	ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported");
     -	goto err;
    -+	ret = grub_crypto_argon2 (passphrase, passphraselen, salt, saltlen,
    -+				  k->kdf.u.argon2.time, k->kdf.u.argon2.memory, k->kdf.u.argon2.cpus,
    -+				  k->kdf.type == LUKS2_KDF_TYPE_ARGON2I ? GRUB_ARGON2_I : GRUB_ARGON2_ID,
    -+				  GRUB_ARGON2_VERSION_NUMBER,
    -+				  area_key, k->area.key_size);
    ++	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", grub_errmsg);
    ++	    grub_dprintf ("luks2", "Argon2 failed: %s\n", argon2_error_message (ret));
     +	    goto err;
     +	  }
     +        break;
-- 
2.25.1



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

* [PATCH v2 1/6] efi: Allocate half of available memory by default
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
@ 2020-02-20 18:00   ` Patrick Steinhardt
  2020-02-20 18:00   ` [PATCH v2 2/6] types.h: add UINT-related macros needed for Argon2 Patrick Steinhardt
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 18:00 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, gmazyland, leif, agraf, pjones,
	mjg59, phcoder

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, let's thus increase the default and make half of
memory available, instead of a quarter only. This amounts to about
1600MB on above systems, which is sufficient for Argon2.

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

diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index b02fab1b1..d1f9d046b 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -599,10 +599,10 @@ 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 half of the available memory.  */
   total_pages = get_total_pages (filtered_memory_map, desc_size,
 				 filtered_memory_map_end);
-  required_pages = (total_pages >> 2);
+  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))
-- 
2.25.1



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

* [PATCH v2 2/6] types.h: add UINT-related macros needed for Argon2
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
  2020-02-20 18:00   ` [PATCH v2 1/6] efi: Allocate half of available memory by default Patrick Steinhardt
@ 2020-02-20 18:00   ` Patrick Steinhardt
  2020-02-21 12:34     ` Daniel Kiper
  2020-02-20 18:00   ` [PATCH v2 3/6] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
                     ` (5 subsequent siblings)
  7 siblings, 1 reply; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 18:00 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, gmazyland, leif, agraf, pjones,
	mjg59, phcoder

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..35ba900dd 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
+# 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.25.1



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

* [PATCH v2 3/6] argon2: Import Argon2 from cryptsetup
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
  2020-02-20 18:00   ` [PATCH v2 1/6] efi: Allocate half of available memory by default Patrick Steinhardt
  2020-02-20 18:00   ` [PATCH v2 2/6] types.h: add UINT-related macros needed for Argon2 Patrick Steinhardt
@ 2020-02-20 18:00   ` Patrick Steinhardt
  2020-02-21 12:39     ` Daniel Kiper
  2020-02-20 18:00   ` [PATCH v2 4/6] luks2: Add missing newline to debug message Patrick Steinhardt
                     ` (4 subsequent siblings)
  7 siblings, 1 reply; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 18:00 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, gmazyland, leif, agraf, pjones,
	mjg59, phcoder

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 df2350be0..490af8b01 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -489,10 +489,74 @@ GRUB includes some code from other projects, and it is sometimes necessary
 to update it.
 
 @menu
+* Argon2::
 * Gnulib::
 * jsmn::
 @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 a0507a1fa..7e96cb1ce 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] 32+ messages in thread

* [PATCH v2 4/6] luks2: Add missing newline to debug message
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
                     ` (2 preceding siblings ...)
  2020-02-20 18:00   ` [PATCH v2 3/6] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
@ 2020-02-20 18:00   ` Patrick Steinhardt
  2020-02-20 18:00   ` [PATCH v2 5/6] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 18:00 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, gmazyland, leif, agraf, pjones,
	mjg59, phcoder

The debug message printed when decryption with a keyslot fails is
missing its trailing newline. Add it to avoid mangling it with
subsequent output.

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

diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 49ee9c862..65c4f0aac 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -610,7 +610,7 @@ luks2_recover_key (grub_disk_t disk,
 			       (const grub_uint8_t *) passphrase, grub_strlen (passphrase));
       if (ret)
 	{
-	  grub_dprintf ("luks2", "Decryption with keyslot %"PRIuGRUB_SIZE" failed", i);
+	  grub_dprintf ("luks2", "Decryption with keyslot %"PRIuGRUB_SIZE" failed\n", i);
 	  continue;
 	}
 
-- 
2.25.1



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

* [PATCH v2 5/6] luks2: Discern Argon2i and Argon2id
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
                     ` (3 preceding siblings ...)
  2020-02-20 18:00   ` [PATCH v2 4/6] luks2: Add missing newline to debug message Patrick Steinhardt
@ 2020-02-20 18:00   ` Patrick Steinhardt
  2020-02-21 12:54     ` Daniel Kiper
  2020-02-20 18:00   ` [PATCH v2 6/6] luks2: Support key derival via Argon2 Patrick Steinhardt
                     ` (2 subsequent siblings)
  7 siblings, 1 reply; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 18:00 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, gmazyland, leif, agraf, pjones,
	mjg59, phcoder

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 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] 32+ messages in thread

* [PATCH v2 6/6] luks2: Support key derival via Argon2
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
                     ` (4 preceding siblings ...)
  2020-02-20 18:00   ` [PATCH v2 5/6] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
@ 2020-02-20 18:00   ` Patrick Steinhardt
  2020-02-21 13:03     ` Daniel Kiper
  2020-02-20 18:38   ` [PATCH v2 0/6] Support Argon2 KDF in LUKS2 Leif Lindholm
  2020-02-21 12:26   ` Daniel Kiper
  7 siblings, 1 reply; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 18:00 UTC (permalink / raw)
  To: grub-devel
  Cc: Patrick Steinhardt, Daniel Kiper, gmazyland, leif, agraf, pjones,
	mjg59, phcoder

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 94336392b..a50effce4 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 7e96cb1ce..7ffd26528 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] 32+ messages in thread

* Re: [PATCH v2 0/6] Support Argon2 KDF in LUKS2
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
                     ` (5 preceding siblings ...)
  2020-02-20 18:00   ` [PATCH v2 6/6] luks2: Support key derival via Argon2 Patrick Steinhardt
@ 2020-02-20 18:38   ` Leif Lindholm
  2020-02-21 12:26   ` Daniel Kiper
  7 siblings, 0 replies; 32+ messages in thread
From: Leif Lindholm @ 2020-02-20 18:38 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, gmazyland, agraf, pjones, mjg59, phcoder

Hi Patrick,

On Thu, Feb 20, 2020 at 19:00:48 +0100, Patrick Steinhardt wrote:
> this is the second version of my patchset to add support for Argon2
> encryption keys for LUKS2.
> 
> The most important change is that I've now verbosely imported the argon2
> code from the official reference implementation instead of from the
> cryptsetup project. The diff between both isn't that big in the end, and
> including from crypsetup's upstream seems a bit cleaner to me. There
> were several transformations required to use GRUB's types and functions
> as well as stripping of unused stuff, which I've now documented the dev
> manual. This also fixes my previously mistaken license headers.
> 
> One thing I'm not sure about here is whether it's fine to declare the
> argon2 mod's license as GPLv3. The code is licensed under CC0/Apache
> 2.0, where the latter is compatible with GPLv3. But I don't know whether
> it's legit to just say "Yeah, this mod is a GPLv3 one".
> 
> I didn't address the comment made by Leif yet with regards to grabbing
> memory. I ain't got much of a clue of GRUB's memory subsystem, so I'd
> gladly accept help there. Otherwise I'll have to dig a bit deeper.

That's fair enough. I think we could do something halfway clever to
resolve that, or we could do something quick and simple, but either
would be better than moving to reserving 50%.

So could you reply to my email on that thread with some info with
regards to the specific memory requirements, and whether they are
precise or "this much seems to always work"?

Regards,

Leif

> The range diff compared to the previous version of this patch set is
> attached to this mail.
> 
> Patrick
> 
> 
> Patrick Steinhardt (6):
>   efi: Allocate half of available memory by default
>   types.h: add UINT-related macros needed for Argon2
>   argon2: Import Argon2 from cryptsetup
>   luks2: Add missing newline to debug message
>   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                        |  28 +-
>  grub-core/kern/efi/mm.c                       |   4 +-
>  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, 2231 insertions(+), 12 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 v1:
> 1:  53cdfdc27 = 1:  15bdf830e efi: Allocate half of available memory by default
> 2:  c55946ca5 < -:  --------- argon2: Import Argon2 from cryptsetup
> -:  --------- > 2:  e81db7d95 types.h: add UINT-related macros needed for Argon2
> -:  --------- > 3:  50aff9670 argon2: Import Argon2 from cryptsetup
> 3:  c17cd2197 ! 4:  af3f85665 disk: luks2: Add missing newline to debug message
>     @@ Metadata
>      Author: Patrick Steinhardt <ps@pks.im>
>      
>       ## Commit message ##
>     -    disk: luks2: Add missing newline to debug message
>     +    luks2: Add missing newline to debug message
>      
>          The debug message printed when decryption with a keyslot fails is
>          missing its trailing newline. Add it to avoid mangling it with
>          subsequent output.
>      
>          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: luks2_recover_key (grub_disk_t disk,
> 4:  390728cea ! 5:  89abe827b disk: luks2: Discern Argon2i and Argon2id
>     @@ Metadata
>      Author: Patrick Steinhardt <ps@pks.im>
>      
>       ## Commit message ##
>     -    disk: luks2: Discern Argon2i and Argon2id
>     +    luks2: Discern Argon2i and Argon2id
>      
>          While GRUB is already able to parse both Argon2i and Argon2id parameters
>          from the LUKS2 header, it doesn't discern both types. This commit
> 5:  ec4389627 ! 6:  70a354e0b disk: luks2: Support key derival via Argon2
>     @@ Metadata
>      Author: Patrick Steinhardt <ps@pks.im>
>      
>       ## Commit message ##
>     -    disk: luks2: Support key derival via Argon2
>     +    luks2: Support key derival via Argon2
>      
>          One addition with LUKS2 was support of the key derival function Argon2
>          in addition to the previously supported PBKDF2 algortihm. In order to
>     @@ Makefile.util.def: library = {
>         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;
>     @@ grub-core/disk/luks2.c: luks2_decrypt_key (grub_uint8_t *out_key,
>             case LUKS2_KDF_TYPE_ARGON2ID:
>      -	ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Argon2 not supported");
>      -	goto err;
>     -+	ret = grub_crypto_argon2 (passphrase, passphraselen, salt, saltlen,
>     -+				  k->kdf.u.argon2.time, k->kdf.u.argon2.memory, k->kdf.u.argon2.cpus,
>     -+				  k->kdf.type == LUKS2_KDF_TYPE_ARGON2I ? GRUB_ARGON2_I : GRUB_ARGON2_ID,
>     -+				  GRUB_ARGON2_VERSION_NUMBER,
>     -+				  area_key, k->area.key_size);
>     ++	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", grub_errmsg);
>     ++	    grub_dprintf ("luks2", "Argon2 failed: %s\n", argon2_error_message (ret));
>      +	    goto err;
>      +	  }
>      +        break;
> -- 
> 2.25.1
> 


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

* Re: [PATCH 1/5] efi: Allocate half of available memory by default
  2020-02-13 11:47   ` Leif Lindholm
@ 2020-02-20 19:29     ` Patrick Steinhardt
  0 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 19:29 UTC (permalink / raw)
  To: Leif Lindholm; +Cc: The development of GNU GRUB, Daniel Kiper

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

On Thu, Feb 13, 2020 at 11:47:54AM +0000, Leif Lindholm wrote:
> On Thu, Feb 06, 2020 at 15:27:29 +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, let's thus increase the default and make half of
> > memory available, instead of a quarter only. This amounts to about
> > 1600MB on above systems, which is sufficient for Argon2.
> 
> I was never a huge fan of the "grab a percentage of RAM" in the first
> place, and I think "grab twice that" is not the best solution here.
> 
> (Real) corner cases that would be affected by this are:
> 1) chainloading grub from grub
> 2) OS loaders (loaded by GRUB) requiring large amounts of RAM before
>    ExitBootsevices().
> 
> If you have a known minimum requirement, can we work towards that
> instead?

Quoting Milan from another mail in this thread:

On Wed, Feb 12, 2020 at 08:18:32AM +0100, Milan Broz wrote:
> Anyway, there are some limits in cryptsetup - we try to never use
> more than half of physical memory and maximum is hard-compiled to 4GiB.
> 
> (But physical memory limit applies when formatting device, then
> is stored in the LUKS2 keyslot header. So if you format it on device with
> much larger RAM and it is later not available, it fails to open.
> It is more complicated though - we have benchmark during format that prioritize
> unlocking time, so PBKDF memory is usually decreased on low-memory systems anyway.)

As far as I can see, the default memory cost for Argon2 is 1,048,576kB,
at least that is what "configure.ac" says for "luks2-memory-kb". That
also matches my experience with cryptsetup 2.2.2.

Patrick

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

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

* Re: [PATCH 0/5] Support Argon2 KDF in LUKS2
  2020-02-12  7:18   ` Milan Broz
@ 2020-02-20 19:34     ` Patrick Steinhardt
  0 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-20 19:34 UTC (permalink / raw)
  To: Milan Broz
  Cc: Daniel Kiper, grub-devel, Daniel Kiper, leif, agraf, pjones,
	mjg59, phcoder

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

On Wed, Feb 12, 2020 at 08:18:32AM +0100, Milan Broz wrote:
> On 11/02/2020 22:53, Daniel Kiper wrote:
> > On Thu, Feb 06, 2020 at 03:27:28PM +0100, Patrick Steinhardt wrote:
> >>     - The import of Argon2 itself. I've imported code from the
> >>       cryptsetup project, but I've modified it quite a bit to fit into
> > 
> > Milan mentioned something about libgcrypt. Milan, when the Argon2 code
> > may land in libgcrypt?
> 
> Once we have volunteer to implement it / port it to gcrypt :-)

I'm not familiar with how the gcrypt project itself operates. In case
it's only a simple port similar to what I'm currently doing for GRUB,
then I would be happy to invest that time.

> BTW if you have embedded Argon2 code, you should also add some test vectors
> to your testsuite.
> (You can use these we have in cryptsetup - see tests/crypto-vectors.c)

I didn't include test vectors for v2 yet, but will do so as soon as we
get closer to something shippable.

Patrick

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

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

* Re: [PATCH v2 0/6] Support Argon2 KDF in LUKS2
  2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
                     ` (6 preceding siblings ...)
  2020-02-20 18:38   ` [PATCH v2 0/6] Support Argon2 KDF in LUKS2 Leif Lindholm
@ 2020-02-21 12:26   ` Daniel Kiper
  2020-02-21 14:29     ` Patrick Steinhardt
  7 siblings, 1 reply; 32+ messages in thread
From: Daniel Kiper @ 2020-02-21 12:26 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

Hi Patrick,

On Thu, Feb 20, 2020 at 07:00:48PM +0100, Patrick Steinhardt wrote:
> Hi,
>
> this is the second version of my patchset to add support for Argon2
> encryption keys for LUKS2.
>
> The most important change is that I've now verbosely imported the argon2
> code from the official reference implementation instead of from the
> cryptsetup project. The diff between both isn't that big in the end, and
> including from crypsetup's upstream seems a bit cleaner to me. There
> were several transformations required to use GRUB's types and functions
> as well as stripping of unused stuff, which I've now documented the dev
> manual. This also fixes my previously mistaken license headers.
>
> One thing I'm not sure about here is whether it's fine to declare the
> argon2 mod's license as GPLv3. The code is licensed under CC0/Apache
> 2.0, where the latter is compatible with GPLv3. But I don't know whether
> it's legit to just say "Yeah, this mod is a GPLv3 one".

Could you give me a reference to the doc/spec or what not which says that
it is legit to do that? I will consult this with GNU legal folks.

> I didn't address the comment made by Leif yet with regards to grabbing
> memory. I ain't got much of a clue of GRUB's memory subsystem, so I'd
> gladly accept help there. Otherwise I'll have to dig a bit deeper.

I will skip this part at this stage of review.

Daniel


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

* Re: [PATCH v2 2/6] types.h: add UINT-related macros needed for Argon2
  2020-02-20 18:00   ` [PATCH v2 2/6] types.h: add UINT-related macros needed for Argon2 Patrick Steinhardt
@ 2020-02-21 12:34     ` Daniel Kiper
  0 siblings, 0 replies; 32+ messages in thread
From: Daniel Kiper @ 2020-02-21 12:34 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

On Thu, Feb 20, 2020 at 07:00:50PM +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>
> ---
>  include/grub/types.h | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/include/grub/types.h b/include/grub/types.h
> index 035a4b528..35ba900dd 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
> +# elif 1

#else?

Daniel


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

* Re: [PATCH v2 3/6] argon2: Import Argon2 from cryptsetup
  2020-02-20 18:00   ` [PATCH v2 3/6] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
@ 2020-02-21 12:39     ` Daniel Kiper
  0 siblings, 0 replies; 32+ messages in thread
From: Daniel Kiper @ 2020-02-21 12:39 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

On Thu, Feb 20, 2020 at 07:00:51PM +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>

LGTM, however, I will give my RB when legal things are resolved...

Daniel


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

* Re: [PATCH v2 5/6] luks2: Discern Argon2i and Argon2id
  2020-02-20 18:00   ` [PATCH v2 5/6] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
@ 2020-02-21 12:54     ` Daniel Kiper
  0 siblings, 0 replies; 32+ messages in thread
From: Daniel Kiper @ 2020-02-21 12:54 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

On Thu, Feb 20, 2020 at 07:00:53PM +0100, Patrick Steinhardt wrote:
> 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>

Daniel


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

* Re: [PATCH v2 6/6] luks2: Support key derival via Argon2
  2020-02-20 18:00   ` [PATCH v2 6/6] luks2: Support key derival via Argon2 Patrick Steinhardt
@ 2020-02-21 13:03     ` Daniel Kiper
  0 siblings, 0 replies; 32+ messages in thread
From: Daniel Kiper @ 2020-02-21 13:03 UTC (permalink / raw)
  To: Patrick Steinhardt
  Cc: grub-devel, Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

On Thu, Feb 20, 2020 at 07:00:54PM +0100, Patrick Steinhardt wrote:
> 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>

Daniel


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

* Re: [PATCH v2 0/6] Support Argon2 KDF in LUKS2
  2020-02-21 12:26   ` Daniel Kiper
@ 2020-02-21 14:29     ` Patrick Steinhardt
  0 siblings, 0 replies; 32+ messages in thread
From: Patrick Steinhardt @ 2020-02-21 14:29 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Daniel Kiper, gmazyland, leif, agraf, pjones, mjg59, phcoder

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

On Fri, Feb 21, 2020 at 01:26:20PM +0100, Daniel Kiper wrote:
> On Thu, Feb 20, 2020 at 07:00:48PM +0100, Patrick Steinhardt wrote:
> > One thing I'm not sure about here is whether it's fine to declare the
> > argon2 mod's license as GPLv3. The code is licensed under CC0/Apache
> > 2.0, where the latter is compatible with GPLv3. But I don't know whether
> > it's legit to just say "Yeah, this mod is a GPLv3 one".
> 
> Could you give me a reference to the doc/spec or what not which says that
> it is legit to do that? I will consult this with GNU legal folks.

With "that" you probably mean combining Apache 2.0 and GPLv3, right?
I've taken this from GNU's list of licenses [1], which explicitly
mentions Apache 2.0 as compatible with version 3 of the GNU GPL.

Patrick

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

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

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

end of thread, other threads:[~2020-02-21 14:29 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-06 14:27 [PATCH 0/5] Support Argon2 KDF in LUKS2 Patrick Steinhardt
2020-02-06 14:27 ` [PATCH 1/5] efi: Allocate half of available memory by default Patrick Steinhardt
2020-02-13 11:47   ` Leif Lindholm
2020-02-20 19:29     ` Patrick Steinhardt
2020-02-06 14:27 ` [PATCH 2/5] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
2020-02-08 11:30   ` Milan Broz
2020-02-08 22:25     ` Patrick Steinhardt
2020-02-06 14:27 ` [PATCH 3/5] disk: luks2: Add missing newline to debug message Patrick Steinhardt
2020-02-11 21:36   ` Daniel Kiper
2020-02-12  7:48     ` Patrick Steinhardt
2020-02-06 14:27 ` [PATCH 4/5] disk: luks2: Discern Argon2i and Argon2id Patrick Steinhardt
2020-02-06 14:27 ` [PATCH 5/5] disk: luks2: Support key derival via Argon2 Patrick Steinhardt
2020-02-11 21:53 ` [PATCH 0/5] Support Argon2 KDF in LUKS2 Daniel Kiper
2020-02-12  7:18   ` Milan Broz
2020-02-20 19:34     ` Patrick Steinhardt
2020-02-12  7:47   ` Patrick Steinhardt
2020-02-13 11:42     ` Daniel Kiper
2020-02-20 14:50       ` Patrick Steinhardt
2020-02-20 18:00 ` [PATCH v2 0/6] " Patrick Steinhardt
2020-02-20 18:00   ` [PATCH v2 1/6] efi: Allocate half of available memory by default Patrick Steinhardt
2020-02-20 18:00   ` [PATCH v2 2/6] types.h: add UINT-related macros needed for Argon2 Patrick Steinhardt
2020-02-21 12:34     ` Daniel Kiper
2020-02-20 18:00   ` [PATCH v2 3/6] argon2: Import Argon2 from cryptsetup Patrick Steinhardt
2020-02-21 12:39     ` Daniel Kiper
2020-02-20 18:00   ` [PATCH v2 4/6] luks2: Add missing newline to debug message Patrick Steinhardt
2020-02-20 18:00   ` [PATCH v2 5/6] luks2: Discern Argon2i and Argon2id Patrick Steinhardt
2020-02-21 12:54     ` Daniel Kiper
2020-02-20 18:00   ` [PATCH v2 6/6] luks2: Support key derival via Argon2 Patrick Steinhardt
2020-02-21 13:03     ` Daniel Kiper
2020-02-20 18:38   ` [PATCH v2 0/6] Support Argon2 KDF in LUKS2 Leif Lindholm
2020-02-21 12:26   ` Daniel Kiper
2020-02-21 14:29     ` Patrick Steinhardt

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.