All of lore.kernel.org
 help / color / mirror / Atom feed
From: John Lane <grub@jelmail.com>
To: grub-devel@gnu.org
Cc: John Lane <john@lane.uk.net>
Subject: [PATCH 3/7] cryptomount luks allow multiple passphrase attempts
Date: Wed, 14 Mar 2018 09:45:00 +0000	[thread overview]
Message-ID: <20180314094504.6177-3-grub@jelmail.com> (raw)
In-Reply-To: <20180314094504.6177-1-grub@jelmail.com>

From: John Lane <john@lane.uk.net>

---
 grub-core/disk/luks.c | 278 ++++++++++++++++++++++++++------------------------
 1 file changed, 143 insertions(+), 135 deletions(-)

diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c
index 588236888..11e437edb 100644
--- a/grub-core/disk/luks.c
+++ b/grub-core/disk/luks.c
@@ -321,10 +321,10 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid,
 
 static grub_err_t
 luks_recover_key (grub_disk_t source,
-		  grub_cryptodisk_t dev,
-		  grub_file_t hdr,
-		  grub_uint8_t *keyfile_bytes,
-		  grub_size_t keyfile_bytes_size)
+                  grub_cryptodisk_t dev,
+                  grub_file_t hdr,
+                  grub_uint8_t *keyfile_bytes,
+                  grub_size_t keyfile_bytes_size)
 {
   struct grub_luks_phdr header;
   grub_size_t keysize;
@@ -339,6 +339,7 @@ luks_recover_key (grub_disk_t source,
   grub_size_t max_stripes = 1;
   char *tmp;
   grub_uint32_t sector;
+  unsigned attempts = 2;
 
   err = GRUB_ERR_NONE;
 
@@ -361,151 +362,158 @@ luks_recover_key (grub_disk_t source,
 
   for (i = 0; i < ARRAY_SIZE (header.keyblock); i++)
     if (grub_be_to_cpu32 (header.keyblock[i].active) == LUKS_KEY_ENABLED
-	&& grub_be_to_cpu32 (header.keyblock[i].stripes) > max_stripes)
+        && grub_be_to_cpu32 (header.keyblock[i].stripes) > max_stripes)
       max_stripes = grub_be_to_cpu32 (header.keyblock[i].stripes);
 
   split_key = grub_malloc (keysize * max_stripes);
   if (!split_key)
     return grub_errno;
 
-  if (keyfile_bytes)
+  while (attempts)
     {
-      /* Use bytestring from key file as passphrase */
-      passphrase = keyfile_bytes;
-      passphrase_length = keyfile_bytes_size;
-    }
-  else
-    {
-      /* Get the passphrase from the user.  */
-      tmp = NULL;
-      if (source->partition)
-        tmp = grub_partition_get_name (source->partition);
-      grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
-		    source->partition ? "," : "", tmp ? : "", dev->uuid);
-      grub_free (tmp);
-      if (!grub_password_get (interactive_passphrase, MAX_PASSPHRASE))
+      if (keyfile_bytes)
         {
-          grub_free (split_key);
-          return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
-        }
-
-      passphrase = (grub_uint8_t *)interactive_passphrase;
-      passphrase_length = grub_strlen (interactive_passphrase);
-
-    }
-
-  /* Try to recover master key from each active keyslot.  */
-  for (i = 0; i < ARRAY_SIZE (header.keyblock); i++)
-    {
-      gcry_err_code_t gcry_err;
-      grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN];
-      grub_uint8_t digest[GRUB_CRYPTODISK_MAX_KEYLEN];
-
-      /* Check if keyslot is enabled.  */
-      if (grub_be_to_cpu32 (header.keyblock[i].active) != LUKS_KEY_ENABLED)
-	continue;
-
-      grub_dprintf ("luks", "Trying keyslot %d\n", i);
-
-      /* Calculate the PBKDF2 of the user supplied passphrase.  */
-      gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase,
-				     passphrase_length,
-				     header.keyblock[i].passwordSalt,
-				     sizeof (header.keyblock[i].passwordSalt),
-				     grub_be_to_cpu32 (header.keyblock[i].
-						       passwordIterations),
-				     digest, keysize);
-
-      if (gcry_err)
-	{
-	  grub_free (split_key);
-	  return grub_crypto_gcry_error (gcry_err);
-	}
-
-      grub_dprintf ("luks", "PBKDF2 done\n");
-
-      gcry_err = grub_cryptodisk_setkey (dev, digest, keysize); 
-      if (gcry_err)
-	{
-	  grub_free (split_key);
-	  return grub_crypto_gcry_error (gcry_err);
-	}
-
-      sector = grub_be_to_cpu32 (header.keyblock[i].keyMaterialOffset);
-      length = (keysize * grub_be_to_cpu32 (header.keyblock[i].stripes));
-
-      /* Read and decrypt the key material from the disk.  */
-      if (hdr)
-        {
-	  grub_file_seek (hdr, sector * 512);
-          if (grub_file_read (hdr, split_key, length) != (grub_ssize_t)length)
-            err = GRUB_ERR_READ_ERROR;
+          /* Use bytestring from key file as passphrase */
+          passphrase = keyfile_bytes;
+          passphrase_length = keyfile_bytes_size;
+	  keyfile_bytes = NULL; /* use it only once */
         }
       else
