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>
|
||||
|
||||
* 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;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
gcry_err_code_t
|
||||
grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
||||
grub_uint8_t * data, grub_size_t len,
|
||||
grub_disk_addr_t sector)
|
||||
static gcry_err_code_t
|
||||
grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev,
|
||||
grub_uint8_t * data, grub_size_t len,
|
||||
grub_disk_addr_t sector, int encrypt)
|
||||
{
|
||||
grub_size_t i;
|
||||
gcry_err_code_t err;
|
||||
|
||||
/* The only mode without IV. */
|
||||
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))
|
||||
{
|
||||
|
@ -269,15 +293,23 @@ grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
|||
switch (dev->mode)
|
||||
{
|
||||
case GRUB_CRYPTODISK_MODE_CBC:
|
||||
err = grub_crypto_cbc_decrypt (dev->cipher, data + i, data + i,
|
||||
(1U << dev->log_sector_size), iv);
|
||||
if (encrypt)
|
||||
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)
|
||||
return err;
|
||||
break;
|
||||
|
||||
case GRUB_CRYPTODISK_MODE_PCBC:
|
||||
err = grub_crypto_pcbc_decrypt (dev->cipher, data + i, data + i,
|
||||
(1U << dev->log_sector_size), iv);
|
||||
if (encrypt)
|
||||
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)
|
||||
return err;
|
||||
break;
|
||||
|
@ -294,9 +326,14 @@ grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
|||
{
|
||||
grub_crypto_xor (data + i + j, data + i + j, iv,
|
||||
dev->cipher->cipher->blocksize);
|
||||
err = grub_crypto_ecb_decrypt (dev->cipher, data + i + j,
|
||||
data + i + j,
|
||||
dev->cipher->cipher->blocksize);
|
||||
if (encrypt)
|
||||
err = grub_crypto_ecb_encrypt (dev->cipher, data + i + j,
|
||||
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)
|
||||
return err;
|
||||
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);
|
||||
lrw_xor (&sec, dev, data + i);
|
||||
|
||||
err = grub_crypto_ecb_decrypt (dev->cipher, data + i,
|
||||
data + i,
|
||||
(1U << dev->log_sector_size));
|
||||
if (encrypt)
|
||||
err = grub_crypto_ecb_encrypt (dev->cipher, data + i,
|
||||
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)
|
||||
return err;
|
||||
lrw_xor (&sec, dev, data + i);
|
||||
}
|
||||
break;
|
||||
case GRUB_CRYPTODISK_MODE_ECB:
|
||||
grub_crypto_ecb_decrypt (dev->cipher, data + i, data + i,
|
||||
(1U << dev->log_sector_size));
|
||||
if (encrypt)
|
||||
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;
|
||||
default:
|
||||
return GPG_ERR_NOT_IMPLEMENTED;
|
||||
|
@ -332,6 +378,14 @@ grub_cryptodisk_decrypt (struct grub_cryptodisk *dev,
|
|||
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
|
||||
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);
|
||||
return err;
|
||||
}
|
||||
gcry_err = grub_cryptodisk_decrypt (dev, (grub_uint8_t *) buf,
|
||||
size << disk->log_sector_size,
|
||||
sector);
|
||||
gcry_err = grub_cryptodisk_endecrypt (dev, (grub_uint8_t *) buf,
|
||||
size << disk->log_sector_size,
|
||||
sector, 0);
|
||||
return grub_crypto_gcry_error (gcry_err);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cryptodisk_write (grub_disk_t disk __attribute ((unused)),
|
||||
grub_disk_addr_t sector __attribute ((unused)),
|
||||
grub_size_t size __attribute ((unused)),
|
||||
const char *buf __attribute ((unused)))
|
||||
grub_cryptodisk_write (grub_disk_t disk, grub_disk_addr_t sector,
|
||||
grub_size_t size, const char *buf)
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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
|
||||
error occurs, otherwise return LEN. */
|
||||
static ssize_t
|
||||
nwrite (int fd, const char *buf, size_t len)
|
||||
ssize_t
|
||||
grub_util_fd_write (int fd, const char *buf, size_t 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)
|
||||
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))
|
||||
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_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_write (int fd, const char *buf, size_t len);
|
||||
grub_err_t
|
||||
grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat);
|
||||
void grub_util_cryptodisk_print_uuid (grub_disk_t disk);
|
||||
|
|
Loading…
Reference in a new issue