grub-devel
[Top][All Lists]
Advanced

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

[PATCH v3 1/1] plainmount: Support plain encryption mode.


From: Maxim Fomin
Subject: [PATCH v3 1/1] plainmount: Support plain encryption mode.
Date: Sat, 18 Jun 2022 14:33:48 +0000

>From 87af7e9cbeb72c3bc146564f64aa8132c1bf6d68 Mon Sep 17 00:00:00 2001
From: Maxim Fomin <maxim@fomin.one>
Date: Sat, 18 Jun 2022 14:32:49 +0100
Subject: [PATCH v3 1/1] plainmount: Support plain encryption mode.

This patch adds support for plain encryption mode (plain dm-crypt) via
new module/command named 'plainmount'.

Changes from the second version of the patch:
- added support for blocklist syntax offset
- added explicit error for unsupported offset syntax
- removed offset options -o and -O
- removed disk size -b option
- added static compile-time uuid
- removed 4096 sector size limitation
- parameters are passed directly (not inside struct)
- added support for plain hash
- minor code improvements
- improved documentation
---
 docs/grub.texi              |  54 ++++
 grub-core/Makefile.core.def |   5 +
 grub-core/disk/plainmount.c | 517 ++++++++++++++++++++++++++++++++++++
 3 files changed, 576 insertions(+)
 create mode 100644 grub-core/disk/plainmount.c

diff --git a/docs/grub.texi b/docs/grub.texi
index 9b902273c..a72475a8b 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4229,6 +4229,7 @@ you forget a command, you can run the command 
@command{help}
 * parttool::                    Modify partition table entries
 * password::                    Set a clear-text password
 * password_pbkdf2::             Set a hashed password
+* plainmount::                  Open device encrypted in plain mode.
 * play::                        Play a tune
 * probe::                       Retrieve device info
 * rdmsr::                       Read values from model-specific registers
@@ -4509,6 +4510,9 @@ function is supported, as Argon2 is not yet supported.

 Also, note that, unlike filesystem UUIDs, UUIDs for encrypted devices must be
 specified without dash separators.
+
+Support for plain encryption mode (plain dm-crypt) is provided via separate
+plainmount command.
 @end deffn

 @node cutmem
@@ -5017,6 +5021,56 @@ to generate password hashes.  @xref{Security}.
 @end deffn


+@node plainmount
+@subsection plainmount
+
+@deffn Command plainmount device @option{-c} cipher @option{-s} key size 
[@option{-h} hash]
+[@option{-S} sector size] [@option{-p} password] [@option{-d} keyfile] 
[@option{-u} uuid]
+
+Setup access to encrypted in plain mode device. Password can be specified in
+two ways: as a secret passphrase or as a byte array from a keyfile. Secret
+passphrase can be provided interactively from console or with option 
@option{-p}.
+The keyfile is specified with option @option{-d} and can be either a path to a
+regular file or a block device. The keyfile parameter @option{-d} has higher
+priority than option @option{-p}.
+
+Cipher @option{-c} and keysize @option{-s} options are mandatory. Hash option
+@option{-h} is mandatory if keyfile is not specified (hash can be 'plain' which
+means no hashing). Cipher must be specified with mode (for example, 
'aes-xts-plain64').
+Key size must not exceed 128 bytes and must be specified in bits (for example,
+-s 256 or -s 512).
+
+Option @option{-S} determines encrypted disk sector size. It should be at least
+512 bytes and a power of 2. Note: current implementation of cryptsetup allows
+only 512/ 1024/2048/4096 sectors. Disk sector size in plain mode is set at 
encryption
+time. Attempt to decrypt already created device with diffferent sector size 
will
+result in error.
+
+Offset of encrypted data (device argument) and offset of keyfile (option 
@option{-d})
+can be specified with grub blocklist syntax ('+10M') where single word 
suffixes 'K',
+'M' and 'G' (base 1024) are available. Note: unlike other grub commands, 
plainmount
+supports only single blocklist offset.
+
+By default new cryptodisk node will have uuid 
'109fea84-a6b7-34a8-4bd1-1c506305a4e1'
+where last digits are incremented for each subsequently created node. Custom
+uuid can be specified with option @option{-u}.
+
+The plainmount command can report internal cryptographic errors. If they 
happen,
+check hash, key size and cipher options - they should match each other.
+Successfully decrypted disks are named as (cryptoX) and have linear numeration
+with other decrypted devices opened by cryptodisk.
+
+Note, all encryption arguments (cipher, hash, key size, disk offset and disk
+sector size) must match those which were used to setup encrypted device. If
+any of them does not match the actual arguments used during the initial 
encryption,
+plainmount will return garbage data and GRUB will report unknown filesystem 
for the
+opened disk. Note, writing data to such a virtual device will result in data
+loss if the underlying partition contained desired data. If the encrypted disk 
hosts
+some high level abstraction (like LVM2 or MDRAID) it will be created under
+separate device name.
+@end deffn
+
+
 @node play
 @subsection play

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 715994872..579acd6c7 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1189,6 +1189,11 @@ module = {
   common = disk/luks.c;
 };

