Cryptodisk write support.
* grub-core/disk/cryptodisk.c (grub_crypto_pcbc_encrypt): New function. (grub_cryptodisk_decrypt): Moved logic to ... (grub_cryptodisk_endecrypt): ...this. New argument "encrypt". (grub_cryptodisk_write): Implement. * grub-core/kern/emu/hostdisk.c (nwrite): Rename to ... (grub_util_fd_write): ... this. Make global. * include/grub/emu/hostdisk.h (grub_util_fd_write): New proto.
This commit is contained in:
parent
87cf97447e
commit
9c6e84b838
4 changed files with 137 additions and 28 deletions
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,15 @@
|
||||||
|
2012-01-29 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
Cryptodisk write support.
|
||||||
|
|
||||||
|
* grub-core/disk/cryptodisk.c (grub_crypto_pcbc_encrypt): New function.
|
||||||
|
(grub_cryptodisk_decrypt): Moved logic to ...
|
||||||
|
(grub_cryptodisk_endecrypt): ...this. New argument "encrypt".
|
||||||
|
(grub_cryptodisk_write): Implement.
|
||||||
|
* grub-core/kern/emu/hostdisk.c (nwrite): Rename to ...
|
||||||
|
(grub_util_fd_write): ... this. Make global.
|
||||||
|
* include/grub/emu/hostdisk.h (grub_util_fd_write): New proto.
|
||||||
|
|
||||||
2012-01-29 Vladimir Serbinenko <phcoder@gmail.com>
|
2012-01-29 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
* include/grub/list.h (grub_list_remove): Don't crash if element is
|
* include/grub/list.h (grub_list_remove): Don't crash if element is
|
||||||
|
|
|
@ -128,6 +128,29 @@ grub_crypto_pcbc_decrypt (grub_crypto_cipher_handle_t cipher,
|
||||||
return GPG_ERR_NO_ERROR;
|
return GPG_ERR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gcry_err_code_t
|
||||||
|
grub_crypto_pcbc_encrypt (grub_crypto_cipher_handle_t cipher,
|
||||||
|
void *out, void *in, grub_size_t size,
|
||||||
|
void *iv)
|
||||||
|
{
|
||||||
|
grub_uint8_t *inptr, *outptr, *end;
|
||||||
|
grub_uint8_t ivt[cipher->cipher->blocksize];
|
||||||
|
if (!cipher->cipher->decrypt)
|
||||||
|
return GPG_ERR_NOT_SUPPORTED;
|
||||||
|
if (size % cipher->cipher->blocksize != 0)
|
||||||
|
return GPG_ERR_INV_ARG;
|
||||||
|
end = (grub_uint8_t *) in + size;
|
||||||
|
for (inptr = in, outptr = out; inptr < end;
|
||||||
|
inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize)
|
||||||
|
{
|
||||||
|
grub_memcpy (ivt, inptr, cipher->cipher->blocksize);
|
||||||
|
grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize);
|
||||||
|
cipher->cipher->encrypt (cipher->ctx, outptr, inptr);
|
||||||
|
grub_crypto_xor (iv, ivt, outptr, cipher->cipher->blocksize);
|
||||||
|
}
|
||||||
|
return GPG_ERR_NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
struct lrw_sector
|
struct lrw_sector
|
||||||
{
|
{
|
||||||
grub_uint8_t low[GRUB_CRYPTODISK_GF_BYTES];
|
grub_uint8_t low[GRUB_CRYPTODISK_GF_BYTES];
|
||||||
|
@ -189,17 +212,18 @@ lrw_xor (const struct lrw_sector *sec,
|
||||||
dev->lrw_precalc, sec->low_byte * GRUB_CRYPTODISK_GF_BYTES);
|
dev->lrw_precalc, sec->low_byte * GRUB_CRYPTODISK_GF_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcry_err_code_t
|
static gcry_err_code_t
|
||||||
grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
grub_cryptodisk_endecrypt (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, int encrypt)
|
||||||
{
|
{
|
||||||
grub_size_t i;
|
grub_size_t i;
|
||||||
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 && !dev->rekey)
|
if (dev->mode == GRUB_CRYPTODISK_MODE_ECB && !dev->rekey)
|
||||||
return grub_crypto_ecb_decrypt (dev->cipher, data, data, len);
|
return (encrypt ? grub_crypto_ecb_encrypt (dev->cipher, data, data, len)
|
||||||
|
: 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))
|
||||||
{
|
{
|
||||||
|
@ -269,15 +293,23 @@ grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
||||||
switch (dev->mode)
|
switch (dev->mode)
|
||||||
{
|
{
|
||||||
case GRUB_CRYPTODISK_MODE_CBC:
|
case GRUB_CRYPTODISK_MODE_CBC:
|
||||||
err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i,
|
if (encrypt)
|
||||||
(1U << dev->log_sector_size), iv);
|
err = grub_crypto_cbc_encrypt (dev->cipher, data + i, data + i,
|
||||||
|
(1U << dev->log_sector_size), iv);
|
||||||
|
else
|
||||||
|
err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i,
|
||||||
|
(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,
|
if (encrypt)
|
||||||
(1U << dev->log_sector_size), iv);
|
err = grub_crypto_pcbc_encrypt (dev->cipher, data + i, data + i,
|
||||||
|
(1U << dev->log_sector_size), iv);
|
||||||
|
else
|
||||||
|
err = grub_crypto_pcbc_decrypt (dev->cipher, data + i, data + i,
|
||||||
|
(1U << dev->log_sector_size), iv);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
break;
|
break;
|
||||||
|
@ -294,9 +326,14 @@ grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
||||||
{
|
{
|
||||||
grub_crypto_xor (data + i + j, data + i + j, iv,
|
grub_crypto_xor (data + i + j, data + i + j, iv,
|
||||||
dev->cipher->cipher->blocksize);
|
dev->cipher->cipher->blocksize);
|
||||||
err = grub_crypto_ecb_decrypt (dev->cipher, data + i + j,
|
if (encrypt)
|
||||||
data + i + j,
|
err = grub_crypto_ecb_encrypt (dev->cipher, data + i + j,
|
||||||
dev->cipher->cipher->blocksize);
|
data + i + j,
|
||||||
|
dev->cipher->cipher->blocksize);
|
||||||
|
else
|
||||||
|
err = grub_crypto_ecb_decrypt (dev->cipher, data + i + j,
|
||||||
|
data + i + j,
|
||||||
|
dev->cipher->cipher->blocksize);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
grub_crypto_xor (data + i + j, data + i + j, iv,
|
grub_crypto_xor (data + i + j, data + i + j, iv,
|
||||||
|
@ -312,17 +349,26 @@ grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
||||||
generate_lrw_sector (&sec, dev, (grub_uint8_t *) iv);
|
generate_lrw_sector (&sec, dev, (grub_uint8_t *) iv);
|
||||||
lrw_xor (&sec, dev, data + i);
|
lrw_xor (&sec, dev, data + i);
|
||||||
|
|
||||||
err = grub_crypto_ecb_decrypt (dev->cipher, data + i,
|
if (encrypt)
|
||||||
data + i,
|
err = grub_crypto_ecb_encrypt (dev->cipher, data + i,
|
||||||
(1U << dev->log_sector_size));
|
data + i,
|
||||||
|
(1U << dev->log_sector_size));
|
||||||
|
else
|
||||||
|
err = grub_crypto_ecb_decrypt (dev->cipher, data + i,
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GRUB_CRYPTODISK_MODE_ECB:
|
case GRUB_CRYPTODISK_MODE_ECB:
|
||||||
grub_crypto_ecb_decrypt (dev->cipher, data + i, data + i,
|
if (encrypt)
|
||||||
(1U << dev->log_sector_size));
|
grub_crypto_ecb_encrypt (dev->cipher, data + i, data + i,
|
||||||
|
(1U << dev->log_sector_size));
|
||||||
|
else
|
||||||
|
grub_crypto_ecb_decrypt (dev->cipher, data + i, data + i,
|
||||||
|
(1U << dev->log_sector_size));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return GPG_ERR_NOT_IMPLEMENTED;
|
return GPG_ERR_NOT_IMPLEMENTED;
|
||||||
|
@ -332,6 +378,14 @@ grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
||||||
return GPG_ERR_NO_ERROR;
|
return GPG_ERR_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gcry_err_code_t
|
||||||
|
grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
||||||
|
grub_uint8_t * data, grub_size_t len,
|
||||||
|
grub_disk_addr_t sector)
|
||||||
|
{
|
||||||
|
return grub_cryptodisk_endecrypt (dev, data, len, sector, 0);
|
||||||
|
}
|
||||||
|
|
||||||
gcry_err_code_t
|
gcry_err_code_t
|
||||||
grub_cryptodisk_setkey (grub_cryptodisk_t dev, grub_uint8_t *key, grub_size_t keysize)
|
grub_cryptodisk_setkey (grub_cryptodisk_t dev, grub_uint8_t *key, grub_size_t keysize)
|
||||||
{
|
{
|
||||||
|
@ -526,19 +580,61 @@ grub_cryptodisk_read (grub_disk_t disk, grub_disk_addr_t sector,
|
||||||
grub_dprintf ("cryptodisk", "grub_disk_read failed with error %d\n", err);
|
grub_dprintf ("cryptodisk", "grub_disk_read failed with error %d\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
gcry_err = grub_cryptodisk_decrypt (dev, (grub_uint8_t *) buf,
|
gcry_err = grub_cryptodisk_endecrypt (dev, (grub_uint8_t *) buf,
|
||||||
size << disk->log_sector_size,
|
size << disk->log_sector_size,
|
||||||
sector);
|
sector, 0);
|
||||||
return grub_crypto_gcry_error (gcry_err);
|
return grub_crypto_gcry_error (gcry_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
grub_cryptodisk_write (grub_disk_t disk __attribute ((unused)),
|
grub_cryptodisk_write (grub_disk_t disk, grub_disk_addr_t sector,
|
||||||
grub_disk_addr_t sector __attribute ((unused)),
|
grub_size_t size, const char *buf)
|
||||||
grub_size_t size __attribute ((unused)),
|
|
||||||
const char *buf __attribute ((unused)))
|
|
||||||
{
|
{
|
||||||
return GRUB_ERR_NOT_IMPLEMENTED_YET;
|
grub_cryptodisk_t dev = (grub_cryptodisk_t) disk->data;
|
||||||
|
gcry_err_code_t gcry_err;
|
||||||
|
char *tmp;
|
||||||
|
grub_err_t err;
|
||||||
|
|
||||||
|
#ifdef GRUB_UTIL
|
||||||
|
if (dev->cheat)
|
||||||
|
{
|
||||||
|
err = grub_util_fd_seek (dev->cheat_fd, dev->cheat,
|
||||||
|
sector << disk->log_sector_size);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (grub_util_fd_write (dev->cheat_fd, buf, size << disk->log_sector_size)
|
||||||
|
!= (ssize_t) (size << disk->log_sector_size))
|
||||||
|
return grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'",
|
||||||
|
dev->cheat);
|
||||||
|
return GRUB_ERR_NONE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tmp = grub_malloc (size << disk->log_sector_size);
|
||||||
|
if (!tmp)
|
||||||
|
return grub_errno;
|
||||||
|
grub_memcpy (tmp, buf, size << disk->log_sector_size);
|
||||||
|
|
||||||
|
grub_dprintf ("cryptodisk",
|
||||||
|
"Writing %" PRIuGRUB_SIZE " sectors to sector 0x%"
|
||||||
|
PRIxGRUB_UINT64_T " with offset of %" PRIuGRUB_UINT64_T "\n",
|
||||||
|
size, sector, dev->offset);
|
||||||
|
|
||||||
|
gcry_err = grub_cryptodisk_endecrypt (dev, (grub_uint8_t *) tmp,
|
||||||
|
size << disk->log_sector_size,
|
||||||
|
sector, 1);
|
||||||
|
if (gcry_err)
|
||||||
|
{
|
||||||
|
grub_free (tmp);
|
||||||
|
return grub_crypto_gcry_error (gcry_err);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = grub_disk_write (dev->source_disk,
|
||||||
|
(sector << (disk->log_sector_size
|
||||||
|
- GRUB_DISK_SECTOR_BITS)) + dev->offset,
|
||||||
|
0, size << disk->log_sector_size, tmp);
|
||||||
|
grub_free (tmp);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GRUB_UTIL
|
#ifdef GRUB_UTIL
|
||||||
|
|
|
@ -958,8 +958,8 @@ grub_util_fd_read (int fd, char *buf, size_t len)
|
||||||
|
|
||||||
/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
|
/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
|
||||||
error occurs, otherwise return LEN. */
|
error occurs, otherwise return LEN. */
|
||||||
static ssize_t
|
ssize_t
|
||||||
nwrite (int fd, const char *buf, size_t len)
|
grub_util_fd_write (int fd, const char *buf, size_t len)
|
||||||
{
|
{
|
||||||
ssize_t size = len;
|
ssize_t size = len;
|
||||||
|
|
||||||
|
@ -1062,7 +1062,7 @@ grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
|
||||||
if (nwrite (fd, buf, size << disk->log_sector_size)
|
if (grub_util_fd_write (fd, buf, size << disk->log_sector_size)
|
||||||
!= (ssize_t) (size << disk->log_sector_size))
|
!= (ssize_t) (size << disk->log_sector_size))
|
||||||
grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
|
grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ void grub_util_pull_device (const char *osname);
|
||||||
grub_err_t
|
grub_err_t
|
||||||
grub_util_fd_seek (int fd, const char *name, grub_uint64_t sector);
|
grub_util_fd_seek (int fd, const char *name, grub_uint64_t sector);
|
||||||
ssize_t grub_util_fd_read (int fd, char *buf, size_t len);
|
ssize_t grub_util_fd_read (int fd, char *buf, size_t len);
|
||||||
|
ssize_t grub_util_fd_write (int fd, const char *buf, size_t len);
|
||||||
grub_err_t
|
grub_err_t
|
||||||
grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat);
|
grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat);
|
||||||
void grub_util_cryptodisk_print_uuid (grub_disk_t disk);
|
void grub_util_cryptodisk_print_uuid (grub_disk_t disk);
|
||||||
|
|
Loading…
Reference in a new issue