18b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
23d14c5d2b6e15c21d8e5467dc62d33127c23a644Yehuda Sadeh#include <linux/ceph/ceph_debug.h>
38b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
48b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil#include <linux/err.h>
58b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil#include <linux/scatterlist.h>
65a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
78b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil#include <crypto/hash.h>
84b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen#include <linux/key-type.h>
98b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
104b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen#include <keys/ceph-type.h>
117c3bec0a1f2cba8a01b505f032a75cfb8d5cd56dDavid Howells#include <keys/user-type.h>
123d14c5d2b6e15c21d8e5467dc62d33127c23a644Yehuda Sadeh#include <linux/ceph/decode.h>
138b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil#include "crypto.h"
148b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
158323c3aa74cd92465350294567142d12ffdcc963Tommi Virtanenint ceph_crypto_key_clone(struct ceph_crypto_key *dst,
168323c3aa74cd92465350294567142d12ffdcc963Tommi Virtanen			  const struct ceph_crypto_key *src)
178323c3aa74cd92465350294567142d12ffdcc963Tommi Virtanen{
188323c3aa74cd92465350294567142d12ffdcc963Tommi Virtanen	memcpy(dst, src, sizeof(struct ceph_crypto_key));
19186482560f660b8dbf77ee43aa6489cb45d342cdThomas Meyer	dst->key = kmemdup(src->key, src->len, GFP_NOFS);
208323c3aa74cd92465350294567142d12ffdcc963Tommi Virtanen	if (!dst->key)
218323c3aa74cd92465350294567142d12ffdcc963Tommi Virtanen		return -ENOMEM;
228323c3aa74cd92465350294567142d12ffdcc963Tommi Virtanen	return 0;
238323c3aa74cd92465350294567142d12ffdcc963Tommi Virtanen}
248323c3aa74cd92465350294567142d12ffdcc963Tommi Virtanen
258b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weilint ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
268b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
278b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (*p + sizeof(u16) + sizeof(key->created) +
288b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	    sizeof(u16) + key->len > end)
298b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return -ERANGE;
308b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ceph_encode_16(p, key->type);
318b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ceph_encode_copy(p, &key->created, sizeof(key->created));
328b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ceph_encode_16(p, key->len);
338b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ceph_encode_copy(p, key->key, key->len);
348b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	return 0;
358b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
368b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
378b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weilint ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
388b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
398b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad);
408b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	key->type = ceph_decode_16(p);
418b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ceph_decode_copy(p, &key->created, sizeof(key->created));
428b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	key->len = ceph_decode_16(p);
438b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ceph_decode_need(p, end, key->len, bad);
448b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	key->key = kmalloc(key->len, GFP_NOFS);
458b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (!key->key)
468b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return -ENOMEM;
478b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ceph_decode_copy(p, key->key, key->len);
488b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	return 0;
498b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
508b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weilbad:
518b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	dout("failed to decode crypto key\n");
528b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	return -EINVAL;
538b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
548b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
558b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weilint ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
568b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
578b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int inlen = strlen(inkey);
588b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int blen = inlen * 3 / 4;
598b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	void *buf, *p;
608b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int ret;
618b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
628b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	dout("crypto_key_unarmor %s\n", inkey);
638b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	buf = kmalloc(blen, GFP_NOFS);
648b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (!buf)
658b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return -ENOMEM;
668b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	blen = ceph_unarmor(buf, inkey, inkey+inlen);
678b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (blen < 0) {
688b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		kfree(buf);
698b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return blen;
708b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
718b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
728b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	p = buf;
738b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ret = ceph_crypto_key_decode(key, &p, p + blen);
748b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	kfree(buf);
758b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (ret)
768b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return ret;
778b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	dout("crypto_key_unarmor key %p type %d len %d\n", key,
788b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	     key->type, key->len);
798b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	return 0;
808b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
818b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
828b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
838b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
848b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil#define AES_KEY_SIZE 16
858b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
868b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weilstatic struct crypto_blkcipher *ceph_crypto_alloc_cipher(void)
878b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
888b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	return crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
898b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
908b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
91cbbfe499055f49c09210e04d9f88c2f483052384Sage Weilstatic const u8 *aes_iv = (u8 *)CEPH_AES_IV;
928b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
93aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov/*
94aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov * Should be used for buffers allocated with ceph_kvmalloc().
95aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov * Currently these are encrypt out-buffer (ceph_buffer) and decrypt
96aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov * in-buffer (msg front).
97aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov *
98aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov * Dispose of @sgt with teardown_sgtable().
99aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov *
100aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov * @prealloc_sg is to avoid memory allocation inside sg_alloc_table()
101aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov * in cases where a single sg is sufficient.  No attempt to reduce the
102aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov * number of sgs by squeezing physically contiguous pages together is
103aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov * made though, for simplicity.
104aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov */
105aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovstatic int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg,
106aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov			 const void *buf, unsigned int buf_len)
107aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov{
108aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	struct scatterlist *sg;
109aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	const bool is_vmalloc = is_vmalloc_addr(buf);
110aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	unsigned int off = offset_in_page(buf);
111aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	unsigned int chunk_cnt = 1;
112aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	unsigned int chunk_len = PAGE_ALIGN(off + buf_len);
113aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	int i;
114aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	int ret;
115aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
116aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (buf_len == 0) {
117aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		memset(sgt, 0, sizeof(*sgt));
118aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		return -EINVAL;
119aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	}
120aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
121aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (is_vmalloc) {
122aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		chunk_cnt = chunk_len >> PAGE_SHIFT;
123aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		chunk_len = PAGE_SIZE;
124aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	}
125aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
126aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (chunk_cnt > 1) {
127aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		ret = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS);
128aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		if (ret)
129aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov			return ret;
130aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	} else {
131aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		WARN_ON(chunk_cnt != 1);
132aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		sg_init_table(prealloc_sg, 1);
133aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		sgt->sgl = prealloc_sg;
134aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		sgt->nents = sgt->orig_nents = 1;
135aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	}
136aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
137aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
138aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		struct page *page;
139aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		unsigned int len = min(chunk_len - off, buf_len);
140aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
141aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		if (is_vmalloc)
142aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov			page = vmalloc_to_page(buf);
143aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		else
144aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov			page = virt_to_page(buf);
145aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
146aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		sg_set_page(sg, page, len, off);
147aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
148aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		off = 0;
149aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		buf += len;
150aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		buf_len -= len;
151aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	}
152aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	WARN_ON(buf_len != 0);
153aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
154aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	return 0;
155aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov}
156aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
157aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovstatic void teardown_sgtable(struct sg_table *sgt)
158aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov{
159aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (sgt->orig_nents > 1)
160aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		sg_free_table(sgt);
161aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov}
162aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
163cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadehstatic int ceph_aes_encrypt(const void *key, int key_len,
164cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			    void *dst, size_t *dst_len,
165cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			    const void *src, size_t src_len)
1668b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
167aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	struct scatterlist sg_in[2], prealloc_sg;
168aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	struct sg_table sg_out;
1698b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
1708b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
1718b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int ret;
1728b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	void *iv;
1738b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int ivsize;
1748b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	size_t zero_padding = (0x10 - (src_len & 0x0f));
1758b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	char pad[16];
1768b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
1778b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (IS_ERR(tfm))
1788b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return PTR_ERR(tfm);
1798b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
1808b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	memset(pad, zero_padding, zero_padding);
1818b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
1828b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*dst_len = src_len + zero_padding;
1838b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
1848b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_init_table(sg_in, 2);
1858b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_in[0], src, src_len);
1868b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_in[1], pad, zero_padding);
187aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	ret = setup_sgtable(&sg_out, &prealloc_sg, dst, *dst_len);
188aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (ret)
189aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		goto out_tfm;
190aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
191aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	crypto_blkcipher_setkey((void *)tfm, key, key_len);
1928b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	iv = crypto_blkcipher_crt(tfm)->iv;
1938b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ivsize = crypto_blkcipher_ivsize(tfm);
1948b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	memcpy(iv, aes_iv, ivsize);
195aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
1968b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	/*
1978b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1,
1988b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       key, key_len, 1);
1998b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "enc src: ", DUMP_PREFIX_NONE, 16, 1,
2008b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			src, src_len, 1);
2018b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1,
2028b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			pad, zero_padding, 1);
2038b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*/
204aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	ret = crypto_blkcipher_encrypt(&desc, sg_out.sgl, sg_in,
2058b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil				     src_len + zero_padding);
206aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (ret < 0) {
2078b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		pr_err("ceph_aes_crypt failed %d\n", ret);
208aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		goto out_sg;
209aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	}
2108b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	/*
2118b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1,
2128b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       dst, *dst_len, 1);
2138b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*/
214aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
215aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovout_sg:
216aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	teardown_sgtable(&sg_out);
217aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovout_tfm:
218aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	crypto_free_blkcipher(tfm);
219aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	return ret;
2208b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
2218b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
222cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadehstatic int ceph_aes_encrypt2(const void *key, int key_len, void *dst,
223cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			     size_t *dst_len,
224cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			     const void *src1, size_t src1_len,
225cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			     const void *src2, size_t src2_len)
2268b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
227aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	struct scatterlist sg_in[3], prealloc_sg;
228aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	struct sg_table sg_out;
2298b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
2308b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
2318b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int ret;
2328b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	void *iv;
2338b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int ivsize;
2348b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f));
2358b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	char pad[16];
2368b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
2378b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (IS_ERR(tfm))
2388b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return PTR_ERR(tfm);
2398b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
2408b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	memset(pad, zero_padding, zero_padding);
2418b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
2428b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*dst_len = src1_len + src2_len + zero_padding;
2438b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
2448b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_init_table(sg_in, 3);
2458b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_in[0], src1, src1_len);
2468b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_in[1], src2, src2_len);
2478b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_in[2], pad, zero_padding);
248aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	ret = setup_sgtable(&sg_out, &prealloc_sg, dst, *dst_len);
249aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (ret)
250aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		goto out_tfm;
251aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
252aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	crypto_blkcipher_setkey((void *)tfm, key, key_len);
2538b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	iv = crypto_blkcipher_crt(tfm)->iv;
2548b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ivsize = crypto_blkcipher_ivsize(tfm);
2558b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	memcpy(iv, aes_iv, ivsize);
256aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
2578b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	/*
2588b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "enc  key: ", DUMP_PREFIX_NONE, 16, 1,
2598b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       key, key_len, 1);
2608b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "enc src1: ", DUMP_PREFIX_NONE, 16, 1,
2618b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			src1, src1_len, 1);
2628b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "enc src2: ", DUMP_PREFIX_NONE, 16, 1,
2638b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			src2, src2_len, 1);
2648b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "enc  pad: ", DUMP_PREFIX_NONE, 16, 1,
2658b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			pad, zero_padding, 1);
2668b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*/
267aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	ret = crypto_blkcipher_encrypt(&desc, sg_out.sgl, sg_in,
2688b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil				     src1_len + src2_len + zero_padding);
269aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (ret < 0) {
2708b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		pr_err("ceph_aes_crypt2 failed %d\n", ret);
271aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		goto out_sg;
272aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	}
2738b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	/*
2748b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "enc  out: ", DUMP_PREFIX_NONE, 16, 1,
2758b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       dst, *dst_len, 1);
2768b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*/
277aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
278aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovout_sg:
279aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	teardown_sgtable(&sg_out);
280aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovout_tfm:
281aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	crypto_free_blkcipher(tfm);
282aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	return ret;
2838b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
2848b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
285cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadehstatic int ceph_aes_decrypt(const void *key, int key_len,
286cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			    void *dst, size_t *dst_len,
287cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			    const void *src, size_t src_len)
2888b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
289aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	struct sg_table sg_in;
290aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	struct scatterlist sg_out[2], prealloc_sg;
2918b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
2928b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	struct blkcipher_desc desc = { .tfm = tfm };
2938b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	char pad[16];
2948b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	void *iv;
2958b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int ivsize;
2968b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int ret;
2978b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int last_byte;
2988b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
2998b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (IS_ERR(tfm))
3008b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return PTR_ERR(tfm);
3018b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
3028b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_init_table(sg_out, 2);
3038b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_out[0], dst, *dst_len);
3048b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_out[1], pad, sizeof(pad));
305aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	ret = setup_sgtable(&sg_in, &prealloc_sg, src, src_len);
306aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (ret)
307aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		goto out_tfm;
3088b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
309aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	crypto_blkcipher_setkey((void *)tfm, key, key_len);
3108b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	iv = crypto_blkcipher_crt(tfm)->iv;
3118b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ivsize = crypto_blkcipher_ivsize(tfm);
3128b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	memcpy(iv, aes_iv, ivsize);
3138b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
3148b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	/*
3158b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1,
3168b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       key, key_len, 1);
3178b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "dec  in: ", DUMP_PREFIX_NONE, 16, 1,
3188b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       src, src_len, 1);
3198b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*/
320aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in.sgl, src_len);
3218b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (ret < 0) {
3228b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		pr_err("ceph_aes_decrypt failed %d\n", ret);
323aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		goto out_sg;
3248b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
3258b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
3268b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (src_len <= *dst_len)
3278b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		last_byte = ((char *)dst)[src_len - 1];
3288b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	else
3298b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		last_byte = pad[src_len - *dst_len - 1];
3308b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (last_byte <= 16 && src_len >= last_byte) {
3318b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		*dst_len = src_len - last_byte;
3328b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	} else {
3338b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
3348b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       last_byte, (int)src_len);
3358b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return -EPERM;  /* bad padding */
3368b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
3378b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	/*
3388b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "dec out: ", DUMP_PREFIX_NONE, 16, 1,
3398b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       dst, *dst_len, 1);
3408b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*/
341aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov
342aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovout_sg:
343aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	teardown_sgtable(&sg_in);
344aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovout_tfm:
345aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	crypto_free_blkcipher(tfm);
346aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	return ret;
3478b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
3488b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
349cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadehstatic int ceph_aes_decrypt2(const void *key, int key_len,
350cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			     void *dst1, size_t *dst1_len,
351cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			     void *dst2, size_t *dst2_len,
352cd84db6e4051a9fb7941d49d31a0193a3371fd61Yehuda Sadeh			     const void *src, size_t src_len)
3538b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
354aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	struct sg_table sg_in;
355aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	struct scatterlist sg_out[3], prealloc_sg;
3568b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
3578b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	struct blkcipher_desc desc = { .tfm = tfm };
3588b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	char pad[16];
3598b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	void *iv;
3608b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int ivsize;
3618b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int ret;
3628b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	int last_byte;
3638b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
3648b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (IS_ERR(tfm))
3658b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return PTR_ERR(tfm);
3668b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
3678b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_init_table(sg_out, 3);
3688b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_out[0], dst1, *dst1_len);
3698b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_out[1], dst2, *dst2_len);
3708b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	sg_set_buf(&sg_out[2], pad, sizeof(pad));
371aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	ret = setup_sgtable(&sg_in, &prealloc_sg, src, src_len);
372aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	if (ret)
373aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		goto out_tfm;
3748b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
3758b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	crypto_blkcipher_setkey((void *)tfm, key, key_len);
3768b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	iv = crypto_blkcipher_crt(tfm)->iv;
3778b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	ivsize = crypto_blkcipher_ivsize(tfm);
3788b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	memcpy(iv, aes_iv, ivsize);
3798b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
3808b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	/*
3818b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "dec  key: ", DUMP_PREFIX_NONE, 16, 1,
3828b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       key, key_len, 1);
3838b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "dec   in: ", DUMP_PREFIX_NONE, 16, 1,
3848b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       src, src_len, 1);
3858b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*/
386aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in.sgl, src_len);
3878b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (ret < 0) {
3888b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		pr_err("ceph_aes_decrypt failed %d\n", ret);
389aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov		goto out_sg;
3908b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
3918b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
3928b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (src_len <= *dst1_len)
3938b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		last_byte = ((char *)dst1)[src_len - 1];
3948b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	else if (src_len <= *dst1_len + *dst2_len)
3958b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		last_byte = ((char *)dst2)[src_len - *dst1_len - 1];
3968b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	else
3978b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		last_byte = pad[src_len - *dst1_len - *dst2_len - 1];
3988b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (last_byte <= 16 && src_len >= last_byte) {
3998b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		src_len -= last_byte;
4008b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	} else {
4018b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
4028b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       last_byte, (int)src_len);
4038b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return -EPERM;  /* bad padding */
4048b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
4058b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4068b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	if (src_len < *dst1_len) {
4078b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		*dst1_len = src_len;
4088b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		*dst2_len = 0;
4098b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	} else {
4108b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		*dst2_len = src_len - *dst1_len;
4118b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
4128b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	/*
4138b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "dec  out1: ", DUMP_PREFIX_NONE, 16, 1,
4148b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       dst1, *dst1_len, 1);
4158b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	print_hex_dump(KERN_ERR, "dec  out2: ", DUMP_PREFIX_NONE, 16, 1,
4168b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		       dst2, *dst2_len, 1);
4178b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	*/
4188b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
419aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovout_sg:
420aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	teardown_sgtable(&sg_in);
421aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomovout_tfm:
422aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	crypto_free_blkcipher(tfm);
423aaef31703a0cf6a733e651885bfb49edc3ac6774Ilya Dryomov	return ret;
4248b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
4258b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4268b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4278b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weilint ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
4288b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		 const void *src, size_t src_len)
4298b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
4308b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	switch (secret->type) {
4318b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	case CEPH_CRYPTO_NONE:
4328b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		if (*dst_len < src_len)
4338b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			return -ERANGE;
4348b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		memcpy(dst, src, src_len);
4358b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		*dst_len = src_len;
4368b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return 0;
4378b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4388b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	case CEPH_CRYPTO_AES:
4398b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return ceph_aes_decrypt(secret->key, secret->len, dst,
4408b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil					dst_len, src, src_len);
4418b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4428b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	default:
4438b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return -EINVAL;
4448b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
4458b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
4468b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4478b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weilint ceph_decrypt2(struct ceph_crypto_key *secret,
4488b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			void *dst1, size_t *dst1_len,
4498b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			void *dst2, size_t *dst2_len,
4508b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			const void *src, size_t src_len)
4518b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
4528b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	size_t t;
4538b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4548b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	switch (secret->type) {
4558b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	case CEPH_CRYPTO_NONE:
4568b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		if (*dst1_len + *dst2_len < src_len)
4578b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			return -ERANGE;
4588b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		t = min(*dst1_len, src_len);
4598b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		memcpy(dst1, src, t);
4608b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		*dst1_len = t;
4618b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		src += t;
4628b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		src_len -= t;
4638b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		if (src_len) {
4648b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			t = min(*dst2_len, src_len);
4658b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			memcpy(dst2, src, t);
4668b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			*dst2_len = t;
4678b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		}
4688b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return 0;
4698b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4708b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	case CEPH_CRYPTO_AES:
4718b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return ceph_aes_decrypt2(secret->key, secret->len,
4728b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil					 dst1, dst1_len, dst2, dst2_len,
4738b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil					 src, src_len);
4748b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4758b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	default:
4768b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return -EINVAL;
4778b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
4788b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
4798b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4808b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weilint ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
4818b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		 const void *src, size_t src_len)
4828b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
4838b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	switch (secret->type) {
4848b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	case CEPH_CRYPTO_NONE:
4858b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		if (*dst_len < src_len)
4868b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			return -ERANGE;
4878b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		memcpy(dst, src, src_len);
4888b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		*dst_len = src_len;
4898b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return 0;
4908b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4918b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	case CEPH_CRYPTO_AES:
4928b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return ceph_aes_encrypt(secret->key, secret->len, dst,
4938b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil					dst_len, src, src_len);
4948b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
4958b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	default:
4968b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return -EINVAL;
4978b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
4988b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
4998b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
5008b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weilint ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
5018b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		  const void *src1, size_t src1_len,
5028b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		  const void *src2, size_t src2_len)
5038b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil{
5048b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	switch (secret->type) {
5058b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	case CEPH_CRYPTO_NONE:
5068b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		if (*dst_len < src1_len + src2_len)
5078b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil			return -ERANGE;
5088b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		memcpy(dst, src1, src1_len);
5098b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		memcpy(dst + src1_len, src2, src2_len);
5108b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		*dst_len = src1_len + src2_len;
5118b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return 0;
5128b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
5138b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	case CEPH_CRYPTO_AES:
5148b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len,
5158b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil					 src1, src1_len, src2, src2_len);
5168b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil
5178b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	default:
5188b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil		return -EINVAL;
5198b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil	}
5208b6e4f2d8b21c25225b1ce8d53a2e03b92cc8522Sage Weil}
5214b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
522efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howellsstatic int ceph_key_preparse(struct key_preparsed_payload *prep)
5234b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen{
5244b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	struct ceph_crypto_key *ckey;
525cf7f601c067994f371ba77721d1e45fce61a4569David Howells	size_t datalen = prep->datalen;
5264b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	int ret;
5274b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	void *p;
5284b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
5294b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	ret = -EINVAL;
530cf7f601c067994f371ba77721d1e45fce61a4569David Howells	if (datalen <= 0 || datalen > 32767 || !prep->data)
5314b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen		goto err;
5324b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
5334b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	ret = -ENOMEM;
5344b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
5354b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	if (!ckey)
5364b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen		goto err;
5374b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
5384b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	/* TODO ceph_crypto_key_decode should really take const input */
539cf7f601c067994f371ba77721d1e45fce61a4569David Howells	p = (void *)prep->data;
540cf7f601c067994f371ba77721d1e45fce61a4569David Howells	ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen);
5414b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	if (ret < 0)
5424b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen		goto err_ckey;
5434b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
544efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells	prep->payload[0] = ckey;
545efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells	prep->quotalen = datalen;
5464b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	return 0;
5474b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
5484b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanenerr_ckey:
5494b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	kfree(ckey);
5504b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanenerr:
5514b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	return ret;
5524b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen}
5534b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
554efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howellsstatic void ceph_key_free_preparse(struct key_preparsed_payload *prep)
555efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells{
556efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells	struct ceph_crypto_key *ckey = prep->payload[0];
557efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells	ceph_crypto_key_destroy(ckey);
558efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells	kfree(ckey);
559efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells}
560efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells
561efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howellsstatic void ceph_key_destroy(struct key *key)
562efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells{
5634b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	struct ceph_crypto_key *ckey = key->payload.data;
5644b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
5654b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	ceph_crypto_key_destroy(ckey);
566f0666b1ac875ff32fe290219b150ec62eebbe10eSylvain Munaut	kfree(ckey);
5674b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen}
5684b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
5694b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanenstruct key_type key_type_ceph = {
5704b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	.name		= "ceph",
571efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells	.preparse	= ceph_key_preparse,
572efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells	.free_preparse	= ceph_key_free_preparse,
573efa64c0978a1fb3de8bca6f931b9858c3e371f1fDavid Howells	.instantiate	= generic_key_instantiate,
5744b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	.destroy	= ceph_key_destroy,
5754b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen};
5764b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
5774b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanenint ceph_crypto_init(void) {
5784b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	return register_key_type(&key_type_ceph);
5794b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen}
5804b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen
5814b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanenvoid ceph_crypto_shutdown(void) {
5824b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen	unregister_key_type(&key_type_ceph);
5834b2a58abd1e17c0ee53c8dded879e015917cca67Tommi Virtanen}
584