Signed-off-by: Vladimir Serbinenko <[email protected]>
---
grub-core/fs/zfs/zfs.c | 502 ++++++++++++++++++++++++++++++++----
grub-core/fs/zfs/zfscrypt.c | 335 +++++++++++++++++++++---
include/grub/zfs/zfs.h | 54 +++-
3 files changed, 793 insertions(+), 98 deletions(-)
diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
index b88a2b032..da1661680 100644
--- a/grub-core/fs/zfs/zfs.c
+++ b/grub-core/fs/zfs/zfs.c
@@ -227,6 +227,10 @@ struct subvolume
grub_uint64_t txg;
grub_uint64_t algo;
} *keyring;
+
+ struct grub_zfs_datto_key key_datto;
+
+ int is_datto_encrypted;
};
struct grub_zfs_data
@@ -264,16 +268,19 @@ struct grub_zfs_dir_ctx
struct grub_zfs_data *data;
};
-grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
- grub_uint64_t algo,
- const void *nonce,
- char *buf, grub_size_t size,
- const grub_uint32_t *expected_mac,
- grub_zfs_endian_t endian) = NULL;
-grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key
*key,
- grub_size_t keysize,
- grub_uint64_t salt,
- grub_uint64_t algo) = NULL;
+struct grub_zfs_decryptor *grub_zfs_decrypt = NULL;
+
+struct grub_zfs_crypt_datto_data
+{
+ grub_uint8_t *iv;
+ grub_size_t ivlen;
+ grub_uint8_t *mac;
+ grub_size_t maclen;
+ grub_uint8_t *master;
+ grub_size_t masterlen;
+ grub_uint8_t *hmac;
+ grub_size_t hmaclen;
+};
/*
* List of pool features that the grub implementation of ZFS supports for
* read. Note that features that are only required for write do not need
@@ -289,6 +296,7 @@ static const char *spa_feature_names[] = {
"com.klarasystems:vdev_zaps_v2",
"com.delphix:head_errlog",
"org.freebsd:zstd_compress",
+ "com.datto:encryption",
NULL
};
@@ -400,6 +408,47 @@ static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS]
= {
static grub_err_t zio_read_data (const blkptr_t * bp,
void *buf, struct grub_zfs_data *data);
+static int
+fill_crypt_datto_data (const void *name,
+ grub_size_t namelen __attribute__ ((unused)),
+ const void *val_in,
+ grub_size_t nelem,
+ grub_size_t elemsize,
+ void *data_in)
+{
+ struct grub_zfs_crypt_datto_data *data = data_in;
+ if (grub_strcmp(name, "DSL_CRYPTO_IV") == 0 && elemsize == 1)
+ {
+ data->ivlen = nelem;
+ data->iv = grub_malloc(nelem);
+ if (data->iv)
+ grub_memcpy(data->iv, val_in, nelem);
+ }
+ else if (grub_strcmp(name, "DSL_CRYPTO_MAC") == 0 && elemsize == 1)
+ {
+ data->maclen = nelem;
+ data->mac = grub_malloc(nelem);
+ if (data->mac)
+ grub_memcpy(data->mac, val_in, nelem);
+ }
+ else if (grub_strcmp(name, "DSL_CRYPTO_MASTER_KEY_1") == 0 && elemsize == 1)
+ {
+ data->masterlen = nelem;
+ data->master = grub_malloc(nelem);
+ if (data->master)
+ grub_memcpy(data->master, val_in, nelem);
+ }
+ else if (grub_strcmp(name, "DSL_CRYPTO_HMAC_KEY_1") == 0 && elemsize == 1)
+ {
+ data->hmaclen = nelem;
+ data->hmac = grub_malloc(nelem);
+ if (data->hmac)
+ grub_memcpy(data->hmac, val_in, nelem);
+ }
+
+ return 0;
+}
+
/*
* Our own version of log2(). Same thing as highbit()-1.
*/
@@ -690,7 +739,7 @@ grub_zfs_byteswap_type(void *buf, grub_size_t len,
grub_uint8_t type)
static grub_err_t
zio_checksum_verify (zio_cksum_t zc, grub_uint32_t checksum,
grub_zfs_endian_t endian,
- char *buf, grub_size_t size)
+ char *buf, grub_size_t size, int datto_crypt)
{
zio_eck_t *zec = (zio_eck_t *) (buf + size) - 1;
zio_checksum_info_t *ci = &zio_checksum_table[checksum];
@@ -715,6 +764,12 @@ zio_checksum_verify (zio_cksum_t zc, grub_uint32_t
checksum,
ci->ci_func (buf, size, endian, &actual_cksum);
int cksumlen = checksum != ZIO_CHECKSUM_SHA256_MAC ? 32 : 20;
+ if (datto_crypt)
+ {
+ actual_cksum.zc_word[0] ^= actual_cksum.zc_word[2];
+ actual_cksum.zc_word[1] ^= actual_cksum.zc_word[3];
+ cksumlen = 16;
+ }
if (ci->ci_eck && !GRUB_ZFS_IS_NATIVE_BYTEORDER(endian))
grub_zfs_byteswap_checksum(&actual_cksum);
@@ -796,7 +851,7 @@ uberblock_verify (uberblock_phys_t * ub, grub_uint64_t
offset,
zc.zc_word[0] = grub_cpu_to_zfs64 (offset, endian);
err = zio_checksum_verify (zc, ZIO_CHECKSUM_LABEL, endian,
- (char *) ub, s);
+ (char *) ub, s, 0);
return err;
}
@@ -1269,7 +1324,7 @@ check_pool_label (struct grub_zfs_data *data,
/* Now check the integrity of the vdev_phys_t structure though checksum. */
ZIO_SET_CHECKSUM(&emptycksum, grub_cpu_to_zfs64(diskdesc->vdev_phys_sector
<< 9, endian), 0, 0, 0);
err = zio_checksum_verify (emptycksum, ZIO_CHECKSUM_LABEL, endian,
- nvlist, VDEV_PHYS_SIZE);
+ nvlist, VDEV_PHYS_SIZE, 0);
if (err) {
grub_free (nvlist);
return err;
@@ -2019,7 +2074,7 @@ zio_read_gang (const blkptr_t * bp, const dva_t * dva,
void *buf,
ZIO_SET_CHECKSUM (&zc, DVA_GET_VDEV (dva),
DVA_GET_OFFSET (dva), bp->blk_birth, 0);
err = zio_checksum_verify (zc, ZIO_CHECKSUM_GANG_HEADER,
BP_GET_BYTEORDER(bp),
- (char *) zio_gb, SPA_GANGBLOCKSIZE);
+ (char *) zio_gb, SPA_GANGBLOCKSIZE, 0);
if (err)
{
grub_free (zio_gb);
@@ -2113,6 +2168,57 @@ decode_embedded_bp_compressed(const blkptr_t *bp, void
*buf)
return GRUB_ERR_NONE;
}
+static int
+datto_is_encrypted_type(grub_uint8_t dn_type)
+{
+ /* New structred types. */
+ if (dn_type & 0x80)
+ return !!(dn_type & 0x20);
+ switch(dn_type) {
+ case DMU_OT_NONE ... DMU_OT_SPACE_MAP:
+ case DMU_OT_OBJSET ... DMU_OT_ZNODE:
+ case DMU_OT_MASTER_NODE:
+ case DMU_OT_ZVOL_PROP:
+ case DMU_OT_ZAP_OTHER ... DMU_OT_DSL_PERMS:
+ case DMU_OT_FUID_SIZE ... DMU_OT_SCRUB_QUEUE:
+ case DMU_OT_USERREFS ... DMU_OT_DDT_STATS:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+static void
+add_blkptr_to_aad (char *aad, grub_size_t *aad_offset, blkptr_t bp,
grub_zfs_endian_t endian, int preswapped)
+{
+ if (!preswapped && !GRUB_ZFS_IS_NATIVE_BYTEORDER(endian))
+ grub_zfs_byteswap_blkptr(&bp);
+
+ grub_uint64_t blk_prop = BP_IS_HOLE(&bp) ? 0 : bp.blk_prop;
+
+ if (BP_GET_LEVEL(&bp) != 0) {
+ blk_prop &= ~0x8000007fffff0000ULL;
+ }
+
+ blk_prop &= ~0x4000ff0000000000ULL;
+
+ grub_set_unaligned64(&aad[*aad_offset], grub_cpu_to_le64(blk_prop));
+ *aad_offset += 8;
+
+ if (!GRUB_ZFS_IS_NATIVE_BYTEORDER(endian))
+ {
+ grub_set_unaligned64(&aad[*aad_offset],
grub_swap_bytes64(bp.blk_cksum.zc_word[2]));
+ grub_set_unaligned64(&aad[*aad_offset+8],
grub_swap_bytes64(bp.blk_cksum.zc_word[3]));
+ }
+ else
+ grub_memcpy(&aad[*aad_offset], &bp.blk_cksum.zc_word[2], 16);
+
+ *aad_offset += 16;
+
+ grub_memset(&aad[*aad_offset], 0, 8);
+ *aad_offset += 8;
+}
+
/*
* Read in a block of data, verify its checksum, decompress if needed,
* and put the uncompressed data in buf.
@@ -2122,17 +2228,44 @@ zio_read (const blkptr_t *bp, void **buf,
grub_size_t *size, struct grub_zfs_data *data)
{
grub_size_t lsize, psize;
- unsigned int comp, encrypted;
+ unsigned int comp;
char *compbuf = NULL;
grub_err_t err;
zio_cksum_t zc = bp->blk_cksum;
grub_uint32_t checksum;
+ int datto_encrypted = 0, datto_authenticated = 0, datto_dnode_encryption =
0, oracle_encrypted = 0;
*buf = NULL;
checksum = BP_GET_CHECKSUM(bp);
comp = BP_GET_COMPRESS(bp);
- encrypted = BP_GET_PROP_BIT_61(bp);
+ if (BP_GET_PROP_BIT_61(bp))
+ {
+ if (data->subvol.is_datto_encrypted)
+ {
+ grub_uint8_t type = BP_GET_TYPE(bp);
+ if (BP_GET_LEVEL(bp) > 0)
+ datto_authenticated = 1;
+ else if (type == DMU_OT_DNODE)
+ {
+ datto_encrypted = 1;
+ datto_authenticated = 0;
+ datto_dnode_encryption = 1;
+ }
+ else if (type == DMU_OT_OBJSET)
+ {
+ /* Objset uses inner hmacs that we don't suport yet.
+ Normal checksum is unaffected . */
+ }
+ else
+ {
+ datto_encrypted = datto_is_encrypted_type(type);
+ datto_authenticated = !datto_encrypted;
+ }
+ }
+ else
+ oracle_encrypted = 1;
+ }
if (BP_IS_EMBEDDED(bp))
{
if (BPE_GET_ETYPE(bp) != BP_EMBEDDED_TYPE_DATA)
@@ -2186,10 +2319,11 @@ zio_read (const blkptr_t *bp, void **buf,
return err;
}
- if (!BP_IS_EMBEDDED(bp))
+ if (!BP_IS_EMBEDDED(bp) && !datto_encrypted)
{
err = zio_checksum_verify (zc, checksum, BP_GET_BYTEORDER(bp),
- compbuf, psize);
+ compbuf, psize,
+ datto_authenticated);
if (err)
{
grub_dprintf ("zfs", "incorrect checksum\n");
@@ -2199,48 +2333,190 @@ zio_read (const blkptr_t *bp, void **buf,
}
}
- if (encrypted)
+ if (!BP_IS_EMBEDDED(bp) && datto_authenticated &&
data->subvol.key_datto.hmac_key && BP_GET_LEVEL(bp) == 0)
{
- if (!grub_zfs_decrypt)
- err = grub_error (GRUB_ERR_BAD_FS,
- N_("module `%s' isn't loaded"),
- "zfscrypt");
- else
+ grub_uint64_t hmac[8];
+ gcry_error_t err_gcry;
+ err_gcry = grub_crypto_hmac_buffer (GRUB_MD_SHA512,
+ data->subvol.key_datto.hmac_key, 64,
+ compbuf, psize,
+ hmac);
+ if (err_gcry)
{
- unsigned i, besti = 0;
- grub_uint64_t bestval = 0;
- for (i = 0; i < data->subvol.nkeys; i++)
- if (data->subvol.keyring[i].txg <= bp->blk_birth
- && data->subvol.keyring[i].txg > bestval)
- {
- besti = i;
- bestval = data->subvol.keyring[i].txg;
- }
- if (bestval == 0)
+ grub_free (compbuf);
+ *buf = NULL;
+ return grub_crypto_gcry_error (err_gcry);
+ }
+
+ if (!GRUB_ZFS_IS_NATIVE_BYTEORDER(BP_GET_BYTEORDER(bp)))
+ {
+ grub_zfs_byteswap_u64(&hmac[0]);
+ grub_zfs_byteswap_u64(&hmac[1]);
+ }
+
+ if (grub_crypto_memcmp(&zc.zc_word[2], hmac, 8) != 0)
+ {
+ grub_free (compbuf);
+ *buf = NULL;
+ grub_dprintf ("zfs", "actual hmac "
+ "%016llx %016llx %016llx %016llx %016llx %016llx
%016llx %016llx \n",
+ (unsigned long long) hmac[0],
+ (unsigned long long) hmac[1],
+ (unsigned long long) hmac[2],
+ (unsigned long long) hmac[3],
+ (unsigned long long) hmac[4],
+ (unsigned long long) hmac[5],
+ (unsigned long long) hmac[6],
+ (unsigned long long) hmac[7]);
+ grub_dprintf ("zfs", "expected hmac %016llx %016llx %016llx
%016llx\n",
+ (unsigned long long) zc.zc_word[0],
+ (unsigned long long) zc.zc_word[1],
+ (unsigned long long) zc.zc_word[2],
+ (unsigned long long) zc.zc_word[3]);
+ return grub_error (GRUB_ERR_BAD_FS, N_("HMAC verification failed"));
+ }
+ }
+
+ if (datto_dnode_encryption && (!grub_zfs_decrypt ||
!data->subvol.key_datto.master_key))
+ {
+ grub_dprintf("zfs", "Skipping decrypt of bonus because of missing
zfscrypt module or key\n");
+ datto_encrypted = 0;
+ datto_dnode_encryption = 0;
+ }
+ if ((oracle_encrypted || datto_encrypted) && !grub_zfs_decrypt)
+ err = grub_error (GRUB_ERR_BAD_FS,
+ N_("module `%s' isn't loaded"),
+ "zfscrypt");
+ else if (datto_encrypted)
+ {
+ grub_uint32_t iv[3];
+
+ if (!data->subvol.key_datto.master_key)
+ {
+ grub_free (compbuf);
+ *buf = NULL;
+ grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
+ bp->blk_birth);
+ return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
+ }
+
+ grub_set_unaligned64(iv, grub_cpu_to_zfs64((bp)->blk_dva[2].dva_word[1],
BP_GET_BYTEORDER(bp)));
+ iv[2] = grub_cpu_to_zfs32((bp)->blk_fill >> 32, BP_GET_BYTEORDER(bp));
+
+ if (datto_dnode_encryption)
+ {
+ grub_size_t offset = 0, crypt_offset = 0, aad_offset = 0;
+ char *crypt = grub_malloc(psize), *aad = grub_malloc(psize);
+ grub_zfs_endian_t endian = BP_GET_BYTEORDER(bp);
+ if (!crypt || !aad)
{
grub_free (compbuf);
+ grub_free (crypt);
+ grub_free (aad);
*buf = NULL;
- grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
- bp->blk_birth);
- return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
+ return grub_errno;
}
- grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T
- ", %p) for txg %" PRIxGRUB_UINT64_T "\n",
- besti, data->subvol.keyring[besti].txg,
- data->subvol.keyring[besti].cipher,
- bp->blk_birth);
- err = grub_zfs_decrypt (data->subvol.keyring[besti].cipher,
- data->subvol.keyring[besti].algo,
- &(bp)->blk_dva[2],
- compbuf, psize, zc.zc_mac,
- BP_GET_BYTEORDER(bp));
+ for (offset = 0; offset + sizeof (dnode_phys_t) <= psize; offset +=
sizeof(dnode_phys_t))
+ {
+ dnode_phys_t *dnp = (dnode_phys_t *) (void *) (compbuf + offset);
+ dnode_phys_t *dno = (dnode_phys_t *) (aad + aad_offset);
+ grub_memcpy(aad + aad_offset, dnp, 64);
+ dno->dn_used = 0;
+ dno->dn_flags &= DNODE_FLAG_SPILL_BLKPTR;
+ int has_spill = dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR;
+ unsigned i;
+
+ aad_offset += 64;
+
+ for (i = 0; i < dnp->dn_nblkptr; i++) {
+ add_blkptr_to_aad (aad, &aad_offset, dnp->dn_blkptr[i], endian,
0);
+ }
+
+ if (has_spill)
+ add_blkptr_to_aad (aad, &aad_offset, dnp->dn_spill, endian, 0);
+
+ char *bonus = DN_BONUS(dnp);
+ char *bonusmaxptr = (char *) (dnp + 1);
+ if (has_spill)
+ bonusmaxptr -= sizeof(blkptr_t);
+ grub_size_t bonusmaxlen = bonusmaxptr - bonus;
+ if (datto_is_encrypted_type(dnp->dn_bonustype))
+ {
+ grub_memcpy(crypt + crypt_offset, bonus, bonusmaxlen);
+ crypt_offset += bonusmaxlen;
+ }
+ else
+ {
+ grub_memcpy(aad + aad_offset, bonus, bonusmaxlen);
+ grub_zfs_byteswap_type((aad + aad_offset), bonusmaxlen,
dnp->dn_bonustype);
+ aad_offset += bonusmaxlen;
+ }
+ }
+ err = grub_zfs_decrypt->decrypt_datto (&data->subvol.key_datto,
+ iv,
(bp)->blk_dva[2].dva_word[0],
+ crypt, crypt_offset, aad,
aad_offset,
+ &zc.zc_word[2],
+ endian);
+ grub_size_t out_offset = 0;
+ for (offset = 0; offset + sizeof (dnode_phys_t) <= psize; offset +=
sizeof(dnode_phys_t))
+ {
+ dnode_phys_t *dnp = (dnode_phys_t *) (void *) (compbuf + offset);
+ int has_spill = dnp->dn_flags & DNODE_FLAG_SPILL_BLKPTR;
+ if (!datto_is_encrypted_type(dnp->dn_bonustype))
+ continue;
+ char * bonus = DN_BONUS(dnp);
+ char *bonusmaxptr = (char *) (dnp + 1);
+ if (has_spill)
+ bonusmaxptr -= sizeof(blkptr_t);
+ grub_size_t bonusmaxlen = bonusmaxptr - bonus;
+ grub_memcpy(bonus, crypt + out_offset, bonusmaxlen);
+ out_offset += bonusmaxlen;
+ }
+
}
- if (err)
+ else
+ err = grub_zfs_decrypt->decrypt_datto (&data->subvol.key_datto,
+ iv, (bp)->blk_dva[2].dva_word[0],
+ compbuf, psize, NULL, 0,
+ &zc.zc_word[2],
+ BP_GET_BYTEORDER(bp));
+ }
+ else if (oracle_encrypted)
+ {
+ unsigned i, besti = 0;
+ grub_uint64_t bestval = 0;
+ grub_dprintf("zfs", "Subvol has %d keys\n", (int) data->subvol.nkeys);
+ for (i = 0; i < data->subvol.nkeys; i++)
+ if (data->subvol.keyring[i].txg <= bp->blk_birth
+ && data->subvol.keyring[i].txg > bestval)
+ {
+ besti = i;
+ bestval = data->subvol.keyring[i].txg;
+ }
+ if (bestval == 0)
{
grub_free (compbuf);
*buf = NULL;
- return err;
+ grub_dprintf ("zfs", "no key for txg %" PRIxGRUB_UINT64_T "\n",
+ bp->blk_birth);
+ return grub_error (GRUB_ERR_BAD_FS, "no key found in keychain");
}
+ grub_dprintf ("zfs", "using key %u (%" PRIxGRUB_UINT64_T
+ ", %p) for txg %" PRIxGRUB_UINT64_T "\n",
+ besti, data->subvol.keyring[besti].txg,
+ data->subvol.keyring[besti].cipher,
+ bp->blk_birth);
+ err = grub_zfs_decrypt->decrypt_oracle
(data->subvol.keyring[besti].cipher,
+ data->subvol.keyring[besti].algo,
+ &(bp)->blk_dva[2],
+ compbuf, psize, zc.zc_mac,
+ BP_GET_BYTEORDER(bp));
+ }
+ if (err)
+ {
+ grub_free (compbuf);
+ *buf = NULL;
+ return err;
}
if (comp != ZIO_COMPRESS_OFF)
@@ -2254,6 +2530,7 @@ zio_read (const blkptr_t *bp, void **buf,
err = decomp_table[comp].decomp_func (compbuf, *buf, psize, lsize);
grub_free (compbuf);
+ compbuf = NULL;
if (err)
{
grub_free (*buf);
@@ -2273,6 +2550,51 @@ zio_read (const blkptr_t *bp, void **buf,
grub_zfs_byteswap_type(*buf, lsize, BP_GET_TYPE(bp));
}
+ if (!BP_IS_EMBEDDED(bp) && datto_authenticated && BP_GET_LEVEL(bp) > 0)
+ {
+ grub_uint64_t hash[8];
+ char *aad = grub_malloc(lsize);
+ grub_size_t aad_offset = 0;
+ if (!aad)
+ {
+ grub_free (*buf);
+ *buf = NULL;
+ return grub_errno;
+ }
+ for (unsigned i = 0; i < lsize / sizeof(blkptr_t); i++)
+ add_blkptr_to_aad (aad, &aad_offset, ((blkptr_t *)*buf)[i],
BP_GET_BYTEORDER(bp), 1);
+ grub_crypto_hash(GRUB_MD_SHA512, hash, aad, aad_offset);
+ grub_free(aad);
+
+ if (!GRUB_ZFS_IS_NATIVE_BYTEORDER(BP_GET_BYTEORDER(bp)))
+ {
+ grub_zfs_byteswap_u64(&hash[0]);
+ grub_zfs_byteswap_u64(&hash[1]);
+ }
+
+ if (grub_crypto_memcmp(&zc.zc_word[2], hash, 8) != 0)
+ {
+ grub_free (*buf);
+ *buf = NULL;
+ grub_dprintf ("zfs", "actual hash "
+ "%016llx %016llx %016llx %016llx %016llx %016llx
%016llx %016llx \n",
+ (unsigned long long) hash[0],
+ (unsigned long long) hash[1],
+ (unsigned long long) hash[2],
+ (unsigned long long) hash[3],
+ (unsigned long long) hash[4],
+ (unsigned long long) hash[5],
+ (unsigned long long) hash[6],
+ (unsigned long long) hash[7]);
+ grub_dprintf ("zfs", "expected hash %016llx %016llx %016llx
%016llx\n",
+ (unsigned long long) zc.zc_word[0],
+ (unsigned long long) zc.zc_word[1],
+ (unsigned long long) zc.zc_word[2],
+ (unsigned long long) zc.zc_word[3]);
+ return grub_error (GRUB_ERR_BAD_FS, N_("hash verification failed"));
+ }
+ }
+
return GRUB_ERR_NONE;
}
@@ -3519,8 +3841,8 @@ load_zap_key (const void *name, grub_size_t namelen,
const void *val_in,
ctx->subvol->keyring[ctx->keyn].algo =
grub_le_to_cpu64 (*(grub_uint64_t *) val_in);
ctx->subvol->keyring[ctx->keyn].cipher =
- grub_zfs_load_key (val_in, nelem, ctx->salt,
- ctx->subvol->keyring[ctx->keyn].algo);
+ grub_zfs_decrypt->load_key_oracle (val_in, nelem, ctx->salt,
+ ctx->subvol->keyring[ctx->keyn].algo);
ctx->keyn++;
return 0;
}
@@ -3587,6 +3909,82 @@ dnode_get_fullpath (const char *fullpath, struct
subvolume *subvol,
grub_dprintf ("zfs", "alive\n");
+ grub_uint64_t crypt_obj;
+
+ err = zap_lookup (dn, "com.datto:crypto_key_obj", &crypt_obj, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ crypt_obj = 0;
+ }
+
+ grub_dprintf("zfs", "crypt obj = %lld\n", (long long) crypt_obj);
+ subvol->is_datto_encrypted = crypt_obj != 0;
+
+ if (grub_zfs_decrypt && crypt_obj)
+ {
+ dnode_phys_t crypt_dn;
+ err = dnode_get (&(data->mos), crypt_obj, 0xc4,
+ &crypt_dn, data);
+ if (err)
+ {
+ grub_free (fsname);
+ grub_free (snapname);
+ return err;
+ }
+
+ err = dnode_get (&(data->mos), crypt_obj, 0 /* ?? */,
+ &crypt_dn, data);
+ struct grub_zfs_crypt_datto_data crypt_datto_data = { 0 };
+ grub_uint64_t pbkdf2iters = 0, pbkdf2salt = 0, guid = 0, algo = 0,
version = 0;
+ zap_iterate (&crypt_dn, 1, fill_crypt_datto_data, &crypt_datto_data,
data);
+
+ err = zap_lookup (&crypt_dn, "pbkdf2iters", &pbkdf2iters, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ pbkdf2iters = 0;
+ }
+
+ err = zap_lookup (&crypt_dn, "DSL_CRYPTO_GUID", &guid, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ guid = 0;
+ }
+
+ err = zap_lookup (&crypt_dn, "DSL_CRYPTO_SUITE", &algo, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ algo = 0;
+ }
+
+ err = zap_lookup (&crypt_dn, "DSL_CRYPTO_VERSION", &version, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ version = 0;
+ }
+
+ err = zap_lookup (&crypt_dn, "pbkdf2salt", &pbkdf2salt, data, 0);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ pbkdf2salt = 0;
+ }
+
+ pbkdf2salt = grub_cpu_to_le64(pbkdf2salt);
+
+ subvol->key_datto =
grub_zfs_decrypt->load_key_datto(crypt_datto_data.iv, crypt_datto_data.ivlen,
+
crypt_datto_data.mac, crypt_datto_data.maclen,
+
crypt_datto_data.master, crypt_datto_data.masterlen,
+
crypt_datto_data.hmac, crypt_datto_data.hmaclen,
+ (const grub_uint8_t
*) &pbkdf2salt, sizeof (pbkdf2salt),
+ pbkdf2iters, guid,
algo, version);
+ }
+
+
headobj = ((dsl_dir_phys_t *) DN_BONUS (dn))->dd_head_dataset_obj;
err = dnode_get (&(data->mos), headobj, 0, &subvol->mdn, data);
@@ -3600,7 +3998,7 @@ dnode_get_fullpath (const char *fullpath, struct
subvolume *subvol,
grub_dprintf("zfs", "keychain obj = %lld\n", (long long) keychainobj);
- if (grub_zfs_decrypt && keychainobj)
+ if (grub_zfs_decrypt && !subvol->is_datto_encrypted && keychainobj)
{
struct dnode_get_fullpath_ctx ctx = {
.subvol = subvol,
diff --git a/grub-core/fs/zfs/zfscrypt.c b/grub-core/fs/zfs/zfscrypt.c
index 535fd4065..e202f4265 100644
--- a/grub-core/fs/zfs/zfscrypt.c
+++ b/grub-core/fs/zfs/zfscrypt.c
@@ -46,8 +46,9 @@
GRUB_MOD_LICENSE ("GPLv3+");
/*
- Mostly based on following article:
+ Oracle part is mostly based on following article:
https://blogs.oracle.com/darren/entry/zfs_encryption_what_is_on
+ Datto part is based on comments in OpenZFS. No actal code has been used
*/
enum grub_zfs_algo
@@ -56,7 +57,26 @@ enum grub_zfs_algo
GRUB_ZFS_ALGO_GCM,
};
-struct grub_zfs_key
+struct datto_algo {
+ grub_size_t wrapkeylen;
+ grub_size_t cryptkeylen;
+ grub_size_t masterkeylen;
+ enum grub_zfs_algo used_algo;
+} datto_algos[] = {
+ { 0 },
+ { 0 },
+ { 0 },
+ { 32, 16, 16, GRUB_ZFS_ALGO_CCM },
+ { 32, 24, 24, GRUB_ZFS_ALGO_CCM },
+ { 32, 32, 32, GRUB_ZFS_ALGO_CCM },
+ { 32, 16, 16, GRUB_ZFS_ALGO_GCM },
+ { 32, 24, 24, GRUB_ZFS_ALGO_GCM },
+ { 32, 32, 32, GRUB_ZFS_ALGO_GCM },
+};
+#define MAX_WRAPCIPHERTEXTLEN 96
+#define MAX_MACLEN 16
+
+struct grub_zfs_key_oracle
{
grub_uint64_t algo;
grub_uint8_t enc_nonce[13];
@@ -102,26 +122,81 @@ grub_zfs_add_key (grub_uint8_t *key_in,
static gcry_err_code_t
grub_ccm_decrypt (grub_crypto_cipher_handle_t cipher,
- grub_uint8_t *out, const grub_uint8_t *in,
- grub_size_t psize,
+ grub_uint8_t *out,
+ const grub_uint8_t *in, grub_size_t psize,
+ const grub_uint8_t *aad, grub_size_t aadsize,
void *mac_out, const void *nonce,
- unsigned l, unsigned m)
+ unsigned noncelen, unsigned m)
{
grub_uint8_t iv[16];
grub_uint8_t mul[16];
grub_uint32_t mac[4];
- unsigned i, j;
+ unsigned i, j, l = 15 - noncelen, aprefixlen = 0;
gcry_err_code_t err;
+ grub_uint8_t aprefix[16] = { 0 };
- grub_memcpy (iv + 1, nonce, 15 - l);
+ grub_memcpy (iv + 1, nonce, noncelen);
- iv[0] = (l - 1) | (((m-2) / 2) << 3);
+ iv[0] = (l - 1) | (((m-2) / 2) << 3) | ((aadsize != 0) << 6);
for (j = 0; j < l; j++)
iv[15 - j] = psize >> (8 * j);
err = grub_crypto_ecb_encrypt (cipher, mac, iv, 16);
if (err)
return err;
+ if (aadsize == 0)
+ aprefixlen = 0;
+ else if (aadsize <= 0xFEFF)
+ {
+ aprefixlen = 2;
+ aprefix[0] = aadsize >> 8;
+ aprefix[1] = aadsize;
+ }
+#if GRUB_CPU_SIZEOF_VOID_P == 8
+ else if ((aadsize >> 32) == 0)
+#endif
+ {
+ aprefixlen = 6;
+ aprefix[0] = 0xff;
+ aprefix[1] = 0xfe;
+ grub_set_unaligned32(aprefix + 2, grub_cpu_to_be32(aadsize));
+ }
+#if GRUB_CPU_SIZEOF_VOID_P == 8
+ else
+ {
+ aprefixlen = 10;
+ aprefix[0] = 0xff;
+ aprefix[1] = 0xff;
+ grub_set_unaligned64(aprefix + 2, grub_cpu_to_be64(aadsize));
+ }
+#endif
+
+ if (aadsize != 0)
+ {
+ grub_size_t ablocks = (aadsize + aprefixlen + 15) / 16;
+ grub_size_t first_block_datalen = 16 - aprefixlen;
+ if (first_block_datalen > aadsize)
+ first_block_datalen = aadsize;
+ grub_memcpy (aprefix + aprefixlen, aad, first_block_datalen);
+
+ grub_crypto_xor (mac, mac, aprefix, 16);
+ err = grub_crypto_ecb_encrypt (cipher, mac, mac, 16);
+ if (err)
+ return err;
+
+ for (i = 1; i < ablocks; i++)
+ {
+ grub_size_t csize, instart = (i - 1) * 16 + first_block_datalen;
+ csize = 16;
+ if (csize > aadsize - instart)
+ csize = aadsize - instart;
+ grub_crypto_xor (mac, mac, aad + instart, csize);
+ err = grub_crypto_ecb_encrypt (cipher, mac, mac, 16);
+ if (err)
+ return err;
+ }
+ }
+
iv[0] = l - 1;
for (i = 0; i < (psize + 15) / 16; i++)
@@ -187,6 +262,8 @@ static gcry_err_code_t
grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
grub_uint8_t *out, const grub_uint8_t *in,
grub_size_t psize,
+ const grub_uint8_t *aad,
+ grub_size_t aadsize,
void *mac_out, const void *nonce,
unsigned nonce_len, unsigned m)
{
@@ -213,7 +290,7 @@ grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
else
{
grub_memset (iv, 0, sizeof (iv));
- grub_memcpy (iv, nonce, nonce_len);
+ grub_memcpy (iv, nonce, nonce_len > sizeof (iv) ? sizeof (iv) :
nonce_len);
grub_gcm_mul (iv, h);
iv[15] ^= nonce_len * 8;
grub_gcm_mul (iv, h);
@@ -223,6 +300,16 @@ grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
if (err)
return err;
+ for (i = 0; i < (aadsize + 15) / 16; i++)
+ {
+ grub_size_t csize;
+ csize = 16;
+ if (csize > aadsize - 16 * i)
+ csize = aadsize - 16 * i;
+ grub_crypto_xor (mac, mac, aad + 16 * i, csize);
+ grub_gcm_mul (mac, h);
+ }
+
for (i = 0; i < (psize + 15) / 16; i++)
{
grub_size_t csize;
@@ -244,6 +331,8 @@ grub_gcm_decrypt (grub_crypto_cipher_handle_t cipher,
}
for (j = 0; j < 8; j++)
mac[15 - j] ^= ((((grub_uint64_t) psize) * 8) >> (8 * j));
+ for (j = 0; j < 8; j++)
+ mac[7 - j] ^= ((((grub_uint64_t) aadsize) * 8) >> (8 * j));
grub_gcm_mul (mac, h);
if (mac_out)
@@ -257,30 +346,33 @@ static gcry_err_code_t
algo_decrypt (grub_crypto_cipher_handle_t cipher, grub_uint64_t algo,
grub_uint8_t *out, const grub_uint8_t *in,
grub_size_t psize,
+ const grub_uint8_t *aad,
+ grub_size_t aadsize,
void *mac_out, const void *nonce,
unsigned l, unsigned m)
{
switch (algo)
{
- case 0:
+ case GRUB_ZFS_ALGO_CCM:
return grub_ccm_decrypt (cipher, out, in, psize,
- mac_out, nonce, l, m);
- case 1:
+ aad, aadsize, mac_out, nonce,
+ l <= 15 ? l : 0, m);
+ case GRUB_ZFS_ALGO_GCM:
return grub_gcm_decrypt (cipher, out, in, psize,
- mac_out, nonce,
- 15 - l, m);
+ aad, aadsize, mac_out, nonce,
+ l <= 15 ? l : 0, m);
default:
return GPG_ERR_CIPHER_ALGO;
}
}
static grub_err_t
-grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher,
- grub_uint64_t algo,
- const void *nonce,
- char *buf, grub_size_t size,
- const grub_uint32_t *expected_mac,
- grub_zfs_endian_t endian)
+grub_zfs_decrypt_oracle (grub_crypto_cipher_handle_t cipher,
+ grub_uint64_t algo,
+ const void *nonce,
+ char *buf, grub_size_t size,
+ const grub_uint32_t *expected_mac,
+ grub_zfs_endian_t endian)
{
grub_uint32_t mac[4];
unsigned i;
@@ -298,8 +390,8 @@ grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher,
err = algo_decrypt (cipher, algo,
(grub_uint8_t *) buf,
(grub_uint8_t *) buf,
- size, mac,
- sw + 1, 3, 12);
+ size, NULL, 0, mac,
+ sw, 12, 12);
if (err)
return grub_crypto_gcry_error (err);
@@ -310,11 +402,73 @@ grub_zfs_decrypt_real (grub_crypto_cipher_handle_t cipher,
return GRUB_ERR_NONE;
}
+static grub_err_t
+grub_zfs_decrypt_datto (const struct grub_zfs_datto_key *key,
+ const grub_uint32_t *nonce, grub_uint64_t salt,
+ char *buf, grub_size_t size,
+ const char *aadbuf, grub_size_t aadsize,
+ const grub_uint64_t *expected_mac,
+ grub_zfs_endian_t endian)
+{
+ grub_uint64_t mac[2];
+ unsigned i;
+ grub_uint8_t extractkey[64];
+ grub_uint8_t expandkey[64];
+ grub_uint8_t t[9];
+ gcry_err_code_t err;
+ grub_crypto_cipher_handle_t cipher;
+
+ if (!key)
+ return grub_error (GRUB_ERR_ACCESS_DENIED,
+ N_("no decryption key available"));
+
+ /* A special case of HKDF with 512 > keylen. */
+ err = grub_crypto_hmac_buffer (GRUB_MD_SHA512,
+ "", 0,
+ key->master_key, key->master_keylen,
+ extractkey);
+ if (err)
+ return grub_crypto_gcry_error (err);
+
+ grub_set_unaligned64(t, grub_cpu_to_zfs64(salt, endian));
+ t[8] = 1;
+ err = grub_crypto_hmac_buffer (GRUB_MD_SHA512,
+ extractkey, 64,
+ t, 9, expandkey);
+ if (err)
+ return grub_crypto_gcry_error (err);
+
+ cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
+ if (!cipher)
+ return grub_crypto_gcry_error (err);
+ err = grub_crypto_cipher_set_key (cipher, expandkey,
datto_algos[key->algo].cryptkeylen);
+ if (err)
+ {
+ grub_crypto_cipher_close (cipher);
+ return grub_crypto_gcry_error (err);
+ }
+
+ err = algo_decrypt (cipher, datto_algos[key->algo].used_algo,
+ (grub_uint8_t *) buf,
+ (grub_uint8_t *) buf,
+ size, (grub_uint8_t *) aadbuf, aadsize, mac,
+ nonce, 12, 16);
+ grub_crypto_cipher_close (cipher);
+ if (err)
+ return grub_crypto_gcry_error (err);
+
+ for (i = 0; i < 2; i++)
+ if (grub_zfs_to_cpu64 (expected_mac[i], endian)
+ != grub_le_to_cpu64 (mac[i]))
+ grub_dprintf("zfs", N_("MAC verification failed"));
+ return GRUB_ERR_NONE;
+}
+
static grub_crypto_cipher_handle_t
-grub_zfs_load_key_real (const struct grub_zfs_key *key,
- grub_size_t keysize,
- grub_uint64_t salt,
- grub_uint64_t algo)
+grub_zfs_load_key_oracle (const struct grub_zfs_key_oracle *key,
+ grub_size_t keysize,
+ grub_uint64_t salt,
+ grub_uint64_t algo)
{
unsigned keylen;
struct grub_zfs_wrap_key *wrap_key;
@@ -373,7 +527,7 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
}
err = algo_decrypt (cipher, algo, decrypted, key->unknown_purpose_key,
32,
- mac, key->unknown_purpose_nonce, 2, 16);
+ NULL, 0, mac, key->unknown_purpose_nonce, 13, 16);
if (err || (grub_crypto_memcmp (mac, key->unknown_purpose_key + 32, 16)
!= 0))
{
@@ -383,8 +537,8 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
continue;
}
- err = algo_decrypt (cipher, algo, decrypted, key->enc_key, keylen, mac,
- key->enc_nonce, 2, 16);
+ err = algo_decrypt (cipher, algo, decrypted, key->enc_key, keylen, NULL,
0,
+ mac, key->enc_nonce, 13, 16);
if (err || grub_crypto_memcmp (mac, key->enc_key + keylen, 16) != 0)
{
grub_dprintf ("zfs", "key loading failed\n");
@@ -413,6 +567,119 @@ grub_zfs_load_key_real (const struct grub_zfs_key *key,
return NULL;
}
+static struct grub_zfs_datto_key
+grub_zfs_load_key_datto (const grub_uint8_t *iv, grub_size_t ivlen,
+ const grub_uint8_t *mac_in, grub_size_t mac_inlen,
+ const grub_uint8_t *master, grub_size_t masterlen,
+ const grub_uint8_t *hmac, grub_size_t hmaclen,
+ const grub_uint8_t *pbkdf2salt, grub_size_t
pbkdf2saltlen,
+ grub_uint64_t pbkdf2iters, grub_uint64_t guid,
grub_uint64_t algo, grub_uint64_t version)
+{
+ struct grub_zfs_wrap_key *wrap_key;
+ struct grub_zfs_datto_key ret = { 0 };
+
+ if (algo <= 2 || algo >= ARRAY_SIZE(datto_algos))
+ {
+ grub_error(GRUB_ERR_BAD_FS, "unsupported crypto algo");
+ return ret;
+ }
+
+ /* Note: if last two ever become variable they need to be checkecked as
matching algo. Especially mac_inlen. */
+ if (masterlen < datto_algos[algo].masterkeylen || hmaclen != 64 || mac_inlen
!= 16)
+ {
+ grub_error(GRUB_ERR_BAD_FS, "crypto keys are invalid");
+ return ret;
+ }
+
+ masterlen = datto_algos[algo].masterkeylen;
+
+ grub_uint8_t ciphertext[MAX_WRAPCIPHERTEXTLEN];
+ grub_uint8_t plaintext[MAX_WRAPCIPHERTEXTLEN];
+ grub_uint8_t mac_computed[MAX_MACLEN];
+ struct {
+ grub_uint64_t guid;
+ grub_uint64_t algo;
+ grub_uint64_t version;
+ } aad = {
+ grub_cpu_to_le64(guid),
+ grub_cpu_to_le64(algo),
+ grub_cpu_to_le64(version)
+ };
+
+ grub_memcpy(ciphertext, master, masterlen);
+ grub_memcpy(ciphertext + masterlen, hmac, hmaclen);
+
+ for (wrap_key = zfs_wrap_keys; wrap_key; wrap_key = wrap_key->next)
+ {
+ grub_crypto_cipher_handle_t cipher;
+ grub_uint8_t wrap_key_real[32] = { 0 };
+ gcry_err_code_t err = 0;
+
+ cipher = grub_crypto_cipher_open (GRUB_CIPHER_AES);
+ if (!cipher)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return ret;
+ }
+ grub_memset (wrap_key_real, 0, sizeof (wrap_key_real));
+
+ if (!wrap_key->is_passphrase)
+ grub_memcpy(wrap_key_real, wrap_key->key,
+ wrap_key->keylen < datto_algos[algo].wrapkeylen ?
wrap_key->keylen : datto_algos[algo].wrapkeylen);
+ else
+ // TODO: PBKDF2
+ err = grub_crypto_pbkdf2 (GRUB_MD_SHA1,
+ (const grub_uint8_t *) wrap_key->key,
+ wrap_key->keylen,
+ pbkdf2salt, pbkdf2saltlen,
+ pbkdf2iters, wrap_key_real,
datto_algos[algo].wrapkeylen);
+
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ grub_crypto_cipher_close (cipher);
+ continue;
+ }
+
+ err = grub_crypto_cipher_set_key (cipher, wrap_key_real,
datto_algos[algo].wrapkeylen);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ grub_crypto_cipher_close (cipher);
+ continue;
+ }
+
+ err = algo_decrypt (cipher, datto_algos[algo].used_algo,
+ plaintext, ciphertext, masterlen + hmaclen,
+ (grub_uint8_t *) &aad, sizeof(aad),
+ mac_computed, iv, ivlen, mac_inlen);
+ if (err || (grub_crypto_memcmp (mac_computed, mac_in, mac_inlen) != 0))
+ {
+ grub_dprintf ("zfs", "key loading failed\n");
+ grub_errno = GRUB_ERR_NONE;
+ grub_crypto_cipher_close (cipher);
+ continue;
+ }
+
+ ret.master_keylen = masterlen;
+ ret.master_key = grub_malloc(ret.master_keylen);
+ if (!ret.master_key)
+ return ret;
+ grub_memcpy(ret.master_key, plaintext, masterlen);
+ ret.hmac_key = grub_malloc(hmaclen);
+ if (!ret.hmac_key)
+ {
+ grub_free(ret.master_key);
+ ret.master_key = NULL;
+ return ret;
+ }
+ ret.algo = algo;
+ grub_memcpy(ret.hmac_key, plaintext + masterlen, hmaclen);
+ return ret;
+ }
+ return ret;
+}
+
static const struct grub_arg_option options[] =
{
{"raw", 'r', 0, N_("Assume input is raw."), 0, 0},
@@ -471,12 +738,17 @@ grub_cmd_zfs_key (grub_extcmd_context_t ctxt, int argc,
char **args)
&& !ctxt->state[1].set));
}
+struct grub_zfs_decryptor grub_zfs_decrypt_real = {
+ .decrypt_oracle = grub_zfs_decrypt_oracle,
+ .decrypt_datto = grub_zfs_decrypt_datto,
+ .load_key_oracle = grub_zfs_load_key_oracle,
+ .load_key_datto = grub_zfs_load_key_datto,
+};
static grub_extcmd_t cmd_key;
GRUB_MOD_INIT(zfscrypt)
{
- grub_zfs_decrypt = grub_zfs_decrypt_real;
- grub_zfs_load_key = grub_zfs_load_key_real;
+ grub_zfs_decrypt = &grub_zfs_decrypt_real;
cmd_key = grub_register_extcmd ("zfskey", grub_cmd_zfs_key, 0,
N_("[-h|-p|-r] [FILE]"),
N_("Import ZFS wrapping key stored in FILE."),
@@ -486,6 +758,5 @@ GRUB_MOD_INIT(zfscrypt)
GRUB_MOD_FINI(zfscrypt)
{
grub_zfs_decrypt = 0;
- grub_zfs_load_key = 0;
grub_unregister_extcmd (cmd_key);
}
diff --git a/include/grub/zfs/zfs.h b/include/grub/zfs/zfs.h
index 0c5c40a73..fbac368b0 100644
--- a/include/grub/zfs/zfs.h
+++ b/include/grub/zfs/zfs.h
@@ -147,20 +147,46 @@ grub_zfs_add_key (grub_uint8_t *key_in,
grub_size_t keylen,
int passphrase);
-extern grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
- grub_uint64_t algo,
- const void *nonce,
- char *buf, grub_size_t size,
- const grub_uint32_t *expected_mac,
- grub_zfs_endian_t endian);
-
-struct grub_zfs_key;
-
-extern grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct
grub_zfs_key *key,
- grub_size_t keysize,
- grub_uint64_t salt,
- grub_uint64_t algo);
-
+struct grub_zfs_key_oracle;
+
+struct grub_zfs_datto_key
+{
+ grub_uint8_t *master_key;
+ grub_size_t master_keylen;
+ grub_uint8_t *hmac_key;
+ grub_uint64_t algo;
+};
+
+struct grub_zfs_decryptor
+{
+ grub_err_t (*decrypt_oracle) (grub_crypto_cipher_handle_t cipher,
+ grub_uint64_t algo,
+ const void *nonce,
+ char *buf, grub_size_t size,
+ const grub_uint32_t *expected_mac,
+ grub_zfs_endian_t endian);
+
+ grub_crypto_cipher_handle_t (*load_key_oracle) (const struct
grub_zfs_key_oracle *key,
+ grub_size_t keysize,
+ grub_uint64_t salt,
+ grub_uint64_t algo);
+
+ grub_err_t (*decrypt_datto) (const struct grub_zfs_datto_key *key,
+ const grub_uint32_t *nonce, grub_uint64_t salt,
+ char *buf, grub_size_t size,
+ const char *aadbuf, grub_size_t aadsize,
+ const grub_uint64_t *expected_mac,
+ grub_zfs_endian_t endian);
+
+ struct grub_zfs_datto_key (*load_key_datto) (const grub_uint8_t *iv,
grub_size_t ivlen,
+ const grub_uint8_t *mac,
grub_size_t maclen,
+ const grub_uint8_t *master,
grub_size_t masterlen,
+ const grub_uint8_t *hmac,
grub_size_t hmaclen,
+ const grub_uint8_t *pbkdf2salt,
grub_size_t pbkdf2saltlen,
+ grub_uint64_t pbkdf2iters,
grub_uint64_t guid, grub_uint64_t algo, grub_uint64_t version);
+};
+
+extern struct grub_zfs_decryptor *grub_zfs_decrypt;
#endif /* ! GRUB_ZFS_HEADER */
--
2.49.0
_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel