grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/5] argon2: Import Argon2 from cryptsetup


From: Patrick Steinhardt
Subject: [PATCH 2/5] argon2: Import Argon2 from cryptsetup
Date: Thu, 6 Feb 2020 15:27:30 +0100

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 <address@hidden>
---
 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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]