[Top][All Lists]

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

[PATCH] luks2: Fix decoding of digests and salts with escaped chars

From: Patrick Steinhardt
Subject: [PATCH] luks2: Fix decoding of digests and salts with escaped chars
Date: Wed, 11 Aug 2021 20:55:32 +0200

It was reported in the #grub IRC channel that decryption of LUKS2
partitions fails with errors about invalid digests and/or salts. In all
of these cases, what failed was decoding the Base64 representation of
these, where the encoded data contained invalid characters.

As it turns out, the root cause is that json-c, which is used by
cryptsetup to read and write the JSON header, will escape some
characters by prepending a backslash when writing JSON strings. Most
importantly, this also includes the forward slash, which is part of the
Base64 alphabet and which may optionally be escaped. Because GRUB
doesn't know to unescape such characters, decoding this string will
rightfully fail.

Fix the issue by stripping the escape character for forward slashes.
There is no need to do so for any other escaped character given that
valid Base64 does not contain anything else.

Signed-off-by: Patrick Steinhardt <>
Reported-by: Afdal
 grub-core/disk/luks2.c | 34 ++++++++++++++++++++++++++++++----
 1 file changed, 30 insertions(+), 4 deletions(-)

diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index 371a53b83..7e596f90d 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -383,6 +383,32 @@ luks2_scan (grub_disk_t disk, const char *check_uuid, int 
   return cryptodisk;
+static int luks2_base64_decode (const char *in, size_t inlen, char *decoded, 
size_t *decodedlen)
+  char *unescaped = NULL;
+  size_t i, j;
+  int err;
+  unescaped = grub_malloc (inlen);
+  grub_memmove (unescaped, in, inlen);
+  /*
+   * JSON strings can escape some characters. Given that we expect
+   * Base64-encoded input here, the only character from the Base64 alphabet
+   * which may optionally be escaped is the forward slash. We thus strip away
+   * the escape character if we see '\/' in the input.
+   */
+  for (i = j = 0; i < inlen; i++) {
+    if (i + 1 < inlen && unescaped[i] == '\\' && unescaped[i + 1] == '/')
+      continue;
+    unescaped[j++] = unescaped[i];
+  }
+  err = base64_decode (unescaped, j, decoded, decodedlen);
+  grub_free (unescaped);
+  return err;
 static grub_err_t
 luks2_verify_key (grub_luks2_digest_t *d, grub_uint8_t *candidate_key,
                  grub_size_t candidate_key_len)
@@ -394,9 +420,9 @@ luks2_verify_key (grub_luks2_digest_t *d, grub_uint8_t 
   gcry_err_code_t gcry_ret;
   /* Decode both digest and salt */
-  if (!base64_decode (d->digest, grub_strlen (d->digest), (char *)digest, 
+  if (!luks2_base64_decode (d->digest, grub_strlen (d->digest), (char 
*)digest, &digestlen))
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid digest");
-  if (!base64_decode (d->salt, grub_strlen (d->salt), (char *)salt, &saltlen))
+  if (!luks2_base64_decode (d->salt, grub_strlen (d->salt), (char *)salt, 
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid digest salt");
   /* Configure the hash used for the digest. */
@@ -434,8 +460,8 @@ luks2_decrypt_key (grub_uint8_t *out_key,
   gcry_err_code_t gcry_ret;
   grub_err_t ret;
-  if (!base64_decode (k->kdf.salt, grub_strlen (k->kdf.salt),
-                    (char *)salt, &saltlen))
+  if (!luks2_base64_decode (k->kdf.salt, grub_strlen (k->kdf.salt),
+                           (char *)salt, &saltlen))
       ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid keyslot salt");
       goto err;

Attachment: signature.asc
Description: PGP signature

reply via email to

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