From: Vladimir Serbinenko <phcoder@gmail.com>
To: grub-devel@gnu.org
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Subject: [PATCH 2/2] zfs: Support datto encryption
Date: Fri, 1 Aug 2025 14:30:40 +0000 [thread overview]
Message-ID: <20250801143052.251913-3-phcoder@gmail.com> (raw)
In-Reply-To: <20250801143052.251913-1-phcoder@gmail.com>
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
---
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
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
next prev parent reply other threads:[~2025-08-01 14:39 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-01 14:30 [PATCH 0/2] zfs: Support datto encryption and fix endianness handling Vladimir Serbinenko
2025-08-01 14:30 ` [PATCH 1/2] zfs: Rewrite " Vladimir Serbinenko
2025-08-01 14:30 ` Vladimir Serbinenko [this message]
2025-08-11 13:48 ` [PATCH 2/2] zfs: Support datto encryption Neal Gompa
2025-08-11 14:13 ` Vladimir 'phcoder' Serbinenko
2025-08-12 16:10 ` Neal Gompa
2025-08-11 13:23 ` [PATCH 0/2] zfs: Support datto encryption and fix endianness handling Neal Gompa
2025-08-11 19:18 ` Toomas Soome via Grub-devel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250801143052.251913-3-phcoder@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.