+module = {
+  name = plainmount;
+  common = disk/plainmount.c;
+};
+
 module = {
   name = luks2;
   common = disk/luks2.c;
diff --git a/grub-core/disk/plainmount.c b/grub-core/disk/plainmount.c
new file mode 100644
index 000000000..086e5cb50
--- /dev/null
+++ b/grub-core/disk/plainmount.c
@@ -0,0 +1,517 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2007,2010,2011,2019  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <grub/cryptodisk.h>
+#include <grub/dl.h>
+#include <grub/err.h>
+#include <grub/extcmd.h>
+#include <grub/partition.h>
+#include <grub/file.h>
+
+
+GRUB_MOD_LICENSE ("GPLv3+");
+char PLAINMOUNT_DEFAULT_UUID[] =       "109fea84-a6b7-34a8-4bd1-1c506305a4e0";
+#define BITS_PER_BYTE                  8
+#define PLAINMOUNT_DEFAULT_SECTOR_SIZE 512
+
+enum PLAINMOUNT_OPTION
+  {
+    OPTION_HASH,
+    OPTION_CIPHER,
+    OPTION_KEY_SIZE,
+    OPTION_SECTOR_SIZE,
+    OPTION_PASSWORD,
+    OPTION_KEYFILE,
+    OPTION_UUID
+  };
+
+static const struct grub_arg_option options[] =
+  {
+    /* TRANSLATORS: It's still restricted to this module only.  */
+    {"hash", 'h', 0, N_("Password hash"), 0, ARG_TYPE_STRING},
+    {"cipher", 'c', 0, N_("Password cipher"), 0, ARG_TYPE_STRING},
+    {"key-size", 's', 0, N_("Key size (in bits)"), 0, ARG_TYPE_INT},
+    {"sector-size", 'S', 0, N_("Device sector size"), 0, ARG_TYPE_INT},
+    {"password", 'p', 0, N_("Password (key)"), 0, ARG_TYPE_STRING},
+    {"keyfile", 'd', 0, N_("Keyfile/disk path"), 0, ARG_TYPE_STRING},
+    {"uuid", 'u', 0, N_("Set device UUID"), 0, ARG_TYPE_STRING},
+    {0, 0, 0, 0, 0, 0}
+  };
+
+struct grub_plainmount_args
+{
+  grub_uint8_t *key_data;
+  char *cipher, *mode, *hash, *keyfile, *uuid;
+  grub_size_t offset, key_size, sector_size, keyfile_offset;
+  grub_disk_t disk;
+};
+typedef struct grub_plainmount_args *grub_plainmount_args_t;
+
+
+/* Cryptodisk setkey() function wrapper */
+static grub_err_t
+plainmount_setkey (grub_cryptodisk_t dev, grub_uint8_t *data,
+                   grub_size_t size)
+{
+  gcry_err_code_t code = grub_cryptodisk_setkey (dev, data, size);
+  if (code != GPG_ERR_NO_ERROR)
+    {
+      grub_dprintf ("plainmount", "password crypto status is %d\n", code);
+      return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                         N_("cannot set key. Check consistency of "
+                            "keysize/hash/cipher options."));
+    }
+  return GRUB_ERR_NONE;
+}
+
+
+/* Parse disk size suffix */
+static grub_size_t plainmount_parse_suffix (char *arg)
+{
+  const char *p;
+  grub_size_t val = grub_strtoull (arg, &p, 0);
+
+  /* Only single word prefix is allowed */
+  if (p[1] != '\0' || (p[0] != '\0' && p[0] != 'K' && p[0] != 'k' &&
+      p[0] != 'M' && p[0] != 'm' && p[0] != 'G' && p[0] != 'g'))
+    return -1;
+
+  switch (*p)
+    {
+      case 'K':
+      case 'k':
+        val = val * 1024;
+        break;
+      case 'M':
+      case 'm':
+        val = val * 1024*1024;
+        break;
+      case 'G':
+      case 'g':
+        val = val * 1024*1024*1024;
+        break;
+      case '\0':
+        break;
+      default:
+        val = -1;
+    }
+  return val;
+}
+
+/* Support blocklist syntax */
+static grub_size_t plainmount_parse_blocklist (char *arg)
+{
+  char *pos = grub_strchr (arg, '+');
+
+  if (!pos)
+    return 0;
+
+  /* Erase '+', arg now points to disk, pos+1 to offset */
+  pos[0] = '\0';
+
+  /* 'hd0,gpt2+' equals 'hd0,gpt2' equals no offset */
+  if (pos[1] == '\0')
+    return 0;
+
+  /* Blocklist syntax here supports K/M/G suffix */
+  return plainmount_parse_suffix (pos+1);
+}
+
+/* Configure cryptodisk uuid */
+static void plainmount_set_uuid (grub_cryptodisk_t dev, char *user_uuid)
+{
+  grub_size_t pos = 0;
+  static const char * def_uuid = PLAINMOUNT_DEFAULT_UUID;
+
+  /* Size of user_uuid is checked in main func */
+  if (user_uuid)
+      grub_memcpy (dev->uuid, user_uuid, grub_strlen (user_uuid));
+
+  /* Set default UUID. Last digits start from 1 and are incremented for
+     each new plainmount device. */
+  else
+    {
+      /* Set uuid to '     ...x' where x starts from 1. */
+      grub_snprintf (dev->uuid, sizeof (dev->uuid)-1, "%32lu", dev->id+1);
+      while (dev->uuid[pos++] == ' ');
+      grub_memcpy (dev->uuid, def_uuid, pos-1);
+    }
+  COMPILE_TIME_ASSERT (sizeof (dev->uuid) >= sizeof (PLAINMOUNT_DEFAULT_UUID));
+}
+
+
+/* Configure cryptodevice sector size (-S option) */
+static grub_err_t
+plainmount_configure_sectors (grub_cryptodisk_t dev, grub_disk_t disk,
+                              grub_size_t sector_size, grub_size_t offset)
+{
+  grub_disk_addr_t total_sectors;
+  dev->log_sector_size = grub_log2ull(sector_size);
+
+  /* Convert size to sectors */
+  total_sectors = grub_disk_native_sectors (disk);
+  if (total_sectors == GRUB_DISK_SIZE_UNKNOWN)
+    return grub_error (GRUB_ERR_BAD_DEVICE,
+                       N_("cannot determine disk %s size"), disk->name);
+
+  total_sectors = grub_convert_sector (total_sectors, GRUB_DISK_SECTOR_BITS,
+                                       dev->log_sector_size);
+  if (total_sectors == 0)
+    return grub_error (GRUB_ERR_BAD_DEVICE,
+                       N_("cannot set specified sector size on disk %s"), 
disk->name);
+
+  /* Convert offset to sectors */
+  dev->offset_sectors = grub_divmod64 (offset, sector_size, NULL);
+  if (total_sectors <= dev->offset_sectors)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       N_("specified disk offset is larger than disk size"));
+
+  /* Adjust device size for offset */
+  dev->total_sectors = total_sectors - dev->offset_sectors;
+  grub_dprintf ("plainmount", "log_sector_size=%d, 
total_sectors=%"PRIuGRUB_SIZE
+                ", offset_sectors=%"PRIuGRUB_SIZE"\n", dev->log_sector_size,
+                dev->total_sectors, dev->offset_sectors);
+  return GRUB_ERR_NONE;
+}
+
+
+/* Hashes a password into a key and stores it with cipher. */
+static grub_err_t
+plainmount_configure_password (grub_cryptodisk_t dev, grub_disk_t disk, char 
*hash,
+                               grub_uint8_t *key_data, grub_size_t key_size)
+{
+  const gcry_md_spec_t *gcry_hash;
+  grub_uint8_t derived_hash[GRUB_CRYPTODISK_MAX_KEYLEN * 2], *dh = 
derived_hash;
+  char *p;
+  unsigned int round, i;
+  unsigned int len, size;
+
+  /* Option -p was not set */
+  if (key_data[0] == '\0')
+  {
+    char *part = grub_partition_get_name (disk->partition);
+    grub_printf_ (N_("Enter passphrase for %s%s%s: "), disk->name,
+                  disk->partition != NULL ? "," : "",
+                  part != NULL ? part : N_("UNKNOWN"));
+    grub_free (part);
+
+    if (!grub_password_get ((char*)key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE-1))
+        grub_error (GRUB_ERR_BAD_ARGUMENT, N_("error reading password"));
+  }
+
+  /* Support none (plain) hash */
+  if (grub_strcmp (hash, "plain") == 0)
+    {
+      dev->hash = NULL;
+      return plainmount_setkey (dev, key_data, key_size);
+    }
+
+  /* Check hash */
+  gcry_hash = grub_crypto_lookup_md_by_name (hash);
+  if (!gcry_hash)
+    return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+                       N_("couldn't load %s hash"),
+                       hash);
+
+  if (gcry_hash->mdlen > GRUB_CRYPTODISK_MAX_KEYLEN)
+        return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                           N_("hash length %"PRIuGRUB_SIZE
+                              " exceeds maximum %d bits"),
+                           gcry_hash->mdlen * BITS_PER_BYTE,
+                           GRUB_CRYPTODISK_MAX_KEYLEN * BITS_PER_BYTE);
+
+  dev->hash = gcry_hash;
+  len = dev->hash->mdlen;
+  p = grub_malloc (key_size + 2 + key_size / len);
+  if (!p)
+    return GRUB_ERR_OUT_OF_MEMORY;
+
+  /* Hash password. Adapted from cryptsetup.
+     https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/lib/crypt_plain.c
+  */
+  for (round = 0, size = key_size; size; round++, dh += len, size -= len)
+    {
+      for (i = 0; i < round; i++)
+       p[i] = 'A';
+
+      grub_strcpy (p + i, (char*)key_data);
+
+      if (len > size)
+       len = size;
+
+      grub_crypto_hash (dev->hash, dh, p, grub_strlen (p));
+    }
+  grub_free (p);
+  return plainmount_setkey (dev, derived_hash, key_size);
+}
+
+
+/* Read keyfile as a file */
+static grub_err_t
+plainmount_configure_keyfile (grub_cryptodisk_t dev, char *keyfile, 
grub_uint8_t *key_data,
+                              grub_size_t key_size, grub_size_t keyfile_offset)
+{
+  grub_file_t g_keyfile = grub_file_open (keyfile, GRUB_FILE_TYPE_NONE);
+  if (!keyfile)
+      return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("cannot open keyfile %s"),
+                       keyfile);
+
+  if (grub_file_seek (g_keyfile, keyfile_offset) == (grub_off_t)-1)
+      return grub_error (GRUB_ERR_FILE_READ_ERROR,
+                        N_("cannot seek keyfile at offset %"PRIuGRUB_SIZE),
+                        keyfile_offset);
+
+  if (key_size > (g_keyfile->size - keyfile_offset))
+      return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                         N_("Specified key size (%"PRIuGRUB_SIZE") is too 
small"
+                            " for keyfile size (%"PRIuGRUB_SIZE") and offset 
(%"
+                            PRIuGRUB_SIZE")"),
+                         key_size, g_keyfile->size, keyfile_offset);
+
+  if (grub_file_read (g_keyfile, key_data, key_size) != (grub_ssize_t) 
key_size)
+     return grub_error (GRUB_ERR_FILE_READ_ERROR, N_("error reading key 
file"));
+
+  return plainmount_setkey (dev, key_data, key_size);
+}
+
+
+/* Read keyfile as a disk segment */
+static grub_err_t
+plainmount_configure_keydisk (grub_cryptodisk_t dev, char *keyfile, 
grub_uint8_t *key_data,
+                              grub_size_t key_size, grub_size_t keyfile_offset)
+{
+  char *keydisk_name = grub_file_get_device_name (keyfile);
+  grub_disk_t keydisk = grub_disk_open (keyfile);
+  if (!keydisk)
+    {
+      grub_free (keydisk_name);
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unable to open key disk 
%s"), keydisk_name);
+    }
+  if (grub_disk_read (keydisk, 0, keyfile_offset, key_size, key_data) != 
GRUB_ERR_NONE)
+    {
+      grub_free (keydisk_name);
+      grub_disk_close (keydisk);
+      return grub_error (GRUB_ERR_READ_ERROR, N_("failed to read key from disk 
%s"), keydisk_name);
+    }
+  return plainmount_setkey (dev, key_data, key_size);
+}
+
+
+/* Plainmount command entry point */
+static grub_err_t
+grub_cmd_plainmount (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+  struct grub_arg_list *state = ctxt->state;
+  struct grub_plainmount_args cargs = {0};
+  grub_cryptodisk_t dev = NULL;
+  char *diskname, *disklast = NULL;
+  grub_size_t len;
+  grub_err_t err;
+  const char *p;
+
+  if (argc < 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("device name required"));
+
+  /* Check whether required arguments are specified */
+  if (!state[OPTION_CIPHER].set || !state[OPTION_KEY_SIZE].set)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "cipher and key size must be 
set");
+  if (!state[OPTION_HASH].set && !state[OPTION_KEYFILE].set)
+      return grub_error (GRUB_ERR_BAD_ARGUMENT, "hash algorithm must be set");
+
+  /* Check cipher mode */
+  if (!grub_strchr (state[OPTION_CIPHER].arg,'-'))
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       N_("invalid cipher mode, must be of format 
cipher-mode"));
+
+  /* Check password size */
+  if (state[OPTION_PASSWORD].set &&
+      grub_strlen (state[OPTION_PASSWORD].arg) + 1 > 
GRUB_CRYPTODISK_MAX_PASSPHRASE)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("password exceeds maximium 
size"));
+
+  /* Check uuid length */
+  if (state[OPTION_UUID].set &&
+      grub_strlen (state[OPTION_UUID].arg) > sizeof (PLAINMOUNT_DEFAULT_UUID))
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("device UUID exceeds maximum 
size"));
+
+  /* Parse cmdline arguments */
+  cargs.offset = plainmount_parse_blocklist (args[0]);
+  if (cargs.offset == (grub_size_t)-1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot parse disk %s"), 
args[0]);
+  if (state[OPTION_KEYFILE].set)
+    {
+      cargs.keyfile_offset = plainmount_parse_blocklist 
(state[OPTION_KEYFILE].arg);
+      if (cargs.keyfile_offset == (grub_size_t)-1)
+        return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot parse keyfile 
%s"),
+                           state[OPTION_KEYFILE].arg);
+    }
+
+  grub_errno = GRUB_ERR_NONE;
+  cargs.sector_size = state[OPTION_SECTOR_SIZE].set ?
+    grub_strtoull (state[OPTION_SECTOR_SIZE].arg, &p, 0) : 
PLAINMOUNT_DEFAULT_SECTOR_SIZE;
+  if (state[OPTION_SECTOR_SIZE].set && (*p != '\0' || grub_errno != 
GRUB_ERR_NONE))
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized sector size"));
+
+  cargs.key_size = grub_strtoull (state[OPTION_KEY_SIZE].arg, &p, 0) / 
BITS_PER_BYTE;
+  if (*p != '\0' || grub_errno != GRUB_ERR_NONE)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized key size"));
+
+  /* Check key size */
+  if (cargs.key_size > GRUB_CRYPTODISK_MAX_KEYLEN)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("key size %"PRIuGRUB_SIZE
+                                                 " exceeds maximum %d bits"),
+                       cargs.key_size * BITS_PER_BYTE,
+                       GRUB_CRYPTODISK_MAX_KEYLEN * BITS_PER_BYTE);
+
+  /* Check disk sector size */
+  if (cargs.sector_size < 512)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "sector size -S must be at least 
512");
+  if ((cargs.sector_size & (cargs.sector_size - 1)) != 0)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       N_("sector size -S %"PRIuGRUB_SIZE" is not power of 2"),
+                       cargs.sector_size);
+
+  /* Allocate all stuff here */
+  cargs.hash =  state[OPTION_HASH].set ? grub_strdup (state[OPTION_HASH].arg) 
: NULL;
+  cargs.cipher = grub_strdup (state[OPTION_CIPHER].arg);
+  cargs.keyfile = state[OPTION_KEYFILE].set ? grub_strdup 
(state[OPTION_KEYFILE].arg) : NULL;
+  dev = grub_zalloc (sizeof *dev);
+  cargs.key_data = grub_zalloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+  cargs.uuid = state[OPTION_UUID].set ? grub_strdup (state[OPTION_UUID].arg) : 
NULL;
+  if ((!cargs.hash && state[OPTION_HASH].set) || !cargs.cipher ||
+      (!cargs.keyfile && state[OPTION_KEYFILE].set) || !dev || !cargs.key_data 
||
+      (!cargs.uuid && state[OPTION_UUID].set))
+    {
+      err = grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+      goto exit;
+    }
+
+  /* Copy user password from -p option */
+  if (state[OPTION_PASSWORD].set)
+    grub_memcpy (cargs.key_data, state[OPTION_PASSWORD].arg,
+                 grub_strlen (state[OPTION_PASSWORD].arg));
+
+  /* Copy user UUID from -u option */
+  if (state[OPTION_UUID].set)
+    grub_memcpy (cargs.uuid, state[OPTION_UUID].arg, grub_strlen 
(state[OPTION_UUID].arg));
+
+  /* Set cipher mode (tested above) */
+  cargs.mode = grub_strchr (cargs.cipher,'-');
+  *cargs.mode++ = '\0';
+
+  /* Check cipher */
+  if (grub_cryptodisk_setcipher (dev, cargs.cipher, cargs.mode) != 
GRUB_ERR_NONE)
+    {
+      err = grub_error (GRUB_ERR_BAD_ARGUMENT,
+                       N_("invalid cipher %s"), cargs.cipher);
+      goto exit;
+    }
+
+  /* Open SOURCE disk */
+  diskname = args[0];
+  len = grub_strlen (diskname);
+  if (len && diskname[0] == '(' && diskname[len - 1] == ')')
+    {
+      disklast = &diskname[len - 1];
+      *disklast = '\0';
+      diskname++;
+    }
+  cargs.disk = grub_disk_open (diskname);
+  if (!cargs.disk)
+    {
+      if (disklast)
+        *disklast = ')';
+      err = grub_error (GRUB_ERR_BAD_ARGUMENT,
+                        N_("cannot open disk %s"), diskname);
+      goto exit;
+    }
+
+  /* Warn if hash and keyfile are both provided */
+  if (cargs.keyfile && state[OPTION_HASH].arg)
+    grub_printf_ (N_("warning: hash is ignored if keyfile is specified\n"));
+
+  /* Warn if -p option is specified with keyfile */
+  if (state[OPTION_PASSWORD].set && state[OPTION_KEYFILE].set)
+    grub_printf_ (N_("warning: password specified with -p option "
+                     "is ignored if keyfile is provided\n"));
+
+  grub_dprintf ("plainmount",
+              "parameters: cipher=%s, hash=%s, key_size=%"PRIuGRUB_SIZE
+             ", keyfile=%s, keyfile offset=%"PRIuGRUB_SIZE"\n",
+              cargs.cipher, cargs.hash, cargs.key_size,
+              cargs.keyfile, cargs.keyfile_offset);
+
+  err = plainmount_configure_sectors (dev, cargs.disk, cargs.sector_size, 
cargs.offset);
+  if (err != GRUB_ERR_NONE)
+    goto exit;
+
+  /* Configure keyfile/keydisk/password */
+  if (cargs.keyfile)
+    if (cargs.keyfile[0] == '/' ||
+       (grub_strchr (cargs.keyfile, ')') < grub_strrchr(cargs.keyfile,'/')))
+      err = plainmount_configure_keyfile (dev, cargs.keyfile, cargs.key_data,
+                                          cargs.key_size, 
cargs.keyfile_offset);
+    else
+      err = plainmount_configure_keydisk (dev, cargs.keyfile, cargs.key_data,
+                                          cargs.key_size, 
cargs.keyfile_offset);
+  else
+    err = plainmount_configure_password (dev, cargs.disk, cargs.hash,
+                                         cargs.key_data, cargs.key_size);
+  if (err != GRUB_ERR_NONE)
+    goto exit;
+
+  err = grub_cryptodisk_insert (dev, diskname, cargs.disk);
+  if (err != GRUB_ERR_NONE)
+    {
+      grub_printf_ (N_("cannot initialize cryptodisk. Check consistency "
+                       "of cipher/key size/hash arguments.\n"));
+      goto exit;
+    }
+
+  dev->modname = "plainmount";
+  dev->source_disk = cargs.disk;
+  plainmount_set_uuid (dev, cargs.uuid);
+
+exit:
+  grub_free (cargs.hash);
+  grub_free (cargs.cipher);
+  grub_free (cargs.keyfile);
+  grub_free (cargs.key_data);
+  grub_free (cargs.uuid);
+  if (err != GRUB_ERR_NONE && cargs.disk)
+    grub_disk_close (cargs.disk);
+  if (err != GRUB_ERR_NONE && dev)
+    grub_free (dev);
+  return err;
+}
+
+static grub_extcmd_t cmd;
+GRUB_MOD_INIT (plainmount)
+{
+  cmd = grub_register_extcmd ("plainmount", grub_cmd_plainmount, 0,
+                             N_("-c cipher -s key-size [-h hash] "
+                             " [-S sector-size] [-p password] [-u uuid] "
+                             " [-d keyfile] <SOURCE>"),
+                             N_("Open partition encrypted in plain mode."),
+                             options);
+}
+
+GRUB_MOD_FINI (plainmount)
+{
+  grub_unregister_extcmd (cmd);
+}
--
2.36.1





reply via email to

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