geli v5 (including rekeying support)
This commit is contained in:
parent
3e90811d88
commit
88ac3146d6
5 changed files with 79 additions and 11 deletions
|
@ -178,7 +178,7 @@ lrw_xor (const struct lrw_sector *sec,
|
||||||
}
|
}
|
||||||
|
|
||||||
gcry_err_code_t
|
gcry_err_code_t
|
||||||
grub_cryptodisk_decrypt (const struct grub_cryptodisk *dev,
|
grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
||||||
grub_uint8_t * data, grub_size_t len,
|
grub_uint8_t * data, grub_size_t len,
|
||||||
grub_disk_addr_t sector)
|
grub_disk_addr_t sector)
|
||||||
{
|
{
|
||||||
|
@ -186,7 +186,7 @@ grub_cryptodisk_decrypt (const struct grub_cryptodisk *dev,
|
||||||
gcry_err_code_t err;
|
gcry_err_code_t err;
|
||||||
|
|
||||||
/* The only mode without IV. */
|
/* The only mode without IV. */
|
||||||
if (dev->mode == GRUB_CRYPTODISK_MODE_ECB)
|
if (dev->mode == GRUB_CRYPTODISK_MODE_ECB && !dev->rekey)
|
||||||
return grub_crypto_ecb_decrypt (dev->cipher, data, data, len);
|
return grub_crypto_ecb_decrypt (dev->cipher, data, data, len);
|
||||||
|
|
||||||
for (i = 0; i < len; i += (1U << dev->log_sector_size))
|
for (i = 0; i < len; i += (1U << dev->log_sector_size))
|
||||||
|
@ -196,6 +196,18 @@ grub_cryptodisk_decrypt (const struct grub_cryptodisk *dev,
|
||||||
/ sizeof (grub_uint32_t));
|
/ sizeof (grub_uint32_t));
|
||||||
grub_uint32_t iv[sz];
|
grub_uint32_t iv[sz];
|
||||||
|
|
||||||
|
if (dev->rekey)
|
||||||
|
{
|
||||||
|
grub_uint64_t zone = sector >> dev->rekey_shift;
|
||||||
|
if (zone != dev->last_rekey)
|
||||||
|
{
|
||||||
|
err = dev->rekey (dev, zone);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
dev->last_rekey = zone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
grub_memset (iv, 0, sz * sizeof (iv[0]));
|
grub_memset (iv, 0, sz * sizeof (iv[0]));
|
||||||
switch (dev->mode_iv)
|
switch (dev->mode_iv)
|
||||||
{
|
{
|
||||||
|
@ -291,6 +303,10 @@ grub_cryptodisk_decrypt (const struct grub_cryptodisk *dev,
|
||||||
lrw_xor (&sec, dev, data + i);
|
lrw_xor (&sec, dev, data + i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case GRUB_CRYPTODISK_MODE_ECB:
|
||||||
|
grub_crypto_ecb_decrypt (dev->cipher, data + i, data + i,
|
||||||
|
(1U << dev->log_sector_size));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return GPG_ERR_NOT_IMPLEMENTED;
|
return GPG_ERR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,28 @@ static const struct grub_arg_option options[] =
|
||||||
static int check_uuid, have_it;
|
static int check_uuid, have_it;
|
||||||
static char *search_uuid;
|
static char *search_uuid;
|
||||||
|
|
||||||
|
static gcry_err_code_t
|
||||||
|
geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno)
|
||||||
|
{
|
||||||
|
gcry_err_code_t gcry_err;
|
||||||
|
const struct {
|
||||||
|
char magic[4];
|
||||||
|
grub_uint64_t zone;
|
||||||
|
} __attribute__ ((packed)) tohash
|
||||||
|
= { {'e', 'k', 'e', 'y'}, grub_cpu_to_le64 (zoneno) };
|
||||||
|
grub_uint64_t key[(dev->hash->mdlen + 7) / 8];
|
||||||
|
|
||||||
|
grub_dprintf ("geli", "rekeying %" PRIuGRUB_UINT64_T " keysize=%d\n",
|
||||||
|
zoneno, dev->rekey_derived_size);
|
||||||
|
gcry_err = grub_crypto_hmac_buffer (dev->hash, dev->rekey_key, 64,
|
||||||
|
&tohash, sizeof (tohash), key);
|
||||||
|
if (gcry_err)
|
||||||
|
return grub_crypto_gcry_error (gcry_err);
|
||||||
|
|
||||||
|
return grub_cryptodisk_setkey (dev, (grub_uint8_t *) key,
|
||||||
|
dev->rekey_derived_size);
|
||||||
|
}
|
||||||
|
|
||||||
static grub_cryptodisk_t
|
static grub_cryptodisk_t
|
||||||
configure_ciphers (const struct grub_geli_phdr *header)
|
configure_ciphers (const struct grub_geli_phdr *header)
|
||||||
{
|
{
|
||||||
|
@ -115,8 +137,8 @@ configure_ciphers (const struct grub_geli_phdr *header)
|
||||||
|
|
||||||
/* Look for GELI magic sequence. */
|
/* Look for GELI magic sequence. */
|
||||||
if (grub_memcmp (header->magic, GELI_MAGIC, sizeof (GELI_MAGIC))
|
if (grub_memcmp (header->magic, GELI_MAGIC, sizeof (GELI_MAGIC))
|
||||||
|| grub_le_to_cpu32 (header->version) > 3
|
|| grub_le_to_cpu32 (header->version) > 5
|
||||||
|| grub_le_to_cpu32 (header->version) < 2)
|
|| grub_le_to_cpu32 (header->version) < 1)
|
||||||
{
|
{
|
||||||
grub_dprintf ("geli", "wrong magic %02x\n", header->magic[0]);
|
grub_dprintf ("geli", "wrong magic %02x\n", header->magic[0]);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -212,6 +234,12 @@ configure_ciphers (const struct grub_geli_phdr *header)
|
||||||
for (newdev->log_sector_size = 0;
|
for (newdev->log_sector_size = 0;
|
||||||
(1U << newdev->log_sector_size) < grub_le_to_cpu32 (header->sector_size);
|
(1U << newdev->log_sector_size) < grub_le_to_cpu32 (header->sector_size);
|
||||||
newdev->log_sector_size++);
|
newdev->log_sector_size++);
|
||||||
|
|
||||||
|
if (grub_le_to_cpu32 (header->version) >= 5)
|
||||||
|
{
|
||||||
|
newdev->rekey = geli_rekey;
|
||||||
|
newdev->rekey_shift = 20;
|
||||||
|
}
|
||||||
#if 0
|
#if 0
|
||||||
grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid));
|
grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid));
|
||||||
#endif
|
#endif
|
||||||
|
@ -325,10 +353,23 @@ recover_key (grub_cryptodisk_t dev, const struct grub_geli_phdr *header,
|
||||||
grub_printf ("Slot %d opened\n", i);
|
grub_printf ("Slot %d opened\n", i);
|
||||||
|
|
||||||
/* Set the master key. */
|
/* Set the master key. */
|
||||||
gcry_err = grub_cryptodisk_setkey (dev, candidate_key.cipher_key,
|
if (!dev->rekey)
|
||||||
keysize);
|
{
|
||||||
if (gcry_err)
|
gcry_err = grub_cryptodisk_setkey (dev, candidate_key.cipher_key,
|
||||||
return grub_crypto_gcry_error (gcry_err);
|
keysize);
|
||||||
|
if (gcry_err)
|
||||||
|
return grub_crypto_gcry_error (gcry_err);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* For a reason I don't know, the IV key is used in rekeying. */
|
||||||
|
grub_memcpy (dev->rekey_key, candidate_key.iv_key,
|
||||||
|
sizeof (candidate_key.iv_key));
|
||||||
|
dev->rekey_derived_size = keysize;
|
||||||
|
dev->last_rekey = -1;
|
||||||
|
COMPILE_TIME_ASSERT (sizeof (dev->rekey_key)
|
||||||
|
>= sizeof (candidate_key.iv_key));
|
||||||
|
}
|
||||||
|
|
||||||
dev->iv_prefix_len = sizeof (candidate_key.iv_key);
|
dev->iv_prefix_len = sizeof (candidate_key.iv_key);
|
||||||
grub_memcpy (dev->iv_prefix, candidate_key.iv_key,
|
grub_memcpy (dev->iv_prefix, candidate_key.iv_key,
|
||||||
|
|
|
@ -388,7 +388,7 @@ grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out)
|
||||||
gcry_err_code_t
|
gcry_err_code_t
|
||||||
grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
|
grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
|
||||||
const void *key, grub_size_t keylen,
|
const void *key, grub_size_t keylen,
|
||||||
void *data, grub_size_t datalen, void *out)
|
const void *data, grub_size_t datalen, void *out)
|
||||||
{
|
{
|
||||||
struct grub_crypto_hmac_handle *hnd;
|
struct grub_crypto_hmac_handle *hnd;
|
||||||
|
|
||||||
|
|
|
@ -244,7 +244,7 @@ grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out);
|
||||||
gcry_err_code_t
|
gcry_err_code_t
|
||||||
grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
|
grub_crypto_hmac_buffer (const struct gcry_md_spec *md,
|
||||||
const void *key, grub_size_t keylen,
|
const void *key, grub_size_t keylen,
|
||||||
void *data, grub_size_t datalen, void *out);
|
const void *data, grub_size_t datalen, void *out);
|
||||||
|
|
||||||
extern gcry_md_spec_t _gcry_digest_spec_md5;
|
extern gcry_md_spec_t _gcry_digest_spec_md5;
|
||||||
extern gcry_md_spec_t _gcry_digest_spec_sha1;
|
extern gcry_md_spec_t _gcry_digest_spec_sha1;
|
||||||
|
|
|
@ -48,6 +48,12 @@ typedef enum
|
||||||
#define GRUB_CRYPTODISK_GF_LOG_BYTES (GRUB_CRYPTODISK_GF_LOG_SIZE - 3)
|
#define GRUB_CRYPTODISK_GF_LOG_BYTES (GRUB_CRYPTODISK_GF_LOG_SIZE - 3)
|
||||||
#define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES)
|
#define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES)
|
||||||
|
|
||||||
|
struct grub_cryptodisk;
|
||||||
|
|
||||||
|
typedef gcry_err_code_t
|
||||||
|
(*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev,
|
||||||
|
grub_uint64_t zoneno);
|
||||||
|
|
||||||
struct grub_cryptodisk
|
struct grub_cryptodisk
|
||||||
{
|
{
|
||||||
char *source;
|
char *source;
|
||||||
|
@ -74,6 +80,11 @@ struct grub_cryptodisk
|
||||||
int cheat_fd;
|
int cheat_fd;
|
||||||
#endif
|
#endif
|
||||||
int log_sector_size;
|
int log_sector_size;
|
||||||
|
grub_cryptodisk_rekey_func_t rekey;
|
||||||
|
int rekey_shift;
|
||||||
|
grub_uint8_t rekey_key[64];
|
||||||
|
grub_uint64_t last_rekey;
|
||||||
|
int rekey_derived_size;
|
||||||
struct grub_cryptodisk *next;
|
struct grub_cryptodisk *next;
|
||||||
};
|
};
|
||||||
typedef struct grub_cryptodisk *grub_cryptodisk_t;
|
typedef struct grub_cryptodisk *grub_cryptodisk_t;
|
||||||
|
@ -82,7 +93,7 @@ gcry_err_code_t
|
||||||
grub_cryptodisk_setkey (grub_cryptodisk_t dev,
|
grub_cryptodisk_setkey (grub_cryptodisk_t dev,
|
||||||
grub_uint8_t *key, grub_size_t keysize);
|
grub_uint8_t *key, grub_size_t keysize);
|
||||||
gcry_err_code_t
|
gcry_err_code_t
|
||||||
grub_cryptodisk_decrypt (const struct grub_cryptodisk *dev,
|
grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
||||||
grub_uint8_t * data, grub_size_t len,
|
grub_uint8_t * data, grub_size_t len,
|
||||||
grub_disk_addr_t sector);
|
grub_disk_addr_t sector);
|
||||||
grub_err_t
|
grub_err_t
|
||||||
|
|
Loading…
Reference in a new issue