18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include <linux/ceph/ceph_debug.h>
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <linux/err.h>
68c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
78c2ecf20Sopenharmony_ci#include <linux/sched.h>
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <crypto/aes.h>
108c2ecf20Sopenharmony_ci#include <crypto/skcipher.h>
118c2ecf20Sopenharmony_ci#include <linux/key-type.h>
128c2ecf20Sopenharmony_ci#include <linux/sched/mm.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <keys/ceph-type.h>
158c2ecf20Sopenharmony_ci#include <keys/user-type.h>
168c2ecf20Sopenharmony_ci#include <linux/ceph/decode.h>
178c2ecf20Sopenharmony_ci#include "crypto.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Set ->key and ->tfm.  The rest of the key should be filled in before
218c2ecf20Sopenharmony_ci * this function is called.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_cistatic int set_secret(struct ceph_crypto_key *key, void *buf)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	unsigned int noio_flag;
268c2ecf20Sopenharmony_ci	int ret;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	key->key = NULL;
298c2ecf20Sopenharmony_ci	key->tfm = NULL;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	switch (key->type) {
328c2ecf20Sopenharmony_ci	case CEPH_CRYPTO_NONE:
338c2ecf20Sopenharmony_ci		return 0; /* nothing to do */
348c2ecf20Sopenharmony_ci	case CEPH_CRYPTO_AES:
358c2ecf20Sopenharmony_ci		break;
368c2ecf20Sopenharmony_ci	default:
378c2ecf20Sopenharmony_ci		return -ENOTSUPP;
388c2ecf20Sopenharmony_ci	}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (!key->len)
418c2ecf20Sopenharmony_ci		return -EINVAL;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	key->key = kmemdup(buf, key->len, GFP_NOIO);
448c2ecf20Sopenharmony_ci	if (!key->key) {
458c2ecf20Sopenharmony_ci		ret = -ENOMEM;
468c2ecf20Sopenharmony_ci		goto fail;
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	/* crypto_alloc_sync_skcipher() allocates with GFP_KERNEL */
508c2ecf20Sopenharmony_ci	noio_flag = memalloc_noio_save();
518c2ecf20Sopenharmony_ci	key->tfm = crypto_alloc_sync_skcipher("cbc(aes)", 0, 0);
528c2ecf20Sopenharmony_ci	memalloc_noio_restore(noio_flag);
538c2ecf20Sopenharmony_ci	if (IS_ERR(key->tfm)) {
548c2ecf20Sopenharmony_ci		ret = PTR_ERR(key->tfm);
558c2ecf20Sopenharmony_ci		key->tfm = NULL;
568c2ecf20Sopenharmony_ci		goto fail;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	ret = crypto_sync_skcipher_setkey(key->tfm, key->key, key->len);
608c2ecf20Sopenharmony_ci	if (ret)
618c2ecf20Sopenharmony_ci		goto fail;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return 0;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cifail:
668c2ecf20Sopenharmony_ci	ceph_crypto_key_destroy(key);
678c2ecf20Sopenharmony_ci	return ret;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ciint ceph_crypto_key_clone(struct ceph_crypto_key *dst,
718c2ecf20Sopenharmony_ci			  const struct ceph_crypto_key *src)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	memcpy(dst, src, sizeof(struct ceph_crypto_key));
748c2ecf20Sopenharmony_ci	return set_secret(dst, src->key);
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ciint ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	if (*p + sizeof(u16) + sizeof(key->created) +
808c2ecf20Sopenharmony_ci	    sizeof(u16) + key->len > end)
818c2ecf20Sopenharmony_ci		return -ERANGE;
828c2ecf20Sopenharmony_ci	ceph_encode_16(p, key->type);
838c2ecf20Sopenharmony_ci	ceph_encode_copy(p, &key->created, sizeof(key->created));
848c2ecf20Sopenharmony_ci	ceph_encode_16(p, key->len);
858c2ecf20Sopenharmony_ci	ceph_encode_copy(p, key->key, key->len);
868c2ecf20Sopenharmony_ci	return 0;
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ciint ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	int ret;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad);
948c2ecf20Sopenharmony_ci	key->type = ceph_decode_16(p);
958c2ecf20Sopenharmony_ci	ceph_decode_copy(p, &key->created, sizeof(key->created));
968c2ecf20Sopenharmony_ci	key->len = ceph_decode_16(p);
978c2ecf20Sopenharmony_ci	ceph_decode_need(p, end, key->len, bad);
988c2ecf20Sopenharmony_ci	ret = set_secret(key, *p);
998c2ecf20Sopenharmony_ci	*p += key->len;
1008c2ecf20Sopenharmony_ci	return ret;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cibad:
1038c2ecf20Sopenharmony_ci	dout("failed to decode crypto key\n");
1048c2ecf20Sopenharmony_ci	return -EINVAL;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ciint ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	int inlen = strlen(inkey);
1108c2ecf20Sopenharmony_ci	int blen = inlen * 3 / 4;
1118c2ecf20Sopenharmony_ci	void *buf, *p;
1128c2ecf20Sopenharmony_ci	int ret;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	dout("crypto_key_unarmor %s\n", inkey);
1158c2ecf20Sopenharmony_ci	buf = kmalloc(blen, GFP_NOFS);
1168c2ecf20Sopenharmony_ci	if (!buf)
1178c2ecf20Sopenharmony_ci		return -ENOMEM;
1188c2ecf20Sopenharmony_ci	blen = ceph_unarmor(buf, inkey, inkey+inlen);
1198c2ecf20Sopenharmony_ci	if (blen < 0) {
1208c2ecf20Sopenharmony_ci		kfree(buf);
1218c2ecf20Sopenharmony_ci		return blen;
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	p = buf;
1258c2ecf20Sopenharmony_ci	ret = ceph_crypto_key_decode(key, &p, p + blen);
1268c2ecf20Sopenharmony_ci	kfree(buf);
1278c2ecf20Sopenharmony_ci	if (ret)
1288c2ecf20Sopenharmony_ci		return ret;
1298c2ecf20Sopenharmony_ci	dout("crypto_key_unarmor key %p type %d len %d\n", key,
1308c2ecf20Sopenharmony_ci	     key->type, key->len);
1318c2ecf20Sopenharmony_ci	return 0;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_civoid ceph_crypto_key_destroy(struct ceph_crypto_key *key)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	if (key) {
1378c2ecf20Sopenharmony_ci		kfree(key->key);
1388c2ecf20Sopenharmony_ci		key->key = NULL;
1398c2ecf20Sopenharmony_ci		if (key->tfm) {
1408c2ecf20Sopenharmony_ci			crypto_free_sync_skcipher(key->tfm);
1418c2ecf20Sopenharmony_ci			key->tfm = NULL;
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic const u8 *aes_iv = (u8 *)CEPH_AES_IV;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci/*
1498c2ecf20Sopenharmony_ci * Should be used for buffers allocated with ceph_kvmalloc().
1508c2ecf20Sopenharmony_ci * Currently these are encrypt out-buffer (ceph_buffer) and decrypt
1518c2ecf20Sopenharmony_ci * in-buffer (msg front).
1528c2ecf20Sopenharmony_ci *
1538c2ecf20Sopenharmony_ci * Dispose of @sgt with teardown_sgtable().
1548c2ecf20Sopenharmony_ci *
1558c2ecf20Sopenharmony_ci * @prealloc_sg is to avoid memory allocation inside sg_alloc_table()
1568c2ecf20Sopenharmony_ci * in cases where a single sg is sufficient.  No attempt to reduce the
1578c2ecf20Sopenharmony_ci * number of sgs by squeezing physically contiguous pages together is
1588c2ecf20Sopenharmony_ci * made though, for simplicity.
1598c2ecf20Sopenharmony_ci */
1608c2ecf20Sopenharmony_cistatic int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
1618c2ecf20Sopenharmony_ci			 const void *buf, unsigned int buf_len)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	struct scatterlist *sg;
1648c2ecf20Sopenharmony_ci	const bool is_vmalloc = is_vmalloc_addr(buf);
1658c2ecf20Sopenharmony_ci	unsigned int off = offset_in_page(buf);
1668c2ecf20Sopenharmony_ci	unsigned int chunk_cnt = 1;
1678c2ecf20Sopenharmony_ci	unsigned int chunk_len = PAGE_ALIGN(off + buf_len);
1688c2ecf20Sopenharmony_ci	int i;
1698c2ecf20Sopenharmony_ci	int ret;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (buf_len == 0) {
1728c2ecf20Sopenharmony_ci		memset(sgt, 0, sizeof(*sgt));
1738c2ecf20Sopenharmony_ci		return -EINVAL;
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	if (is_vmalloc) {
1778c2ecf20Sopenharmony_ci		chunk_cnt = chunk_len >> PAGE_SHIFT;
1788c2ecf20Sopenharmony_ci		chunk_len = PAGE_SIZE;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (chunk_cnt > 1) {
1828c2ecf20Sopenharmony_ci		ret = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS);
1838c2ecf20Sopenharmony_ci		if (ret)
1848c2ecf20Sopenharmony_ci			return ret;
1858c2ecf20Sopenharmony_ci	} else {
1868c2ecf20Sopenharmony_ci		WARN_ON(chunk_cnt != 1);
1878c2ecf20Sopenharmony_ci		sg_init_table(prealloc_sg, 1);
1888c2ecf20Sopenharmony_ci		sgt->sgl = prealloc_sg;
1898c2ecf20Sopenharmony_ci		sgt->nents = sgt->orig_nents = 1;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
1938c2ecf20Sopenharmony_ci		struct page *page;
1948c2ecf20Sopenharmony_ci		unsigned int len = min(chunk_len - off, buf_len);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci		if (is_vmalloc)
1978c2ecf20Sopenharmony_ci			page = vmalloc_to_page(buf);
1988c2ecf20Sopenharmony_ci		else
1998c2ecf20Sopenharmony_ci			page = virt_to_page(buf);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		sg_set_page(sg, page, len, off);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		off = 0;
2048c2ecf20Sopenharmony_ci		buf += len;
2058c2ecf20Sopenharmony_ci		buf_len -= len;
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci	WARN_ON(buf_len != 0);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	return 0;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic void teardown_sgtable(struct sg_table *sgt)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	if (sgt->orig_nents > 1)
2158c2ecf20Sopenharmony_ci		sg_free_table(sgt);
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic int ceph_aes_crypt(const struct ceph_crypto_key *key, bool encrypt,
2198c2ecf20Sopenharmony_ci			  void *buf, int buf_len, int in_len, int *pout_len)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	SYNC_SKCIPHER_REQUEST_ON_STACK(req, key->tfm);
2228c2ecf20Sopenharmony_ci	struct sg_table sgt;
2238c2ecf20Sopenharmony_ci	struct scatterlist prealloc_sg;
2248c2ecf20Sopenharmony_ci	char iv[AES_BLOCK_SIZE] __aligned(8);
2258c2ecf20Sopenharmony_ci	int pad_byte = AES_BLOCK_SIZE - (in_len & (AES_BLOCK_SIZE - 1));
2268c2ecf20Sopenharmony_ci	int crypt_len = encrypt ? in_len + pad_byte : in_len;
2278c2ecf20Sopenharmony_ci	int ret;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	WARN_ON(crypt_len > buf_len);
2308c2ecf20Sopenharmony_ci	if (encrypt)
2318c2ecf20Sopenharmony_ci		memset(buf + in_len, pad_byte, pad_byte);
2328c2ecf20Sopenharmony_ci	ret = setup_sgtable(&sgt, &prealloc_sg, buf, crypt_len);
2338c2ecf20Sopenharmony_ci	if (ret)
2348c2ecf20Sopenharmony_ci		return ret;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	memcpy(iv, aes_iv, AES_BLOCK_SIZE);
2378c2ecf20Sopenharmony_ci	skcipher_request_set_sync_tfm(req, key->tfm);
2388c2ecf20Sopenharmony_ci	skcipher_request_set_callback(req, 0, NULL, NULL);
2398c2ecf20Sopenharmony_ci	skcipher_request_set_crypt(req, sgt.sgl, sgt.sgl, crypt_len, iv);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	/*
2428c2ecf20Sopenharmony_ci	print_hex_dump(KERN_ERR, "key: ", DUMP_PREFIX_NONE, 16, 1,
2438c2ecf20Sopenharmony_ci		       key->key, key->len, 1);
2448c2ecf20Sopenharmony_ci	print_hex_dump(KERN_ERR, " in: ", DUMP_PREFIX_NONE, 16, 1,
2458c2ecf20Sopenharmony_ci		       buf, crypt_len, 1);
2468c2ecf20Sopenharmony_ci	*/
2478c2ecf20Sopenharmony_ci	if (encrypt)
2488c2ecf20Sopenharmony_ci		ret = crypto_skcipher_encrypt(req);
2498c2ecf20Sopenharmony_ci	else
2508c2ecf20Sopenharmony_ci		ret = crypto_skcipher_decrypt(req);
2518c2ecf20Sopenharmony_ci	skcipher_request_zero(req);
2528c2ecf20Sopenharmony_ci	if (ret) {
2538c2ecf20Sopenharmony_ci		pr_err("%s %scrypt failed: %d\n", __func__,
2548c2ecf20Sopenharmony_ci		       encrypt ? "en" : "de", ret);
2558c2ecf20Sopenharmony_ci		goto out_sgt;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci	/*
2588c2ecf20Sopenharmony_ci	print_hex_dump(KERN_ERR, "out: ", DUMP_PREFIX_NONE, 16, 1,
2598c2ecf20Sopenharmony_ci		       buf, crypt_len, 1);
2608c2ecf20Sopenharmony_ci	*/
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (encrypt) {
2638c2ecf20Sopenharmony_ci		*pout_len = crypt_len;
2648c2ecf20Sopenharmony_ci	} else {
2658c2ecf20Sopenharmony_ci		pad_byte = *(char *)(buf + in_len - 1);
2668c2ecf20Sopenharmony_ci		if (pad_byte > 0 && pad_byte <= AES_BLOCK_SIZE &&
2678c2ecf20Sopenharmony_ci		    in_len >= pad_byte) {
2688c2ecf20Sopenharmony_ci			*pout_len = in_len - pad_byte;
2698c2ecf20Sopenharmony_ci		} else {
2708c2ecf20Sopenharmony_ci			pr_err("%s got bad padding %d on in_len %d\n",
2718c2ecf20Sopenharmony_ci			       __func__, pad_byte, in_len);
2728c2ecf20Sopenharmony_ci			ret = -EPERM;
2738c2ecf20Sopenharmony_ci			goto out_sgt;
2748c2ecf20Sopenharmony_ci		}
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ciout_sgt:
2788c2ecf20Sopenharmony_ci	teardown_sgtable(&sgt);
2798c2ecf20Sopenharmony_ci	return ret;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ciint ceph_crypt(const struct ceph_crypto_key *key, bool encrypt,
2838c2ecf20Sopenharmony_ci	       void *buf, int buf_len, int in_len, int *pout_len)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	switch (key->type) {
2868c2ecf20Sopenharmony_ci	case CEPH_CRYPTO_NONE:
2878c2ecf20Sopenharmony_ci		*pout_len = in_len;
2888c2ecf20Sopenharmony_ci		return 0;
2898c2ecf20Sopenharmony_ci	case CEPH_CRYPTO_AES:
2908c2ecf20Sopenharmony_ci		return ceph_aes_crypt(key, encrypt, buf, buf_len, in_len,
2918c2ecf20Sopenharmony_ci				      pout_len);
2928c2ecf20Sopenharmony_ci	default:
2938c2ecf20Sopenharmony_ci		return -ENOTSUPP;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic int ceph_key_preparse(struct key_preparsed_payload *prep)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	struct ceph_crypto_key *ckey;
3008c2ecf20Sopenharmony_ci	size_t datalen = prep->datalen;
3018c2ecf20Sopenharmony_ci	int ret;
3028c2ecf20Sopenharmony_ci	void *p;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	ret = -EINVAL;
3058c2ecf20Sopenharmony_ci	if (datalen <= 0 || datalen > 32767 || !prep->data)
3068c2ecf20Sopenharmony_ci		goto err;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	ret = -ENOMEM;
3098c2ecf20Sopenharmony_ci	ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
3108c2ecf20Sopenharmony_ci	if (!ckey)
3118c2ecf20Sopenharmony_ci		goto err;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	/* TODO ceph_crypto_key_decode should really take const input */
3148c2ecf20Sopenharmony_ci	p = (void *)prep->data;
3158c2ecf20Sopenharmony_ci	ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen);
3168c2ecf20Sopenharmony_ci	if (ret < 0)
3178c2ecf20Sopenharmony_ci		goto err_ckey;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	prep->payload.data[0] = ckey;
3208c2ecf20Sopenharmony_ci	prep->quotalen = datalen;
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cierr_ckey:
3248c2ecf20Sopenharmony_ci	kfree(ckey);
3258c2ecf20Sopenharmony_cierr:
3268c2ecf20Sopenharmony_ci	return ret;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic void ceph_key_free_preparse(struct key_preparsed_payload *prep)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct ceph_crypto_key *ckey = prep->payload.data[0];
3328c2ecf20Sopenharmony_ci	ceph_crypto_key_destroy(ckey);
3338c2ecf20Sopenharmony_ci	kfree(ckey);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic void ceph_key_destroy(struct key *key)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	struct ceph_crypto_key *ckey = key->payload.data[0];
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	ceph_crypto_key_destroy(ckey);
3418c2ecf20Sopenharmony_ci	kfree(ckey);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistruct key_type key_type_ceph = {
3458c2ecf20Sopenharmony_ci	.name		= "ceph",
3468c2ecf20Sopenharmony_ci	.preparse	= ceph_key_preparse,
3478c2ecf20Sopenharmony_ci	.free_preparse	= ceph_key_free_preparse,
3488c2ecf20Sopenharmony_ci	.instantiate	= generic_key_instantiate,
3498c2ecf20Sopenharmony_ci	.destroy	= ceph_key_destroy,
3508c2ecf20Sopenharmony_ci};
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ciint __init ceph_crypto_init(void)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	return register_key_type(&key_type_ceph);
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_civoid ceph_crypto_shutdown(void)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	unregister_key_type(&key_type_ceph);
3608c2ecf20Sopenharmony_ci}
361