2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2003,2007,2010,2011 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 /* This file is loosely based on FreeBSD geli implementation
20 (but no code was directly copied). FreeBSD geli is distributed under
23 * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
24 * All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
35 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 #include <grub/cryptodisk.h>
49 #include <grub/types.h>
50 #include <grub/misc.h>
54 #include <grub/disk.h>
55 #include <grub/crypto.h>
56 #include <grub/partition.h>
57 #include <grub/i18n.h>
59 GRUB_MOD_LICENSE ("GPLv3+");
61 /* Dirty trick to solve circular dependency. */
64 #include <grub/util/misc.h>
69 static const gcry_md_spec_t
*
70 grub_md_sha256_real (void)
72 const gcry_md_spec_t
*ret
;
73 ret
= grub_crypto_lookup_md_by_name ("sha256");
75 grub_util_error ("%s", _("Couldn't load sha256"));
79 static const gcry_md_spec_t
*
80 grub_md_sha512_real (void)
82 const gcry_md_spec_t
*ret
;
83 ret
= grub_crypto_lookup_md_by_name ("sha512");
85 grub_util_error ("%s", _("Couldn't load sha512"));
89 #define GRUB_MD_SHA256 grub_md_sha256_real()
90 #define GRUB_MD_SHA512 grub_md_sha512_real()
95 grub_uint8_t iv_key
[64];
96 grub_uint8_t cipher_key
[64];
97 grub_uint8_t hmac
[64];
100 struct grub_geli_phdr
102 grub_uint8_t magic
[16];
103 #define GELI_MAGIC "GEOM::ELI"
104 grub_uint32_t version
;
107 grub_uint16_t keylen
;
108 grub_uint16_t unused3
[5];
109 grub_uint32_t sector_size
;
110 grub_uint8_t keys_used
;
112 grub_uint8_t salt
[64];
113 struct grub_geli_key keys
[2];
118 GRUB_GELI_FLAGS_ONETIME
= 1,
119 GRUB_GELI_FLAGS_BOOT
= 2,
122 /* FIXME: support version 0. */
123 /* FIXME: support big-endian pre-version-4 volumes. */
124 /* FIXME: support for keyfiles. */
125 /* FIXME: support for HMAC. */
126 const char *algorithms
[] = {
131 /* FIXME: 0x05 is skipjack, but we don't have it. */
133 /* FIXME: 0x10 is null. */
134 [0x15] = "camellia128",
138 #define MAX_PASSPHRASE 256
140 static gcry_err_code_t
141 geli_rekey (struct grub_cryptodisk
*dev
, grub_uint64_t zoneno
)
143 gcry_err_code_t gcry_err
;
148 = { {'e', 'k', 'e', 'y'}, grub_cpu_to_le64 (zoneno
) };
149 GRUB_PROPERLY_ALIGNED_ARRAY (key
, GRUB_CRYPTO_MAX_MDLEN
);
151 if (dev
->hash
->mdlen
> GRUB_CRYPTO_MAX_MDLEN
)
152 return GPG_ERR_INV_ARG
;
154 grub_dprintf ("geli", "rekeying %" PRIuGRUB_UINT64_T
" keysize=%d\n",
155 zoneno
, dev
->rekey_derived_size
);
156 gcry_err
= grub_crypto_hmac_buffer (dev
->hash
, dev
->rekey_key
, 64,
157 &tohash
, sizeof (tohash
), key
);
161 return grub_cryptodisk_setkey (dev
, (grub_uint8_t
*) key
,
162 dev
->rekey_derived_size
);
165 static inline gcry_err_code_t
166 make_uuid (const struct grub_geli_phdr
*header
,
169 grub_uint8_t uuidbin
[GRUB_CRYPTODISK_MAX_UUID_LENGTH
];
174 if (2 * GRUB_MD_SHA256
->mdlen
+ 1 > GRUB_CRYPTODISK_MAX_UUID_LENGTH
)
175 return GPG_ERR_TOO_LARGE
;
176 err
= grub_crypto_hmac_buffer (GRUB_MD_SHA256
,
177 header
->salt
, sizeof (header
->salt
),
178 "uuid", sizeof ("uuid") - 1, uuidbin
);
183 for (iptr
= uuidbin
; iptr
< &uuidbin
[GRUB_MD_SHA256
->mdlen
]; iptr
++)
185 grub_snprintf (optr
, 3, "%02x", *iptr
);
189 return GPG_ERR_NO_ERROR
;
194 #include <grub/emu/hostdisk.h>
195 #include <grub/emu/misc.h>
198 grub_util_get_geli_uuid (const char *dev
)
202 unsigned log_secsize
;
203 grub_uint8_t hdr
[512];
204 struct grub_geli_phdr
*header
;
208 fd
= grub_util_fd_open (dev
, GRUB_UTIL_FD_O_RDONLY
);
210 if (!GRUB_UTIL_FD_IS_VALID (fd
))
213 s
= grub_util_get_fd_size (fd
, dev
, &log_secsize
);
215 if (grub_util_fd_seek (fd
, (s
<< log_secsize
) - 512) < 0)
216 grub_util_error ("%s", _("couldn't read ELI metadata"));
218 uuid
= xmalloc (GRUB_MD_SHA256
->mdlen
* 2 + 1);
219 if (grub_util_fd_read (fd
, (void *) &hdr
, 512) < 0)
220 grub_util_error ("%s", _("couldn't read ELI metadata"));
222 grub_util_fd_close (fd
);
224 COMPILE_TIME_ASSERT (sizeof (header
) <= 512);
225 header
= (void *) &hdr
;
227 /* Look for GELI magic sequence. */
228 if (grub_memcmp (header
->magic
, GELI_MAGIC
, sizeof (GELI_MAGIC
))
229 || grub_le_to_cpu32 (header
->version
) > 7
230 || grub_le_to_cpu32 (header
->version
) < 1)
231 grub_util_error ("%s", _("wrong ELI magic or version"));
233 err
= make_uuid ((void *) &hdr
, uuid
);
244 static grub_cryptodisk_t
245 configure_ciphers (grub_disk_t disk
, const char *check_uuid
,
248 grub_cryptodisk_t newdev
;
249 struct grub_geli_phdr header
;
250 grub_crypto_cipher_handle_t cipher
= NULL
, secondary_cipher
= NULL
;
251 const struct gcry_cipher_spec
*ciph
;
252 const char *ciphername
= NULL
;
253 gcry_err_code_t gcry_err
;
254 char uuid
[GRUB_CRYPTODISK_MAX_UUID_LENGTH
];
255 grub_disk_addr_t sector
;
258 if (2 * GRUB_MD_SHA256
->mdlen
+ 1 > GRUB_CRYPTODISK_MAX_UUID_LENGTH
)
261 sector
= grub_disk_get_size (disk
);
262 if (sector
== GRUB_DISK_SIZE_UNKNOWN
|| sector
== 0)
265 /* Read the GELI header. */
266 err
= grub_disk_read (disk
, sector
- 1, 0, sizeof (header
), &header
);
270 /* Look for GELI magic sequence. */
271 if (grub_memcmp (header
.magic
, GELI_MAGIC
, sizeof (GELI_MAGIC
))
272 || grub_le_to_cpu32 (header
.version
) > 7
273 || grub_le_to_cpu32 (header
.version
) < 1)
275 grub_dprintf ("geli", "wrong magic %02x\n", header
.magic
[0]);
279 if ((grub_le_to_cpu32 (header
.sector_size
)
280 & (grub_le_to_cpu32 (header
.sector_size
) - 1))
281 || grub_le_to_cpu32 (header
.sector_size
) == 0)
283 grub_dprintf ("geli", "incorrect sector size %d\n",
284 grub_le_to_cpu32 (header
.sector_size
));
288 if (grub_le_to_cpu32 (header
.flags
) & GRUB_GELI_FLAGS_ONETIME
)
290 grub_dprintf ("geli", "skipping one-time volume\n");
294 if (boot_only
&& !(grub_le_to_cpu32 (header
.flags
) & GRUB_GELI_FLAGS_BOOT
))
296 grub_dprintf ("geli", "not a boot volume\n");
300 gcry_err
= make_uuid (&header
, uuid
);
303 grub_crypto_gcry_error (gcry_err
);
307 if (check_uuid
&& grub_strcasecmp (check_uuid
, uuid
) != 0)
309 grub_dprintf ("geli", "%s != %s\n", uuid
, check_uuid
);
313 if (grub_le_to_cpu16 (header
.alg
) >= ARRAY_SIZE (algorithms
)
314 || algorithms
[grub_le_to_cpu16 (header
.alg
)] == NULL
)
316 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "Cipher 0x%x unknown",
317 grub_le_to_cpu16 (header
.alg
));
321 ciphername
= algorithms
[grub_le_to_cpu16 (header
.alg
)];
322 ciph
= grub_crypto_lookup_cipher_by_name (ciphername
);
325 grub_error (GRUB_ERR_FILE_NOT_FOUND
, "Cipher %s isn't available",
330 /* Configure the cipher used for the bulk data. */
331 cipher
= grub_crypto_cipher_open (ciph
);
335 if (grub_le_to_cpu16 (header
.alg
) == 0x16)
337 secondary_cipher
= grub_crypto_cipher_open (ciph
);
338 if (!secondary_cipher
)
340 grub_crypto_cipher_close (cipher
);
346 if (grub_le_to_cpu16 (header
.keylen
) > 1024)
348 grub_error (GRUB_ERR_BAD_ARGUMENT
, "invalid keysize %d",
349 grub_le_to_cpu16 (header
.keylen
));
350 grub_crypto_cipher_close (cipher
);
351 grub_crypto_cipher_close (secondary_cipher
);
355 newdev
= grub_zalloc (sizeof (struct grub_cryptodisk
));
358 grub_crypto_cipher_close (cipher
);
359 grub_crypto_cipher_close (secondary_cipher
);
362 newdev
->cipher
= cipher
;
363 newdev
->secondary_cipher
= secondary_cipher
;
365 newdev
->source_disk
= NULL
;
366 newdev
->benbi_log
= 0;
367 if (grub_le_to_cpu16 (header
.alg
) == 0x16)
369 newdev
->mode
= GRUB_CRYPTODISK_MODE_XTS
;
370 newdev
->mode_iv
= GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64
;
374 newdev
->mode
= GRUB_CRYPTODISK_MODE_CBC
;
375 newdev
->mode_iv
= GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH
;
377 newdev
->essiv_cipher
= NULL
;
378 newdev
->essiv_hash
= NULL
;
379 newdev
->hash
= GRUB_MD_SHA512
;
380 newdev
->iv_hash
= GRUB_MD_SHA256
;
382 for (newdev
->log_sector_size
= 0;
383 (1U << newdev
->log_sector_size
) < grub_le_to_cpu32 (header
.sector_size
);
384 newdev
->log_sector_size
++);
386 if (grub_le_to_cpu32 (header
.version
) >= 5)
388 newdev
->rekey
= geli_rekey
;
389 newdev
->rekey_shift
= 20;
392 newdev
->modname
= "geli";
394 newdev
->total_length
= grub_disk_get_size (disk
) - 1;
395 grub_memcpy (newdev
->uuid
, uuid
, sizeof (newdev
->uuid
));
396 COMPILE_TIME_ASSERT (sizeof (newdev
->uuid
) >= 32 * 2 + 1);
401 recover_key (grub_disk_t source
, grub_cryptodisk_t dev
)
404 grub_uint8_t digest
[GRUB_CRYPTO_MAX_MDLEN
];
405 grub_uint8_t geomkey
[GRUB_CRYPTO_MAX_MDLEN
];
406 grub_uint8_t verify_key
[GRUB_CRYPTO_MAX_MDLEN
];
407 grub_uint8_t zero
[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE
];
408 grub_uint8_t geli_cipher_key
[64];
409 char passphrase
[MAX_PASSPHRASE
] = "";
411 gcry_err_code_t gcry_err
;
412 struct grub_geli_phdr header
;
414 grub_disk_addr_t sector
;
417 if (dev
->cipher
->cipher
->blocksize
> GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE
)
418 return grub_error (GRUB_ERR_BUG
, "cipher block is too long");
420 if (dev
->hash
->mdlen
> GRUB_CRYPTO_MAX_MDLEN
)
421 return grub_error (GRUB_ERR_BUG
, "mdlen is too long");
423 sector
= grub_disk_get_size (source
);
424 if (sector
== GRUB_DISK_SIZE_UNKNOWN
|| sector
== 0)
425 return grub_error (GRUB_ERR_BUG
, "not a geli");
427 /* Read the GELI header. */
428 err
= grub_disk_read (source
, sector
- 1, 0, sizeof (header
), &header
);
432 keysize
= grub_le_to_cpu16 (header
.keylen
) / GRUB_CHAR_BIT
;
433 grub_memset (zero
, 0, sizeof (zero
));
435 grub_puts_ (N_("Attempting to decrypt master key..."));
437 /* Get the passphrase from the user. */
439 if (source
->partition
)
440 tmp
= grub_partition_get_name (source
->partition
);
441 grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source
->name
,
442 source
->partition
? "," : "", tmp
? : "",
445 if (!grub_password_get (passphrase
, MAX_PASSPHRASE
))
446 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "Passphrase not supplied");
448 /* Calculate the PBKDF2 of the user supplied passphrase. */
449 if (grub_le_to_cpu32 (header
.niter
) != 0)
451 grub_uint8_t pbkdf_key
[64];
452 gcry_err
= grub_crypto_pbkdf2 (dev
->hash
, (grub_uint8_t
*) passphrase
,
453 grub_strlen (passphrase
),
455 sizeof (header
.salt
),
456 grub_le_to_cpu32 (header
.niter
),
457 pbkdf_key
, sizeof (pbkdf_key
));
460 return grub_crypto_gcry_error (gcry_err
);
462 gcry_err
= grub_crypto_hmac_buffer (dev
->hash
, NULL
, 0, pbkdf_key
,
463 sizeof (pbkdf_key
), geomkey
);
465 return grub_crypto_gcry_error (gcry_err
);
469 struct grub_crypto_hmac_handle
*hnd
;
471 hnd
= grub_crypto_hmac_init (dev
->hash
, NULL
, 0);
473 return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY
);
475 grub_crypto_hmac_write (hnd
, header
.salt
, sizeof (header
.salt
));
476 grub_crypto_hmac_write (hnd
, passphrase
, grub_strlen (passphrase
));
478 gcry_err
= grub_crypto_hmac_fini (hnd
, geomkey
);
480 return grub_crypto_gcry_error (gcry_err
);
483 gcry_err
= grub_crypto_hmac_buffer (dev
->hash
, geomkey
,
484 dev
->hash
->mdlen
, "\1", 1, digest
);
486 return grub_crypto_gcry_error (gcry_err
);
488 gcry_err
= grub_crypto_hmac_buffer (dev
->hash
, geomkey
,
489 dev
->hash
->mdlen
, "\0", 1, verify_key
);
491 return grub_crypto_gcry_error (gcry_err
);
493 grub_dprintf ("geli", "keylen = %" PRIuGRUB_SIZE
"\n", keysize
);
495 /* Try to recover master key from each active keyslot. */
496 for (i
= 0; i
< ARRAY_SIZE (header
.keys
); i
++)
498 struct grub_geli_key candidate_key
;
499 grub_uint8_t key_hmac
[GRUB_CRYPTO_MAX_MDLEN
];
501 /* Check if keyslot is enabled. */
502 if (! (header
.keys_used
& (1 << i
)))
505 grub_dprintf ("geli", "Trying keyslot %d\n", i
);
507 gcry_err
= grub_crypto_cipher_set_key (dev
->cipher
,
510 return grub_crypto_gcry_error (gcry_err
);
512 gcry_err
= grub_crypto_cbc_decrypt (dev
->cipher
, &candidate_key
,
514 sizeof (candidate_key
),
517 return grub_crypto_gcry_error (gcry_err
);
519 gcry_err
= grub_crypto_hmac_buffer (dev
->hash
, verify_key
,
522 (sizeof (candidate_key
)
523 - sizeof (candidate_key
.hmac
)),
526 return grub_crypto_gcry_error (gcry_err
);
528 if (grub_memcmp (candidate_key
.hmac
, key_hmac
, dev
->hash
->mdlen
) != 0)
530 grub_printf_ (N_("Slot %d opened\n"), i
);
532 if (grub_le_to_cpu32 (header
.version
) >= 7)
534 /* GELI >=7 uses the cipher_key */
535 grub_memcpy (geli_cipher_key
, candidate_key
.cipher_key
,
536 sizeof (candidate_key
.cipher_key
));
540 /* GELI <=6 uses the iv_key */
541 grub_memcpy (geli_cipher_key
, candidate_key
.iv_key
,
542 sizeof (candidate_key
.iv_key
));
545 /* Set the master key. */
548 grub_size_t real_keysize
= keysize
;
549 if (grub_le_to_cpu16 (header
.alg
) == 0x16)
551 gcry_err
= grub_cryptodisk_setkey (dev
, candidate_key
.cipher_key
,
554 return grub_crypto_gcry_error (gcry_err
);
558 grub_size_t real_keysize
= keysize
;
559 if (grub_le_to_cpu16 (header
.alg
) == 0x16)
562 grub_memcpy (dev
->rekey_key
, geli_cipher_key
,
563 sizeof (geli_cipher_key
));
564 dev
->rekey_derived_size
= real_keysize
;
565 dev
->last_rekey
= -1;
566 COMPILE_TIME_ASSERT (sizeof (dev
->rekey_key
)
567 >= sizeof (geli_cipher_key
));
570 dev
->iv_prefix_len
= sizeof (candidate_key
.iv_key
);
571 grub_memcpy (dev
->iv_prefix
, candidate_key
.iv_key
,
572 sizeof (candidate_key
.iv_key
));
574 COMPILE_TIME_ASSERT (sizeof (dev
->iv_prefix
) >= sizeof (candidate_key
.iv_key
));
576 return GRUB_ERR_NONE
;
579 return GRUB_ACCESS_DENIED
;
582 struct grub_cryptodisk_dev geli_crypto
= {
583 .scan
= configure_ciphers
,
584 .recover_key
= recover_key
589 grub_cryptodisk_dev_register (&geli_crypto
);
594 grub_cryptodisk_dev_unregister (&geli_crypto
);