support non-512B sectors for geli

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-04-24 14:59:38 +02:00
parent ae13460ee1
commit 3e90811d88
4 changed files with 49 additions and 24 deletions

View file

@ -35,7 +35,10 @@ GRUB_MOD_LICENSE ("GPLv3+");
/* Our irreducible polynom is x^128+x^7+x^2+x+1. Lowest byte of it is: */ /* Our irreducible polynom is x^128+x^7+x^2+x+1. Lowest byte of it is: */
#define GF_POLYNOM 0x87 #define GF_POLYNOM 0x87
#define GF_PER_SECTOR (GRUB_DISK_SECTOR_SIZE / GRUB_CRYPTODISK_GF_BYTES) static inline int GF_PER_SECTOR (const struct grub_cryptodisk *dev)
{
return 1U << (dev->log_sector_size - GRUB_CRYPTODISK_GF_LOG_BYTES);
}
static grub_cryptodisk_t cryptodisk_list = NULL; static grub_cryptodisk_t cryptodisk_list = NULL;
static grub_uint8_t n = 0; static grub_uint8_t n = 0;
@ -44,7 +47,7 @@ static void
gf_mul_x (grub_uint8_t *g) gf_mul_x (grub_uint8_t *g)
{ {
int over = 0, over2 = 0; int over = 0, over2 = 0;
int j; unsigned j;
for (j = 0; j < GRUB_CRYPTODISK_GF_BYTES; j++) for (j = 0; j < GRUB_CRYPTODISK_GF_BYTES; j++)
{ {
@ -64,7 +67,7 @@ gf_mul_x_be (grub_uint8_t *g)
int over = 0, over2 = 0; int over = 0, over2 = 0;
int j; int j;
for (j = GRUB_CRYPTODISK_GF_BYTES - 1; j >= 0; j--) for (j = (int) GRUB_CRYPTODISK_GF_BYTES - 1; j >= 0; j--)
{ {
over2 = !!(g[j] & 0x80); over2 = !!(g[j] & 0x80);
g[j] <<= 1; g[j] <<= 1;
@ -78,7 +81,7 @@ gf_mul_x_be (grub_uint8_t *g)
static void static void
gf_mul_be (grub_uint8_t *o, const grub_uint8_t *a, const grub_uint8_t *b) gf_mul_be (grub_uint8_t *o, const grub_uint8_t *a, const grub_uint8_t *b)
{ {
int i; unsigned i;
grub_uint8_t t[GRUB_CRYPTODISK_GF_BYTES]; grub_uint8_t t[GRUB_CRYPTODISK_GF_BYTES];
grub_memset (o, 0, GRUB_CRYPTODISK_GF_BYTES); grub_memset (o, 0, GRUB_CRYPTODISK_GF_BYTES);
grub_memcpy (t, b, GRUB_CRYPTODISK_GF_BYTES); grub_memcpy (t, b, GRUB_CRYPTODISK_GF_BYTES);
@ -129,14 +132,15 @@ generate_lrw_sector (struct lrw_sector *sec,
grub_uint16_t c; grub_uint16_t c;
int j; int j;
grub_memcpy (idx, iv, GRUB_CRYPTODISK_GF_BYTES); grub_memcpy (idx, iv, GRUB_CRYPTODISK_GF_BYTES);
sec->low_byte = (idx[GRUB_CRYPTODISK_GF_BYTES - 1] & (GF_PER_SECTOR - 1)); sec->low_byte = (idx[GRUB_CRYPTODISK_GF_BYTES - 1]
sec->low_byte_c = (((GF_PER_SECTOR - 1) & ~sec->low_byte) + 1); & (GF_PER_SECTOR (dev) - 1));
idx[GRUB_CRYPTODISK_GF_BYTES - 1] &= ~(GF_PER_SECTOR - 1); sec->low_byte_c = (((GF_PER_SECTOR (dev) - 1) & ~sec->low_byte) + 1);
idx[GRUB_CRYPTODISK_GF_BYTES - 1] &= ~(GF_PER_SECTOR (dev) - 1);
gf_mul_be (sec->low, dev->lrw_key, idx); gf_mul_be (sec->low, dev->lrw_key, idx);
if (!sec->low_byte) if (!sec->low_byte)
return; return;
c = idx[GRUB_CRYPTODISK_GF_BYTES - 1] + GF_PER_SECTOR; c = idx[GRUB_CRYPTODISK_GF_BYTES - 1] + GF_PER_SECTOR (dev);
if (c & 0x100) if (c & 0x100)
{ {
for (j = GRUB_CRYPTODISK_GF_BYTES - 2; j >= 0; j--) for (j = GRUB_CRYPTODISK_GF_BYTES - 2; j >= 0; j--)
@ -155,9 +159,10 @@ lrw_xor (const struct lrw_sector *sec,
const struct grub_cryptodisk *dev, const struct grub_cryptodisk *dev,
grub_uint8_t *b) grub_uint8_t *b)
{ {
int i; unsigned i;
for (i = 0; i < sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES; i += GRUB_CRYPTODISK_GF_BYTES) for (i = 0; i < sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES;
i += GRUB_CRYPTODISK_GF_BYTES)
grub_crypto_xor (b + i, b + i, sec->low, GRUB_CRYPTODISK_GF_BYTES); grub_crypto_xor (b + i, b + i, sec->low, GRUB_CRYPTODISK_GF_BYTES);
grub_crypto_xor (b, b, dev->lrw_precalc + GRUB_CRYPTODISK_GF_BYTES * sec->low_byte, grub_crypto_xor (b, b, dev->lrw_precalc + GRUB_CRYPTODISK_GF_BYTES * sec->low_byte,
sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES); sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES);
@ -165,7 +170,7 @@ lrw_xor (const struct lrw_sector *sec,
return; return;
for (i = sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES; for (i = sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES;
i < GRUB_DISK_SECTOR_SIZE; i += GRUB_CRYPTODISK_GF_BYTES) i < (1U << dev->log_sector_size); i += GRUB_CRYPTODISK_GF_BYTES)
grub_crypto_xor (b + i, b + i, sec->high, GRUB_CRYPTODISK_GF_BYTES); grub_crypto_xor (b + i, b + i, sec->high, GRUB_CRYPTODISK_GF_BYTES);
grub_crypto_xor (b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES, grub_crypto_xor (b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES,
b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES, b + sec->low_byte_c * GRUB_CRYPTODISK_GF_BYTES,
@ -184,7 +189,7 @@ grub_cryptodisk_decrypt (const struct grub_cryptodisk *dev,
if (dev->mode == GRUB_CRYPTODISK_MODE_ECB) if (dev->mode == GRUB_CRYPTODISK_MODE_ECB)
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 += GRUB_DISK_SECTOR_SIZE) for (i = 0; i < len; i += (1U << dev->log_sector_size))
{ {
grub_size_t sz = ((dev->cipher->cipher->blocksize grub_size_t sz = ((dev->cipher->cipher->blocksize
+ sizeof (grub_uint32_t) - 1) + sizeof (grub_uint32_t) - 1)
@ -203,7 +208,7 @@ grub_cryptodisk_decrypt (const struct grub_cryptodisk *dev,
grub_memset (ctx, 0, sizeof (ctx)); grub_memset (ctx, 0, sizeof (ctx));
tmp = grub_cpu_to_le64 (sector << GRUB_DISK_SECTOR_BITS); tmp = grub_cpu_to_le64 (sector << dev->log_sector_size);
dev->iv_hash->init (ctx); dev->iv_hash->init (ctx);
dev->iv_hash->write (ctx, dev->iv_prefix, dev->iv_prefix_len); dev->iv_hash->write (ctx, dev->iv_prefix, dev->iv_prefix_len);
dev->iv_hash->write (ctx, &tmp, sizeof (tmp)); dev->iv_hash->write (ctx, &tmp, sizeof (tmp));
@ -236,26 +241,26 @@ grub_cryptodisk_decrypt (const struct grub_cryptodisk *dev,
{ {
case GRUB_CRYPTODISK_MODE_CBC: case GRUB_CRYPTODISK_MODE_CBC:
err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i, err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i,
GRUB_DISK_SECTOR_SIZE, iv); (1U << dev->log_sector_size), iv);
if (err) if (err)
return err; return err;
break; break;
case GRUB_CRYPTODISK_MODE_PCBC: case GRUB_CRYPTODISK_MODE_PCBC:
err = grub_crypto_pcbc_decrypt (dev->cipher, data + i, data + i, err = grub_crypto_pcbc_decrypt (dev->cipher, data + i, data + i,
GRUB_DISK_SECTOR_SIZE, iv); (1U << dev->log_sector_size), iv);
if (err) if (err)
return err; return err;
break; break;
case GRUB_CRYPTODISK_MODE_XTS: case GRUB_CRYPTODISK_MODE_XTS:
{ {
int j; unsigned j;
err = grub_crypto_ecb_encrypt (dev->secondary_cipher, iv, iv, err = grub_crypto_ecb_encrypt (dev->secondary_cipher, iv, iv,
dev->cipher->cipher->blocksize); dev->cipher->cipher->blocksize);
if (err) if (err)
return err; return err;
for (j = 0; j < GRUB_DISK_SECTOR_SIZE; for (j = 0; j < (1U << dev->log_sector_size);
j += dev->cipher->cipher->blocksize) j += dev->cipher->cipher->blocksize)
{ {
grub_crypto_xor (data + i + j, data + i + j, iv, grub_crypto_xor (data + i + j, data + i + j, iv,
@ -279,7 +284,8 @@ grub_cryptodisk_decrypt (const struct grub_cryptodisk *dev,
lrw_xor (&sec, dev, data + i); lrw_xor (&sec, dev, data + i);
err = grub_crypto_ecb_decrypt (dev->cipher, data + i, err = grub_crypto_ecb_decrypt (dev->cipher, data + i,
data + i, GRUB_DISK_SECTOR_SIZE); data + i,
(1U << dev->log_sector_size));
if (err) if (err)
return err; return err;
lrw_xor (&sec, dev, data + i); lrw_xor (&sec, dev, data + i);
@ -333,17 +339,17 @@ grub_cryptodisk_setkey (grub_cryptodisk_t dev, grub_uint8_t *key, grub_size_t ke
if (dev->mode == GRUB_CRYPTODISK_MODE_LRW) if (dev->mode == GRUB_CRYPTODISK_MODE_LRW)
{ {
int i; unsigned i;
grub_uint8_t idx[GRUB_CRYPTODISK_GF_BYTES]; grub_uint8_t idx[GRUB_CRYPTODISK_GF_BYTES];
grub_free (dev->lrw_precalc); grub_free (dev->lrw_precalc);
grub_memcpy (dev->lrw_key, key + real_keysize, grub_memcpy (dev->lrw_key, key + real_keysize,
dev->cipher->cipher->blocksize); dev->cipher->cipher->blocksize);
dev->lrw_precalc = grub_malloc (GRUB_DISK_SECTOR_SIZE); dev->lrw_precalc = grub_malloc ((1U << dev->log_sector_size));
if (!dev->lrw_precalc) if (!dev->lrw_precalc)
return GPG_ERR_OUT_OF_MEMORY; return GPG_ERR_OUT_OF_MEMORY;
grub_memset (idx, 0, GRUB_CRYPTODISK_GF_BYTES); grub_memset (idx, 0, GRUB_CRYPTODISK_GF_BYTES);
for (i = 0; i < GRUB_DISK_SECTOR_SIZE; for (i = 0; i < (1U << dev->log_sector_size);
i += GRUB_CRYPTODISK_GF_BYTES) i += GRUB_CRYPTODISK_GF_BYTES)
{ {
idx[GRUB_CRYPTODISK_GF_BYTES - 1] = i / GRUB_CRYPTODISK_GF_BYTES; idx[GRUB_CRYPTODISK_GF_BYTES - 1] = i / GRUB_CRYPTODISK_GF_BYTES;
@ -401,6 +407,8 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk,
if (!dev) if (!dev)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device"); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
disk->log_sector_size = dev->log_sector_size;
#ifdef GRUB_UTIL #ifdef GRUB_UTIL
if (dev->cheat) if (dev->cheat)
{ {

View file

@ -73,7 +73,8 @@ struct grub_geli_phdr
grub_uint32_t unused1; grub_uint32_t unused1;
grub_uint16_t alg; grub_uint16_t alg;
grub_uint16_t keylen; grub_uint16_t keylen;
grub_uint16_t unused3[7]; grub_uint16_t unused3[5];
grub_uint32_t sector_size;
grub_uint8_t keys_used; grub_uint8_t keys_used;
grub_uint32_t niter; grub_uint32_t niter;
grub_uint8_t salt[64]; grub_uint8_t salt[64];
@ -120,6 +121,14 @@ configure_ciphers (const struct grub_geli_phdr *header)
grub_dprintf ("geli", "wrong magic %02x\n", header->magic[0]); grub_dprintf ("geli", "wrong magic %02x\n", header->magic[0]);
return NULL; return NULL;
} }
if ((grub_le_to_cpu32 (header->sector_size)
& (grub_le_to_cpu32 (header->sector_size) - 1))
|| grub_le_to_cpu32 (header->sector_size) == 0)
{
grub_dprintf ("geli", "incorrect sector size %d\n",
grub_le_to_cpu32 (header->sector_size));
return NULL;
}
#if 0 #if 0
optr = uuid; optr = uuid;
@ -199,6 +208,10 @@ configure_ciphers (const struct grub_geli_phdr *header)
newdev->essiv_hash = NULL; newdev->essiv_hash = NULL;
newdev->hash = hash; newdev->hash = hash;
newdev->iv_hash = iv_hash; newdev->iv_hash = iv_hash;
for (newdev->log_sector_size = 0;
(1U << newdev->log_sector_size) < grub_le_to_cpu32 (header->sector_size);
newdev->log_sector_size++);
#if 0 #if 0
grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid)); grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid));
#endif #endif

View file

@ -283,6 +283,7 @@ configure_ciphers (const struct grub_luks_phdr *header)
newdev->essiv_cipher = essiv_cipher; newdev->essiv_cipher = essiv_cipher;
newdev->essiv_hash = essiv_hash; newdev->essiv_hash = essiv_hash;
newdev->hash = hash; newdev->hash = hash;
newdev->log_sector_size = 9;
grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid)); grub_memcpy (newdev->uuid, uuid, sizeof (newdev->uuid));
return newdev; return newdev;
} }

View file

@ -43,8 +43,10 @@ typedef enum
#define GRUB_CRYPTODISK_MAX_UUID_LENGTH 63 #define GRUB_CRYPTODISK_MAX_UUID_LENGTH 63
#define GRUB_CRYPTODISK_GF_SIZE 128 #define GRUB_CRYPTODISK_GF_LOG_SIZE 7
#define GRUB_CRYPTODISK_GF_BYTES (GRUB_CRYPTODISK_GF_SIZE / 8) #define GRUB_CRYPTODISK_GF_SIZE (1U << GRUB_CRYPTODISK_GF_LOG_SIZE)
#define GRUB_CRYPTODISK_GF_LOG_BYTES (GRUB_CRYPTODISK_GF_LOG_SIZE - 3)
#define GRUB_CRYPTODISK_GF_BYTES (1U << GRUB_CRYPTODISK_GF_LOG_BYTES)
struct grub_cryptodisk struct grub_cryptodisk
{ {
@ -71,6 +73,7 @@ struct grub_cryptodisk
char *cheat; char *cheat;
int cheat_fd; int cheat_fd;
#endif #endif
int log_sector_size;
struct grub_cryptodisk *next; struct grub_cryptodisk *next;
}; };
typedef struct grub_cryptodisk *grub_cryptodisk_t; typedef struct grub_cryptodisk *grub_cryptodisk_t;