-        err = grub_disk_read (source, sector, 0, length, split_key);
-      if (err)
-	{
-	  grub_free (split_key);
-	  return err;
-	}
-
-      gcry_err = grub_cryptodisk_decrypt (dev, split_key, length, 0);
-      if (gcry_err)
-	{
-	  grub_free (split_key);
-	  return grub_crypto_gcry_error (gcry_err);
-	}
-
-      /* Merge the decrypted key material to get the candidate master key.  */
-      gcry_err = AF_merge (dev->hash, split_key, candidate_key, keysize,
-			   grub_be_to_cpu32 (header.keyblock[i].stripes));
-      if (gcry_err)
-	{
-	  grub_free (split_key);
-	  return grub_crypto_gcry_error (gcry_err);
-	}
-
-      grub_dprintf ("luks", "candidate key recovered\n");
-
-      /* Calculate the PBKDF2 of the candidate master key.  */
-      gcry_err = grub_crypto_pbkdf2 (dev->hash, candidate_key,
-				     grub_be_to_cpu32 (header.keyBytes),
-				     header.mkDigestSalt,
-				     sizeof (header.mkDigestSalt),
-				     grub_be_to_cpu32
-				     (header.mkDigestIterations),
-				     candidate_digest,
-				     sizeof (candidate_digest));
-      if (gcry_err)
-	{
-	  grub_free (split_key);
-	  return grub_crypto_gcry_error (gcry_err);
-	}
-
-      /* Compare the calculated PBKDF2 to the digest stored
-         in the header to see if it's correct.  */
-      if (grub_memcmp (candidate_digest, header.mkDigest,
-		       sizeof (header.mkDigest)) != 0)
-	{
-	  grub_dprintf ("luks", "bad digest\n");
-	  continue;
-	}
+        {
+          /* Get the passphrase from the user.  */
+          tmp = NULL;
+          if (source->partition)
+            tmp = grub_partition_get_name (source->partition);
+          grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
+                              source->partition ? "," : "", tmp ? : "", dev->uuid);
+          grub_free (tmp);
+          if (!grub_password_get (interactive_passphrase, MAX_PASSPHRASE))
+            {
+              grub_free (split_key);
+              return grub_error (GRUB_ERR_BAD_ARGUMENT, "Passphrase not supplied");
+            }
+
+          passphrase = (grub_uint8_t *)interactive_passphrase;
+          passphrase_length = grub_strlen (interactive_passphrase);
 
-      /* TRANSLATORS: It's a cryptographic key slot: one element of an array
-	 where each element is either empty or holds a key.  */
-      grub_printf_ (N_("Slot %d opened\n"), i);
+        }
 
