123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright 2019 Google LLC
- */
- /*
- * Refer to Documentation/block/inline-encryption.rst for detailed explanation.
- */
- #define pr_fmt(fmt) "blk-crypto: " fmt
- #include <linux/blk-crypto.h>
- #include <linux/blkdev.h>
- #include <linux/keyslot-manager.h>
- #include <linux/random.h>
- #include <linux/siphash.h>
- #include "blk-crypto-internal.h"
- const struct blk_crypto_mode blk_crypto_modes[] = {
- [BLK_ENCRYPTION_MODE_AES_256_XTS] = {
- .cipher_str = "xts(aes)",
- .keysize = 64,
- .ivsize = 16,
- },
- [BLK_ENCRYPTION_MODE_AES_128_CBC_ESSIV] = {
- .cipher_str = "essiv(cbc(aes),sha256)",
- .keysize = 16,
- .ivsize = 16,
- },
- [BLK_ENCRYPTION_MODE_ADIANTUM] = {
- .cipher_str = "adiantum(xchacha12,aes)",
- .keysize = 32,
- .ivsize = 32,
- },
- };
- /* Check that all I/O segments are data unit aligned */
- static int bio_crypt_check_alignment(struct bio *bio)
- {
- const unsigned int data_unit_size =
- bio->bi_crypt_context->bc_key->data_unit_size;
- struct bvec_iter iter;
- struct bio_vec bv;
- bio_for_each_segment(bv, bio, iter) {
- if (!IS_ALIGNED(bv.bv_len | bv.bv_offset, data_unit_size))
- return -EIO;
- }
- return 0;
- }
- /**
- * blk_crypto_submit_bio - handle submitting bio for inline encryption
- *
- * @bio_ptr: pointer to original bio pointer
- *
- * If the bio doesn't have inline encryption enabled or the submitter already
- * specified a keyslot for the target device, do nothing. Else, a raw key must
- * have been provided, so acquire a device keyslot for it if supported. Else,
- * use the crypto API fallback.
- *
- * When the crypto API fallback is used for encryption, blk-crypto may choose to
- * split the bio into 2 - the first one that will continue to be processed and
- * the second one that will be resubmitted via generic_make_request.
- * A bounce bio will be allocated to encrypt the contents of the aforementioned
- * "first one", and *bio_ptr will be updated to this bounce bio.
- *
- * Return: 0 if bio submission should continue; nonzero if bio_endio() was
- * already called so bio submission should abort.
- */
- int blk_crypto_submit_bio(struct bio **bio_ptr)
- {
- struct bio *bio = *bio_ptr;
- struct request_queue *q;
- struct bio_crypt_ctx *bc = bio->bi_crypt_context;
- int err;
- if (!bc || !bio_has_data(bio))
- return 0;
- /*
- * When a read bio is marked for fallback decryption, its bi_iter is
- * saved so that when we decrypt the bio later, we know what part of it
- * was marked for fallback decryption (when the bio is passed down after
- * blk_crypto_submit bio, it may be split or advanced so we cannot rely
- * on the bi_iter while decrypting in blk_crypto_endio)
- */
- if (bio_crypt_fallback_crypted(bc))
- return 0;
- err = bio_crypt_check_alignment(bio);
- if (err) {
- bio->bi_status = BLK_STS_IOERR;
- goto out;
- }
- q = bio->bi_disk->queue;
- if (bc->bc_ksm) {
- /* Key already programmed into device? */
- if (q->ksm == bc->bc_ksm)
- return 0;
- /* Nope, release the existing keyslot. */
- bio_crypt_ctx_release_keyslot(bc);
- }
- /* Get device keyslot if supported */
- if (keyslot_manager_crypto_mode_supported(q->ksm,
- bc->bc_key->crypto_mode,
- blk_crypto_key_dun_bytes(bc->bc_key),
- bc->bc_key->data_unit_size,
- bc->bc_key->is_hw_wrapped)) {
- err = bio_crypt_ctx_acquire_keyslot(bc, q->ksm);
- if (!err)
- return 0;
- pr_warn_once("Failed to acquire keyslot for %s (err=%d). Falling back to crypto API.\n",
- bio->bi_disk->disk_name, err);
- }
- /* Fallback to crypto API */
- err = blk_crypto_fallback_submit_bio(bio_ptr);
- if (err)
- goto out;
- return 0;
- out:
- bio_endio(*bio_ptr);
- return err;
- }
- /**
- * blk_crypto_endio - clean up bio w.r.t inline encryption during bio_endio
- *
- * @bio: the bio to clean up
- *
- * If blk_crypto_submit_bio decided to fallback to crypto API for this bio,
- * we queue the bio for decryption into a workqueue and return false,
- * and call bio_endio(bio) at a later time (after the bio has been decrypted).
- *
- * If the bio is not to be decrypted by the crypto API, this function releases
- * the reference to the keyslot that blk_crypto_submit_bio got.
- *
- * Return: true if bio_endio should continue; false otherwise (bio_endio will
- * be called again when bio has been decrypted).
- */
- bool blk_crypto_endio(struct bio *bio)
- {
- struct bio_crypt_ctx *bc = bio->bi_crypt_context;
- if (!bc)
- return true;
- if (bio_crypt_fallback_crypted(bc)) {
- /*
- * The only bios who's crypto is handled by the blk-crypto
- * fallback when they reach here are those with
- * bio_data_dir(bio) == READ, since WRITE bios that are
- * encrypted by the crypto API fallback are handled by
- * blk_crypto_encrypt_endio().
- */
- return !blk_crypto_queue_decrypt_bio(bio);
- }
- if (bc->bc_keyslot >= 0)
- bio_crypt_ctx_release_keyslot(bc);
- return true;
- }
- /**
- * blk_crypto_init_key() - Prepare a key for use with blk-crypto
- * @blk_key: Pointer to the blk_crypto_key to initialize.
- * @raw_key: Pointer to the raw key.
- * @raw_key_size: Size of raw key. Must be at least the required size for the
- * chosen @crypto_mode; see blk_crypto_modes[]. (It's allowed
- * to be longer than the mode's actual key size, in order to
- * support inline encryption hardware that accepts wrapped keys.
- * @is_hw_wrapped has to be set for such keys)
- * @is_hw_wrapped: Denotes @raw_key is wrapped.
- * @crypto_mode: identifier for the encryption algorithm to use
- * @dun_bytes: number of bytes that will be used to specify the DUN when this
- * key is used
- * @data_unit_size: the data unit size to use for en/decryption
- *
- * Return: The blk_crypto_key that was prepared, or an ERR_PTR() on error. When
- * done using the key, it must be freed with blk_crypto_free_key().
- */
- int blk_crypto_init_key(struct blk_crypto_key *blk_key,
- const u8 *raw_key, unsigned int raw_key_size,
- bool is_hw_wrapped,
- enum blk_crypto_mode_num crypto_mode,
- unsigned int dun_bytes,
- unsigned int data_unit_size)
- {
- const struct blk_crypto_mode *mode;
- static siphash_key_t hash_key;
- u32 hash;
- memset(blk_key, 0, sizeof(*blk_key));
- if (crypto_mode >= ARRAY_SIZE(blk_crypto_modes))
- return -EINVAL;
- BUILD_BUG_ON(BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE < BLK_CRYPTO_MAX_KEY_SIZE);
- mode = &blk_crypto_modes[crypto_mode];
- if (is_hw_wrapped) {
- if (raw_key_size < mode->keysize ||
- raw_key_size > BLK_CRYPTO_MAX_WRAPPED_KEY_SIZE)
- return -EINVAL;
- } else {
- if (raw_key_size != mode->keysize)
- return -EINVAL;
- }
- if (dun_bytes <= 0 || dun_bytes > BLK_CRYPTO_MAX_IV_SIZE)
- return -EINVAL;
- if (!is_power_of_2(data_unit_size))
- return -EINVAL;
- blk_key->crypto_mode = crypto_mode;
- blk_key->data_unit_size = data_unit_size;
- blk_key->data_unit_size_bits = ilog2(data_unit_size);
- blk_key->size = raw_key_size;
- blk_key->is_hw_wrapped = is_hw_wrapped;
- memcpy(blk_key->raw, raw_key, raw_key_size);
- /*
- * The keyslot manager uses the SipHash of the key to implement O(1) key
- * lookups while avoiding leaking information about the keys. It's
- * precomputed here so that it only needs to be computed once per key.
- */
- get_random_once(&hash_key, sizeof(hash_key));
- hash = (u32)siphash(raw_key, raw_key_size, &hash_key);
- blk_crypto_key_set_hash_and_dun_bytes(blk_key, hash, dun_bytes);
- return 0;
- }
- EXPORT_SYMBOL_GPL(blk_crypto_init_key);
- /**
- * blk_crypto_start_using_mode() - Start using blk-crypto on a device
- * @crypto_mode: the crypto mode that will be used
- * @dun_bytes: number of bytes that will be used to specify the DUN
- * @data_unit_size: the data unit size that will be used
- * @is_hw_wrapped_key: whether the key will be hardware-wrapped
- * @q: the request queue for the device
- *
- * Upper layers must call this function to ensure that either the hardware
- * supports the needed crypto settings, or the crypto API fallback has
- * transforms for the needed mode allocated and ready to go.
- *
- * Return: 0 on success; -ENOPKG if the hardware doesn't support the crypto
- * settings and blk-crypto-fallback is either disabled or the needed
- * algorithm is disabled in the crypto API; or another -errno code.
- */
- int blk_crypto_start_using_mode(enum blk_crypto_mode_num crypto_mode,
- unsigned int dun_bytes,
- unsigned int data_unit_size,
- bool is_hw_wrapped_key,
- struct request_queue *q)
- {
- if (keyslot_manager_crypto_mode_supported(q->ksm, crypto_mode,
- dun_bytes, data_unit_size,
- is_hw_wrapped_key))
- return 0;
- if (is_hw_wrapped_key) {
- pr_warn_once("hardware doesn't support wrapped keys\n");
- return -EOPNOTSUPP;
- }
- return blk_crypto_fallback_start_using_mode(crypto_mode);
- }
- EXPORT_SYMBOL_GPL(blk_crypto_start_using_mode);
- /**
- * blk_crypto_evict_key() - Evict a key from any inline encryption hardware
- * it may have been programmed into
- * @q: The request queue who's keyslot manager this key might have been
- * programmed into
- * @key: The key to evict
- *
- * Upper layers (filesystems) should call this function to ensure that a key
- * is evicted from hardware that it might have been programmed into. This
- * will call keyslot_manager_evict_key on the queue's keyslot manager, if one
- * exists, and supports the crypto algorithm with the specified data unit size.
- * Otherwise, it will evict the key from the blk-crypto-fallback's ksm.
- *
- * Return: 0 on success, -err on error.
- */
- int blk_crypto_evict_key(struct request_queue *q,
- const struct blk_crypto_key *key)
- {
- if (q->ksm &&
- keyslot_manager_crypto_mode_supported(q->ksm, key->crypto_mode,
- blk_crypto_key_dun_bytes(key),
- key->data_unit_size,
- key->is_hw_wrapped))
- return keyslot_manager_evict_key(q->ksm, key);
- return blk_crypto_fallback_evict_key(key);
- }
- EXPORT_SYMBOL_GPL(blk_crypto_evict_key);
- inline void blk_crypto_flock(struct keyslot_manager *ksm, unsigned int flags)
- {
- ksm_flock(ksm, flags);
- }
- EXPORT_SYMBOL_GPL(blk_crypto_flock);
|