Changeset View
Changeset View
Standalone View
Standalone View
sys/contrib/openzfs/module/os/linux/zfs/zio_crypt.c
Show First 20 Lines • Show All 370 Lines • ▼ Show 20 Lines | |||||
* encrypting it expects puio to reference the plaintext and cuio to | * encrypting it expects puio to reference the plaintext and cuio to | ||||
* reference the ciphertext. cuio must have enough space for the | * reference the ciphertext. cuio must have enough space for the | ||||
* ciphertext + room for a MAC. datalen should be the length of the | * ciphertext + room for a MAC. datalen should be the length of the | ||||
* plaintext / ciphertext alone. | * plaintext / ciphertext alone. | ||||
*/ | */ | ||||
static int | static int | ||||
zio_do_crypt_uio(boolean_t encrypt, uint64_t crypt, crypto_key_t *key, | zio_do_crypt_uio(boolean_t encrypt, uint64_t crypt, crypto_key_t *key, | ||||
crypto_ctx_template_t tmpl, uint8_t *ivbuf, uint_t datalen, | crypto_ctx_template_t tmpl, uint8_t *ivbuf, uint_t datalen, | ||||
uio_t *puio, uio_t *cuio, uint8_t *authbuf, uint_t auth_len) | zfs_uio_t *puio, zfs_uio_t *cuio, uint8_t *authbuf, uint_t auth_len) | ||||
{ | { | ||||
int ret; | int ret; | ||||
crypto_data_t plaindata, cipherdata; | crypto_data_t plaindata, cipherdata; | ||||
CK_AES_CCM_PARAMS ccmp; | CK_AES_CCM_PARAMS ccmp; | ||||
CK_AES_GCM_PARAMS gcmp; | CK_AES_GCM_PARAMS gcmp; | ||||
crypto_mechanism_t mech; | crypto_mechanism_t mech; | ||||
zio_crypt_info_t crypt_info; | zio_crypt_info_t crypt_info; | ||||
uint_t plain_full_len, maclen; | uint_t plain_full_len, maclen; | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | error: | ||||
return (ret); | return (ret); | ||||
} | } | ||||
int | int | ||||
zio_crypt_key_wrap(crypto_key_t *cwkey, zio_crypt_key_t *key, uint8_t *iv, | zio_crypt_key_wrap(crypto_key_t *cwkey, zio_crypt_key_t *key, uint8_t *iv, | ||||
uint8_t *mac, uint8_t *keydata_out, uint8_t *hmac_keydata_out) | uint8_t *mac, uint8_t *keydata_out, uint8_t *hmac_keydata_out) | ||||
{ | { | ||||
int ret; | int ret; | ||||
uio_t puio, cuio; | zfs_uio_t puio, cuio; | ||||
uint64_t aad[3]; | uint64_t aad[3]; | ||||
iovec_t plain_iovecs[2], cipher_iovecs[3]; | iovec_t plain_iovecs[2], cipher_iovecs[3]; | ||||
uint64_t crypt = key->zk_crypt; | uint64_t crypt = key->zk_crypt; | ||||
uint_t enc_len, keydata_len, aad_len; | uint_t enc_len, keydata_len, aad_len; | ||||
ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS); | ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS); | ||||
ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW); | ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW); | ||||
keydata_len = zio_crypt_table[crypt].ci_keylen; | keydata_len = zio_crypt_table[crypt].ci_keylen; | ||||
/* generate iv for wrapping the master and hmac key */ | /* generate iv for wrapping the master and hmac key */ | ||||
ret = random_get_pseudo_bytes(iv, WRAPPING_IV_LEN); | ret = random_get_pseudo_bytes(iv, WRAPPING_IV_LEN); | ||||
if (ret != 0) | if (ret != 0) | ||||
goto error; | goto error; | ||||
/* initialize uio_ts */ | /* initialize zfs_uio_ts */ | ||||
plain_iovecs[0].iov_base = key->zk_master_keydata; | plain_iovecs[0].iov_base = key->zk_master_keydata; | ||||
plain_iovecs[0].iov_len = keydata_len; | plain_iovecs[0].iov_len = keydata_len; | ||||
plain_iovecs[1].iov_base = key->zk_hmac_keydata; | plain_iovecs[1].iov_base = key->zk_hmac_keydata; | ||||
plain_iovecs[1].iov_len = SHA512_HMAC_KEYLEN; | plain_iovecs[1].iov_len = SHA512_HMAC_KEYLEN; | ||||
cipher_iovecs[0].iov_base = keydata_out; | cipher_iovecs[0].iov_base = keydata_out; | ||||
cipher_iovecs[0].iov_len = keydata_len; | cipher_iovecs[0].iov_len = keydata_len; | ||||
cipher_iovecs[1].iov_base = hmac_keydata_out; | cipher_iovecs[1].iov_base = hmac_keydata_out; | ||||
Show All 38 Lines | |||||
} | } | ||||
int | int | ||||
zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version, | zio_crypt_key_unwrap(crypto_key_t *cwkey, uint64_t crypt, uint64_t version, | ||||
uint64_t guid, uint8_t *keydata, uint8_t *hmac_keydata, uint8_t *iv, | uint64_t guid, uint8_t *keydata, uint8_t *hmac_keydata, uint8_t *iv, | ||||
uint8_t *mac, zio_crypt_key_t *key) | uint8_t *mac, zio_crypt_key_t *key) | ||||
{ | { | ||||
crypto_mechanism_t mech; | crypto_mechanism_t mech; | ||||
uio_t puio, cuio; | zfs_uio_t puio, cuio; | ||||
uint64_t aad[3]; | uint64_t aad[3]; | ||||
iovec_t plain_iovecs[2], cipher_iovecs[3]; | iovec_t plain_iovecs[2], cipher_iovecs[3]; | ||||
uint_t enc_len, keydata_len, aad_len; | uint_t enc_len, keydata_len, aad_len; | ||||
int ret; | int ret; | ||||
ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS); | ASSERT3U(crypt, <, ZIO_CRYPT_FUNCTIONS); | ||||
ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW); | ASSERT3U(cwkey->ck_format, ==, CRYPTO_KEY_RAW); | ||||
rw_init(&key->zk_salt_lock, NULL, RW_DEFAULT, NULL); | rw_init(&key->zk_salt_lock, NULL, RW_DEFAULT, NULL); | ||||
keydata_len = zio_crypt_table[crypt].ci_keylen; | keydata_len = zio_crypt_table[crypt].ci_keylen; | ||||
/* initialize uio_ts */ | /* initialize zfs_uio_ts */ | ||||
plain_iovecs[0].iov_base = key->zk_master_keydata; | plain_iovecs[0].iov_base = key->zk_master_keydata; | ||||
plain_iovecs[0].iov_len = keydata_len; | plain_iovecs[0].iov_len = keydata_len; | ||||
plain_iovecs[1].iov_base = key->zk_hmac_keydata; | plain_iovecs[1].iov_base = key->zk_hmac_keydata; | ||||
plain_iovecs[1].iov_len = SHA512_HMAC_KEYLEN; | plain_iovecs[1].iov_len = SHA512_HMAC_KEYLEN; | ||||
cipher_iovecs[0].iov_base = keydata; | cipher_iovecs[0].iov_base = keydata; | ||||
cipher_iovecs[0].iov_len = keydata_len; | cipher_iovecs[0].iov_len = keydata_len; | ||||
cipher_iovecs[1].iov_base = hmac_keydata; | cipher_iovecs[1].iov_base = hmac_keydata; | ||||
▲ Show 20 Lines • Show All 716 Lines • ▼ Show 20 Lines | |||||
error: | error: | ||||
bzero(portable_mac, ZIO_OBJSET_MAC_LEN); | bzero(portable_mac, ZIO_OBJSET_MAC_LEN); | ||||
bzero(local_mac, ZIO_OBJSET_MAC_LEN); | bzero(local_mac, ZIO_OBJSET_MAC_LEN); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static void | static void | ||||
zio_crypt_destroy_uio(uio_t *uio) | zio_crypt_destroy_uio(zfs_uio_t *uio) | ||||
{ | { | ||||
if (uio->uio_iov) | if (uio->uio_iov) | ||||
kmem_free(uio->uio_iov, uio->uio_iovcnt * sizeof (iovec_t)); | kmem_free(uio->uio_iov, uio->uio_iovcnt * sizeof (iovec_t)); | ||||
} | } | ||||
/* | /* | ||||
* This function parses an uncompressed indirect block and returns a checksum | * This function parses an uncompressed indirect block and returns a checksum | ||||
* of all the portable fields from all of the contained bps. The portable | * of all the portable fields from all of the contained bps. The portable | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | |||||
* Special case handling routine for encrypting / decrypting ZIL blocks. | * Special case handling routine for encrypting / decrypting ZIL blocks. | ||||
* We do not check for the older ZIL chain because the encryption feature | * We do not check for the older ZIL chain because the encryption feature | ||||
* was not available before the newer ZIL chain was introduced. The goal | * was not available before the newer ZIL chain was introduced. The goal | ||||
* here is to encrypt everything except the blkptr_t of a lr_write_t and | * here is to encrypt everything except the blkptr_t of a lr_write_t and | ||||
* the zil_chain_t header. Everything that is not encrypted is authenticated. | * the zil_chain_t header. Everything that is not encrypted is authenticated. | ||||
*/ | */ | ||||
static int | static int | ||||
zio_crypt_init_uios_zil(boolean_t encrypt, uint8_t *plainbuf, | zio_crypt_init_uios_zil(boolean_t encrypt, uint8_t *plainbuf, | ||||
uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, uio_t *puio, | uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, zfs_uio_t *puio, | ||||
uio_t *cuio, uint_t *enc_len, uint8_t **authbuf, uint_t *auth_len, | zfs_uio_t *cuio, uint_t *enc_len, uint8_t **authbuf, uint_t *auth_len, | ||||
boolean_t *no_crypt) | boolean_t *no_crypt) | ||||
{ | { | ||||
int ret; | int ret; | ||||
uint64_t txtype, lr_len; | uint64_t txtype, lr_len; | ||||
uint_t nr_src, nr_dst, crypt_len; | uint_t nr_src, nr_dst, crypt_len; | ||||
uint_t aad_len = 0, nr_iovecs = 0, total_len = 0; | uint_t aad_len = 0, nr_iovecs = 0, total_len = 0; | ||||
iovec_t *src_iovecs = NULL, *dst_iovecs = NULL; | iovec_t *src_iovecs = NULL, *dst_iovecs = NULL; | ||||
uint8_t *src, *dst, *slrp, *dlrp, *blkend, *aadp; | uint8_t *src, *dst, *slrp, *dlrp, *blkend, *aadp; | ||||
▲ Show 20 Lines • Show All 177 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Special case handling routine for encrypting / decrypting dnode blocks. | * Special case handling routine for encrypting / decrypting dnode blocks. | ||||
*/ | */ | ||||
static int | static int | ||||
zio_crypt_init_uios_dnode(boolean_t encrypt, uint64_t version, | zio_crypt_init_uios_dnode(boolean_t encrypt, uint64_t version, | ||||
uint8_t *plainbuf, uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, | uint8_t *plainbuf, uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, | ||||
uio_t *puio, uio_t *cuio, uint_t *enc_len, uint8_t **authbuf, | zfs_uio_t *puio, zfs_uio_t *cuio, uint_t *enc_len, uint8_t **authbuf, | ||||
uint_t *auth_len, boolean_t *no_crypt) | uint_t *auth_len, boolean_t *no_crypt) | ||||
{ | { | ||||
int ret; | int ret; | ||||
uint_t nr_src, nr_dst, crypt_len; | uint_t nr_src, nr_dst, crypt_len; | ||||
uint_t aad_len = 0, nr_iovecs = 0, total_len = 0; | uint_t aad_len = 0, nr_iovecs = 0, total_len = 0; | ||||
uint_t i, j, max_dnp = datalen >> DNODE_SHIFT; | uint_t i, j, max_dnp = datalen >> DNODE_SHIFT; | ||||
iovec_t *src_iovecs = NULL, *dst_iovecs = NULL; | iovec_t *src_iovecs = NULL, *dst_iovecs = NULL; | ||||
uint8_t *src, *dst, *aadp; | uint8_t *src, *dst, *aadp; | ||||
▲ Show 20 Lines • Show All 166 Lines • ▼ Show 20 Lines | error: | ||||
puio->uio_iovcnt = 0; | puio->uio_iovcnt = 0; | ||||
cuio->uio_iov = NULL; | cuio->uio_iov = NULL; | ||||
cuio->uio_iovcnt = 0; | cuio->uio_iovcnt = 0; | ||||
return (ret); | return (ret); | ||||
} | } | ||||
static int | static int | ||||
zio_crypt_init_uios_normal(boolean_t encrypt, uint8_t *plainbuf, | zio_crypt_init_uios_normal(boolean_t encrypt, uint8_t *plainbuf, | ||||
uint8_t *cipherbuf, uint_t datalen, uio_t *puio, uio_t *cuio, | uint8_t *cipherbuf, uint_t datalen, zfs_uio_t *puio, zfs_uio_t *cuio, | ||||
uint_t *enc_len) | uint_t *enc_len) | ||||
{ | { | ||||
int ret; | int ret; | ||||
uint_t nr_plain = 1, nr_cipher = 2; | uint_t nr_plain = 1, nr_cipher = 2; | ||||
iovec_t *plain_iovecs = NULL, *cipher_iovecs = NULL; | iovec_t *plain_iovecs = NULL, *cipher_iovecs = NULL; | ||||
/* allocate the iovecs for the plain and cipher data */ | /* allocate the iovecs for the plain and cipher data */ | ||||
plain_iovecs = kmem_alloc(nr_plain * sizeof (iovec_t), | plain_iovecs = kmem_alloc(nr_plain * sizeof (iovec_t), | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
* Most blocks will use zio_crypt_init_uios_normal(), with ZIL and dnode blocks | * Most blocks will use zio_crypt_init_uios_normal(), with ZIL and dnode blocks | ||||
* requiring special handling to parse out pieces that are to be encrypted. The | * requiring special handling to parse out pieces that are to be encrypted. The | ||||
* authbuf is used by these special cases to store additional authenticated | * authbuf is used by these special cases to store additional authenticated | ||||
* data (AAD) for the encryption modes. | * data (AAD) for the encryption modes. | ||||
*/ | */ | ||||
static int | static int | ||||
zio_crypt_init_uios(boolean_t encrypt, uint64_t version, dmu_object_type_t ot, | zio_crypt_init_uios(boolean_t encrypt, uint64_t version, dmu_object_type_t ot, | ||||
uint8_t *plainbuf, uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, | uint8_t *plainbuf, uint8_t *cipherbuf, uint_t datalen, boolean_t byteswap, | ||||
uint8_t *mac, uio_t *puio, uio_t *cuio, uint_t *enc_len, uint8_t **authbuf, | uint8_t *mac, zfs_uio_t *puio, zfs_uio_t *cuio, uint_t *enc_len, | ||||
uint_t *auth_len, boolean_t *no_crypt) | uint8_t **authbuf, uint_t *auth_len, boolean_t *no_crypt) | ||||
{ | { | ||||
int ret; | int ret; | ||||
iovec_t *mac_iov; | iovec_t *mac_iov; | ||||
ASSERT(DMU_OT_IS_ENCRYPTED(ot) || ot == DMU_OT_NONE); | ASSERT(DMU_OT_IS_ENCRYPTED(ot) || ot == DMU_OT_NONE); | ||||
/* route to handler */ | /* route to handler */ | ||||
switch (ot) { | switch (ot) { | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | zio_do_crypt_data(boolean_t encrypt, zio_crypt_key_t *key, | ||||
uint8_t *mac, uint_t datalen, uint8_t *plainbuf, uint8_t *cipherbuf, | uint8_t *mac, uint_t datalen, uint8_t *plainbuf, uint8_t *cipherbuf, | ||||
boolean_t *no_crypt) | boolean_t *no_crypt) | ||||
{ | { | ||||
int ret; | int ret; | ||||
boolean_t locked = B_FALSE; | boolean_t locked = B_FALSE; | ||||
uint64_t crypt = key->zk_crypt; | uint64_t crypt = key->zk_crypt; | ||||
uint_t keydata_len = zio_crypt_table[crypt].ci_keylen; | uint_t keydata_len = zio_crypt_table[crypt].ci_keylen; | ||||
uint_t enc_len, auth_len; | uint_t enc_len, auth_len; | ||||
uio_t puio, cuio; | zfs_uio_t puio, cuio; | ||||
uint8_t enc_keydata[MASTER_KEY_MAX_LEN]; | uint8_t enc_keydata[MASTER_KEY_MAX_LEN]; | ||||
crypto_key_t tmp_ckey, *ckey = NULL; | crypto_key_t tmp_ckey, *ckey = NULL; | ||||
crypto_ctx_template_t tmpl; | crypto_ctx_template_t tmpl; | ||||
uint8_t *authbuf = NULL; | uint8_t *authbuf = NULL; | ||||
/* | /* | ||||
* If the needed key is the current one, just use it. Otherwise we | * If the needed key is the current one, just use it. Otherwise we | ||||
* need to generate a temporary one from the given salt + master key. | * need to generate a temporary one from the given salt + master key. | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if (ret == CPA_STATUS_SUCCESS) { | ||||
locked = B_FALSE; | locked = B_FALSE; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
/* If the hardware implementation fails fall back to software */ | /* If the hardware implementation fails fall back to software */ | ||||
} | } | ||||
bzero(&puio, sizeof (uio_t)); | bzero(&puio, sizeof (zfs_uio_t)); | ||||
bzero(&cuio, sizeof (uio_t)); | bzero(&cuio, sizeof (zfs_uio_t)); | ||||
/* create uios for encryption */ | /* create uios for encryption */ | ||||
ret = zio_crypt_init_uios(encrypt, key->zk_version, ot, plainbuf, | ret = zio_crypt_init_uios(encrypt, key->zk_version, ot, plainbuf, | ||||
cipherbuf, datalen, byteswap, mac, &puio, &cuio, &enc_len, | cipherbuf, datalen, byteswap, mac, &puio, &cuio, &enc_len, | ||||
&authbuf, &auth_len, no_crypt); | &authbuf, &auth_len, no_crypt); | ||||
if (ret != 0) | if (ret != 0) | ||||
goto error; | goto error; | ||||
▲ Show 20 Lines • Show All 87 Lines • Show Last 20 Lines |