-      /* Set the master key.  */
-      gcry_err = grub_cryptodisk_setkey (dev, candidate_key, keysize); 
-      if (gcry_err)
-	{
-	  grub_free (split_key);
-	  return grub_crypto_gcry_error (gcry_err);
-	}
+      /* Try to recover master key from each active keyslot.  */
+      for (i = 0; i < ARRAY_SIZE (header.keyblock); i++)
+        {
+          gcry_err_code_t gcry_err;
+          grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN];
+          grub_uint8_t digest[GRUB_CRYPTODISK_MAX_KEYLEN];
+
+          /* Check if keyslot is enabled.  */
+          if (grub_be_to_cpu32 (header.keyblock[i].active) != LUKS_KEY_ENABLED)
+            continue;
+
+          grub_dprintf ("luks", "Trying keyslot %d\n", i);
+
+          /* Calculate the PBKDF2 of the user supplied passphrase.  */
+          gcry_err = grub_crypto_pbkdf2 (dev->hash, (grub_uint8_t *) passphrase,
+                                         passphrase_length,
+                                         header.keyblock[i].passwordSalt,
+                                         sizeof (header.keyblock[i].passwordSalt),
+                                         grub_be_to_cpu32 (header.keyblock[i].
+                                         passwordIterations),
+                                         digest, keysize);
+
+          if (gcry_err)
+            {
+              grub_free (split_key);
+              return grub_crypto_gcry_error (gcry_err);
+            }
+
+          grub_dprintf ("luks", "PBKDF2 done\n");
+
+          gcry_err = grub_cryptodisk_setkey (dev, digest, keysize);
+          if (gcry_err)
+            {
+              grub_free (split_key);
+              return grub_crypto_gcry_error (gcry_err);
+            }
+
+          sector = grub_be_to_cpu32 (header.keyblock[i].keyMaterialOffset);
+          length = (keysize * grub_be_to_cpu32 (header.keyblock[i].stripes));
+
+          /* Read and decrypt the key material from the disk.  */
+          if (hdr)
+            {
+              grub_file_seek (hdr, sector * 512);
+              if (grub_file_read (hdr, split_key, length) != (grub_ssize_t)length)
+                err = GRUB_ERR_READ_ERROR;
+            }
+          else
+            err = grub_disk_read (source, sector, 0, length, split_key);
+          if (err)
+            {
+              grub_free (split_key);
+              return err;
+            }
+
+          gcry_err = grub_cryptodisk_decrypt (dev, split_key, length, 0);
+          if (gcry_err)
+            {
+              grub_free (split_key);
+              return grub_crypto_gcry_error (gcry_err);
+            }
+
+          /* Merge the decrypted key material to get the candidate master key.  */
+          gcry_err = AF_merge (dev->hash, split_key, candidate_key, keysize,
+                               grub_be_to_cpu32 (header.keyblock[i].stripes));
+          if (gcry_err)
+            {
+              grub_free (split_key);
+              return grub_crypto_gcry_error (gcry_err);
+            }
+
+          grub_dprintf ("luks", "candidate key recovered\n");
+
+          /* Calculate the PBKDF2 of the candidate master key.  */
+          gcry_err = grub_crypto_pbkdf2 (dev->hash, candidate_key,
+                                     grub_be_to_cpu32 (header.keyBytes),
+                                     header.mkDigestSalt,
+                                     sizeof (header.mkDigestSalt),
+                                     grub_be_to_cpu32
+                                     (header.mkDigestIterations),
+                                     candidate_digest,
+                                     sizeof (candidate_digest));
+          if (gcry_err)
+            {
+              grub_free (split_key);
+              return grub_crypto_gcry_error (gcry_err);
+            }
+
+          /* Compare the calculated PBKDF2 to the digest stored
+             in the header to see if it's correct.  */
+          if (grub_memcmp (candidate_digest, header.mkDigest,
+                                             sizeof (header.mkDigest)) != 0)
+            {
+              grub_dprintf ("luks", "bad digest\n");
+              continue;
+            }
+
+          /* TRANSLATORS: It's a cryptographic key slot: one element of an array
+             where each element is either empty or holds a key.  */
+          grub_printf_ (N_("Slot %d opened\n"), i);
+
+          /* Set the master key.  */
+          gcry_err = grub_cryptodisk_setkey (dev, candidate_key, keysize);
+          if (gcry_err)
+            {
+              grub_free (split_key);
+              return grub_crypto_gcry_error (gcry_err);
+            }
 
-      grub_free (split_key);
+          grub_free (split_key);
 
-      return GRUB_ERR_NONE;
+          return GRUB_ERR_NONE;
+        }
+      grub_printf_ (N_("Failed to decrypt master key.\n"));
+      if (--attempts) grub_printf_ (N_("%u attempt%s remaining.\n"), attempts,
+		                    (attempts==1) ? "" : "s");
     }
 
   grub_free (split_key);
-- 
2.16.2



  parent reply	other threads:[~2018-03-14  9:45 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-14  9:44 [PATCH 1/7] Cryptomount support LUKS detached header John Lane
2018-03-14  9:44 ` [PATCH 2/7] Cryptomount support key files John Lane
2018-03-17 11:10   ` TJ
2018-03-18 20:29     ` John Lane
2018-03-14  9:45 ` John Lane [this message]
2018-03-17 11:10   ` [PATCH 3/7] cryptomount luks allow multiple passphrase attempts TJ
2018-03-18 20:30     ` John Lane
2018-03-14  9:45 ` [PATCH 4/7] Cryptomount support plain dm-crypt John Lane
2018-03-14  9:45 ` [PATCH 5/7] Cryptomount support for hyphens in UUID John Lane
2018-03-14  9:45 ` [PATCH 6/7] Retain constness of parameters John Lane
2018-03-14  9:45 ` [PATCH 7/7] Add support for using a whole device as a keyfile John Lane
2018-03-14 13:05 ` [PATCH 1/7] Cryptomount support LUKS detached header Daniel Kiper
2018-03-14 19:00   ` John Lane
2018-03-21  7:23     ` Paul Menzel
2018-03-22 12:38     ` Daniel Kiper
2018-03-22 14:22       ` TJ
2018-03-26 13:10         ` John Lane
2018-03-26 14:42           ` Daniel Kiper
2018-03-17 11:09 ` TJ
2018-03-18 20:29   ` John Lane

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180314094504.6177-3-grub@jelmail.com \
    --to=grub@jelmail.com \
    --cc=grub-devel@gnu.org \
    --cc=john@lane.uk.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.