Commit | Line | Data |
---|---|---|
8b6e4f2d | 1 | |
3d14c5d2 | 2 | #include <linux/ceph/ceph_debug.h> |
8b6e4f2d SW |
3 | |
4 | #include <linux/err.h> | |
5 | #include <linux/scatterlist.h> | |
5a0e3ad6 | 6 | #include <linux/slab.h> |
e59dd982 HX |
7 | #include <crypto/aes.h> |
8 | #include <crypto/skcipher.h> | |
4b2a58ab | 9 | #include <linux/key-type.h> |
8b6e4f2d | 10 | |
4b2a58ab | 11 | #include <keys/ceph-type.h> |
7c3bec0a | 12 | #include <keys/user-type.h> |
3d14c5d2 | 13 | #include <linux/ceph/decode.h> |
8b6e4f2d | 14 | #include "crypto.h" |
8b6e4f2d | 15 | |
8323c3aa TV |
16 | int ceph_crypto_key_clone(struct ceph_crypto_key *dst, |
17 | const struct ceph_crypto_key *src) | |
18 | { | |
19 | memcpy(dst, src, sizeof(struct ceph_crypto_key)); | |
18648256 | 20 | dst->key = kmemdup(src->key, src->len, GFP_NOFS); |
8323c3aa TV |
21 | if (!dst->key) |
22 | return -ENOMEM; | |
8323c3aa TV |
23 | return 0; |
24 | } | |
25 | ||
8b6e4f2d SW |
26 | int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end) |
27 | { | |
28 | if (*p + sizeof(u16) + sizeof(key->created) + | |
29 | sizeof(u16) + key->len > end) | |
30 | return -ERANGE; | |
31 | ceph_encode_16(p, key->type); | |
32 | ceph_encode_copy(p, &key->created, sizeof(key->created)); | |
33 | ceph_encode_16(p, key->len); | |
34 | ceph_encode_copy(p, key->key, key->len); | |
35 | return 0; | |
36 | } | |
37 | ||
38 | int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end) | |
39 | { | |
40 | ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad); | |
41 | key->type = ceph_decode_16(p); | |
42 | ceph_decode_copy(p, &key->created, sizeof(key->created)); | |
43 | key->len = ceph_decode_16(p); | |
44 | ceph_decode_need(p, end, key->len, bad); | |
45 | key->key = kmalloc(key->len, GFP_NOFS); | |
46 | if (!key->key) | |
47 | return -ENOMEM; | |
48 | ceph_decode_copy(p, key->key, key->len); | |
49 | return 0; | |
50 | ||
51 | bad: | |
52 | dout("failed to decode crypto key\n"); | |
53 | return -EINVAL; | |
54 | } | |
55 | ||
56 | int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey) | |
57 | { | |
58 | int inlen = strlen(inkey); | |
59 | int blen = inlen * 3 / 4; | |
60 | void *buf, *p; | |
61 | int ret; | |
62 | ||
63 | dout("crypto_key_unarmor %s\n", inkey); | |
64 | buf = kmalloc(blen, GFP_NOFS); | |
65 | if (!buf) | |
66 | return -ENOMEM; | |
67 | blen = ceph_unarmor(buf, inkey, inkey+inlen); | |
68 | if (blen < 0) { | |
69 | kfree(buf); | |
70 | return blen; | |
71 | } | |
72 | ||
73 | p = buf; | |
74 | ret = ceph_crypto_key_decode(key, &p, p + blen); | |
75 | kfree(buf); | |
76 | if (ret) | |
77 | return ret; | |
78 | dout("crypto_key_unarmor key %p type %d len %d\n", key, | |
79 | key->type, key->len); | |
80 | return 0; | |
81 | } | |
82 | ||
e59dd982 | 83 | static struct crypto_skcipher *ceph_crypto_alloc_cipher(void) |
8b6e4f2d | 84 | { |
e59dd982 | 85 | return crypto_alloc_skcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); |
8b6e4f2d SW |
86 | } |
87 | ||
cbbfe499 | 88 | static const u8 *aes_iv = (u8 *)CEPH_AES_IV; |
8b6e4f2d | 89 | |
aaef3170 ID |
90 | /* |
91 | * Should be used for buffers allocated with ceph_kvmalloc(). | |
92 | * Currently these are encrypt out-buffer (ceph_buffer) and decrypt | |
93 | * in-buffer (msg front). | |
94 | * | |
95 | * Dispose of @sgt with teardown_sgtable(). | |
96 | * | |
97 | * @prealloc_sg is to avoid memory allocation inside sg_alloc_table() | |
98 | * in cases where a single sg is sufficient. No attempt to reduce the | |
99 | * number of sgs by squeezing physically contiguous pages together is | |
100 | * made though, for simplicity. | |
101 | */ | |
102 | static int setup_sgtable(struct sg_table *sgt, struct scatterlist *prealloc_sg, | |
103 | const void *buf, unsigned int buf_len) | |
104 | { | |
105 | struct scatterlist *sg; | |
106 | const bool is_vmalloc = is_vmalloc_addr(buf); | |
107 | unsigned int off = offset_in_page(buf); | |
108 | unsigned int chunk_cnt = 1; | |
109 | unsigned int chunk_len = PAGE_ALIGN(off + buf_len); | |
110 | int i; | |
111 | int ret; | |
112 | ||
113 | if (buf_len == 0) { | |
114 | memset(sgt, 0, sizeof(*sgt)); | |
115 | return -EINVAL; | |
116 | } | |
117 | ||
118 | if (is_vmalloc) { | |
119 | chunk_cnt = chunk_len >> PAGE_SHIFT; | |
120 | chunk_len = PAGE_SIZE; | |
121 | } | |
122 | ||
123 | if (chunk_cnt > 1) { | |
124 | ret = sg_alloc_table(sgt, chunk_cnt, GFP_NOFS); | |
125 | if (ret) | |
126 | return ret; | |
127 | } else { | |
128 | WARN_ON(chunk_cnt != 1); | |
129 | sg_init_table(prealloc_sg, 1); | |
130 | sgt->sgl = prealloc_sg; | |
131 | sgt->nents = sgt->orig_nents = 1; | |
132 | } | |
133 | ||
134 | for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) { | |
135 | struct page *page; | |
136 | unsigned int len = min(chunk_len - off, buf_len); | |
137 | ||
138 | if (is_vmalloc) | |
139 | page = vmalloc_to_page(buf); | |
140 | else | |
141 | page = virt_to_page(buf); | |
142 | ||
143 | sg_set_page(sg, page, len, off); | |
144 | ||
145 | off = 0; | |
146 | buf += len; | |
147 | buf_len -= len; | |
148 | } | |
149 | WARN_ON(buf_len != 0); | |
150 | ||
151 | return 0; | |
152 | } | |
153 | ||
154 | static void teardown_sgtable(struct sg_table *sgt) | |
155 | { | |
156 | if (sgt->orig_nents > 1) | |
157 | sg_free_table(sgt); | |
158 | } | |
159 | ||
cd84db6e YS |
160 | static int ceph_aes_encrypt(const void *key, int key_len, |
161 | void *dst, size_t *dst_len, | |
162 | const void *src, size_t src_len) | |
8b6e4f2d | 163 | { |
aaef3170 ID |
164 | struct scatterlist sg_in[2], prealloc_sg; |
165 | struct sg_table sg_out; | |
e59dd982 HX |
166 | struct crypto_skcipher *tfm = ceph_crypto_alloc_cipher(); |
167 | SKCIPHER_REQUEST_ON_STACK(req, tfm); | |
8b6e4f2d | 168 | int ret; |
e59dd982 HX |
169 | int ivsize = AES_BLOCK_SIZE; |
170 | char iv[ivsize]; | |
8b6e4f2d SW |
171 | size_t zero_padding = (0x10 - (src_len & 0x0f)); |
172 | char pad[16]; | |
173 | ||
174 | if (IS_ERR(tfm)) | |
175 | return PTR_ERR(tfm); | |
176 | ||
177 | memset(pad, zero_padding, zero_padding); | |
178 | ||
179 | *dst_len = src_len + zero_padding; | |
180 | ||
8b6e4f2d SW |
181 | sg_init_table(sg_in, 2); |
182 | sg_set_buf(&sg_in[0], src, src_len); | |
183 | sg_set_buf(&sg_in[1], pad, zero_padding); | |
aaef3170 ID |
184 | ret = setup_sgtable(&sg_out, &prealloc_sg, dst, *dst_len); |
185 | if (ret) | |
186 | goto out_tfm; | |
187 | ||
e59dd982 | 188 | crypto_skcipher_setkey((void *)tfm, key, key_len); |
8b6e4f2d | 189 | memcpy(iv, aes_iv, ivsize); |
aaef3170 | 190 | |
e59dd982 HX |
191 | skcipher_request_set_tfm(req, tfm); |
192 | skcipher_request_set_callback(req, 0, NULL, NULL); | |
193 | skcipher_request_set_crypt(req, sg_in, sg_out.sgl, | |
194 | src_len + zero_padding, iv); | |
195 | ||
8b6e4f2d SW |
196 | /* |
197 | print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1, | |
198 | key, key_len, 1); | |
199 | print_hex_dump(KERN_ERR, "enc src: ", DUMP_PREFIX_NONE, 16, 1, | |
200 | src, src_len, 1); | |
201 | print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1, | |
202 | pad, zero_padding, 1); | |
203 | */ | |
e59dd982 HX |
204 | ret = crypto_skcipher_encrypt(req); |
205 | skcipher_request_zero(req); | |
aaef3170 | 206 | if (ret < 0) { |
8b6e4f2d | 207 | pr_err("ceph_aes_crypt failed %d\n", ret); |
aaef3170 ID |
208 | goto out_sg; |
209 | } | |
8b6e4f2d SW |
210 | /* |
211 | print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1, | |
212 | dst, *dst_len, 1); | |
213 | */ | |
aaef3170 ID |
214 | |
215 | out_sg: | |
216 | teardown_sgtable(&sg_out); | |
217 | out_tfm: | |
e59dd982 | 218 | crypto_free_skcipher(tfm); |
aaef3170 | 219 | return ret; |
8b6e4f2d SW |
220 | } |
221 | ||
cd84db6e YS |
222 | static int ceph_aes_encrypt2(const void *key, int key_len, void *dst, |
223 | size_t *dst_len, | |
224 | const void *src1, size_t src1_len, | |
225 | const void *src2, size_t src2_len) | |
8b6e4f2d | 226 | { |
aaef3170 ID |
227 | struct scatterlist sg_in[3], prealloc_sg; |
228 | struct sg_table sg_out; | |
e59dd982 HX |
229 | struct crypto_skcipher *tfm = ceph_crypto_alloc_cipher(); |
230 | SKCIPHER_REQUEST_ON_STACK(req, tfm); | |
8b6e4f2d | 231 | int ret; |
e59dd982 HX |
232 | int ivsize = AES_BLOCK_SIZE; |
233 | char iv[ivsize]; | |
8b6e4f2d SW |
234 | size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f)); |
235 | char pad[16]; | |
236 | ||
237 | if (IS_ERR(tfm)) | |
238 | return PTR_ERR(tfm); | |
239 | ||
240 | memset(pad, zero_padding, zero_padding); | |
241 | ||
242 | *dst_len = src1_len + src2_len + zero_padding; | |
243 | ||
8b6e4f2d SW |
244 | sg_init_table(sg_in, 3); |
245 | sg_set_buf(&sg_in[0], src1, src1_len); | |
246 | sg_set_buf(&sg_in[1], src2, src2_len); | |
247 | sg_set_buf(&sg_in[2], pad, zero_padding); | |
aaef3170 ID |
248 | ret = setup_sgtable(&sg_out, &prealloc_sg, dst, *dst_len); |
249 | if (ret) | |
250 | goto out_tfm; | |
251 | ||
e59dd982 | 252 | crypto_skcipher_setkey((void *)tfm, key, key_len); |
8b6e4f2d | 253 | memcpy(iv, aes_iv, ivsize); |
aaef3170 | 254 | |
e59dd982 HX |
255 | skcipher_request_set_tfm(req, tfm); |
256 | skcipher_request_set_callback(req, 0, NULL, NULL); | |
257 | skcipher_request_set_crypt(req, sg_in, sg_out.sgl, | |
258 | src1_len + src2_len + zero_padding, iv); | |
259 | ||
8b6e4f2d SW |
260 | /* |
261 | print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1, | |
262 | key, key_len, 1); | |
263 | print_hex_dump(KERN_ERR, "enc src1: ", DUMP_PREFIX_NONE, 16, 1, | |
264 | src1, src1_len, 1); | |
265 | print_hex_dump(KERN_ERR, "enc src2: ", DUMP_PREFIX_NONE, 16, 1, | |
266 | src2, src2_len, 1); | |
267 | print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1, | |
268 | pad, zero_padding, 1); | |
269 | */ | |
e59dd982 HX |
270 | ret = crypto_skcipher_encrypt(req); |
271 | skcipher_request_zero(req); | |
aaef3170 | 272 | if (ret < 0) { |
8b6e4f2d | 273 | pr_err("ceph_aes_crypt2 failed %d\n", ret); |
aaef3170 ID |
274 | goto out_sg; |
275 | } | |
8b6e4f2d SW |
276 | /* |
277 | print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1, | |
278 | dst, *dst_len, 1); | |
279 | */ | |
aaef3170 ID |
280 | |
281 | out_sg: | |
282 | teardown_sgtable(&sg_out); | |
283 | out_tfm: | |
e59dd982 | 284 | crypto_free_skcipher(tfm); |
aaef3170 | 285 | return ret; |
8b6e4f2d SW |
286 | } |
287 | ||
cd84db6e YS |
288 | static int ceph_aes_decrypt(const void *key, int key_len, |
289 | void *dst, size_t *dst_len, | |
290 | const void *src, size_t src_len) | |
8b6e4f2d | 291 | { |
aaef3170 ID |
292 | struct sg_table sg_in; |
293 | struct scatterlist sg_out[2], prealloc_sg; | |
e59dd982 HX |
294 | struct crypto_skcipher *tfm = ceph_crypto_alloc_cipher(); |
295 | SKCIPHER_REQUEST_ON_STACK(req, tfm); | |
8b6e4f2d | 296 | char pad[16]; |
e59dd982 HX |
297 | int ivsize = AES_BLOCK_SIZE; |
298 | char iv[16]; | |
8b6e4f2d SW |
299 | int ret; |
300 | int last_byte; | |
301 | ||
302 | if (IS_ERR(tfm)) | |
303 | return PTR_ERR(tfm); | |
304 | ||
8b6e4f2d | 305 | sg_init_table(sg_out, 2); |
8b6e4f2d SW |
306 | sg_set_buf(&sg_out[0], dst, *dst_len); |
307 | sg_set_buf(&sg_out[1], pad, sizeof(pad)); | |
aaef3170 ID |
308 | ret = setup_sgtable(&sg_in, &prealloc_sg, src, src_len); |
309 | if (ret) | |
310 | goto out_tfm; | |
8b6e4f2d | 311 | |
e59dd982 | 312 | crypto_skcipher_setkey((void *)tfm, key, key_len); |
8b6e4f2d SW |
313 | memcpy(iv, aes_iv, ivsize); |
314 | ||
e59dd982 HX |
315 | skcipher_request_set_tfm(req, tfm); |
316 | skcipher_request_set_callback(req, 0, NULL, NULL); | |
317 | skcipher_request_set_crypt(req, sg_in.sgl, sg_out, | |
318 | src_len, iv); | |
319 | ||
8b6e4f2d SW |
320 | /* |
321 | print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1, | |
322 | key, key_len, 1); | |
323 | print_hex_dump(KERN_ERR, "dec in: ", DUMP_PREFIX_NONE, 16, 1, | |
324 | src, src_len, 1); | |
325 | */ | |
e59dd982 HX |
326 | ret = crypto_skcipher_decrypt(req); |
327 | skcipher_request_zero(req); | |
8b6e4f2d SW |
328 | if (ret < 0) { |
329 | pr_err("ceph_aes_decrypt failed %d\n", ret); | |
aaef3170 | 330 | goto out_sg; |
8b6e4f2d SW |
331 | } |
332 | ||
333 | if (src_len <= *dst_len) | |
334 | last_byte = ((char *)dst)[src_len - 1]; | |
335 | else | |
336 | last_byte = pad[src_len - *dst_len - 1]; | |
337 | if (last_byte <= 16 && src_len >= last_byte) { | |
338 | *dst_len = src_len - last_byte; | |
339 | } else { | |
340 | pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n", | |
341 | last_byte, (int)src_len); | |
342 | return -EPERM; /* bad padding */ | |
343 | } | |
344 | /* | |
345 | print_hex_dump(KERN_ERR, "dec out: ", DUMP_PREFIX_NONE, 16, 1, | |
346 | dst, *dst_len, 1); | |
347 | */ | |
aaef3170 ID |
348 | |
349 | out_sg: | |
350 | teardown_sgtable(&sg_in); | |
351 | out_tfm: | |
e59dd982 | 352 | crypto_free_skcipher(tfm); |
aaef3170 | 353 | return ret; |
8b6e4f2d SW |
354 | } |
355 | ||
cd84db6e YS |
356 | static int ceph_aes_decrypt2(const void *key, int key_len, |
357 | void *dst1, size_t *dst1_len, | |
358 | void *dst2, size_t *dst2_len, | |
359 | const void *src, size_t src_len) | |
8b6e4f2d | 360 | { |
aaef3170 ID |
361 | struct sg_table sg_in; |
362 | struct scatterlist sg_out[3], prealloc_sg; | |
e59dd982 HX |
363 | struct crypto_skcipher *tfm = ceph_crypto_alloc_cipher(); |
364 | SKCIPHER_REQUEST_ON_STACK(req, tfm); | |
8b6e4f2d | 365 | char pad[16]; |
e59dd982 HX |
366 | int ivsize = AES_BLOCK_SIZE; |
367 | char iv[ivsize]; | |
8b6e4f2d SW |
368 | int ret; |
369 | int last_byte; | |
370 | ||
371 | if (IS_ERR(tfm)) | |
372 | return PTR_ERR(tfm); | |
373 | ||
8b6e4f2d SW |
374 | sg_init_table(sg_out, 3); |
375 | sg_set_buf(&sg_out[0], dst1, *dst1_len); | |
376 | sg_set_buf(&sg_out[1], dst2, *dst2_len); | |
377 | sg_set_buf(&sg_out[2], pad, sizeof(pad)); | |
aaef3170 ID |
378 | ret = setup_sgtable(&sg_in, &prealloc_sg, src, src_len); |
379 | if (ret) | |
380 | goto out_tfm; | |
8b6e4f2d | 381 | |
e59dd982 | 382 | crypto_skcipher_setkey((void *)tfm, key, key_len); |
8b6e4f2d SW |
383 | memcpy(iv, aes_iv, ivsize); |
384 | ||
e59dd982 HX |
385 | skcipher_request_set_tfm(req, tfm); |
386 | skcipher_request_set_callback(req, 0, NULL, NULL); | |
387 | skcipher_request_set_crypt(req, sg_in.sgl, sg_out, | |
388 | src_len, iv); | |
389 | ||
8b6e4f2d SW |
390 | /* |
391 | print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1, | |
392 | key, key_len, 1); | |
393 | print_hex_dump(KERN_ERR, "dec in: ", DUMP_PREFIX_NONE, 16, 1, | |
394 | src, src_len, 1); | |
395 | */ | |
e59dd982 HX |
396 | ret = crypto_skcipher_decrypt(req); |
397 | skcipher_request_zero(req); | |
8b6e4f2d SW |
398 | if (ret < 0) { |
399 | pr_err("ceph_aes_decrypt failed %d\n", ret); | |
aaef3170 | 400 | goto out_sg; |
8b6e4f2d SW |
401 | } |
402 | ||
403 | if (src_len <= *dst1_len) | |
404 | last_byte = ((char *)dst1)[src_len - 1]; | |
405 | else if (src_len <= *dst1_len + *dst2_len) | |
406 | last_byte = ((char *)dst2)[src_len - *dst1_len - 1]; | |
407 | else | |
408 | last_byte = pad[src_len - *dst1_len - *dst2_len - 1]; | |
409 | if (last_byte <= 16 && src_len >= last_byte) { | |
410 | src_len -= last_byte; | |
411 | } else { | |
412 | pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n", | |
413 | last_byte, (int)src_len); | |
414 | return -EPERM; /* bad padding */ | |
415 | } | |
416 | ||
417 | if (src_len < *dst1_len) { | |
418 | *dst1_len = src_len; | |
419 | *dst2_len = 0; | |
420 | } else { | |
421 | *dst2_len = src_len - *dst1_len; | |
422 | } | |
423 | /* | |
424 | print_hex_dump(KERN_ERR, "dec out1: ", DUMP_PREFIX_NONE, 16, 1, | |
425 | dst1, *dst1_len, 1); | |
426 | print_hex_dump(KERN_ERR, "dec out2: ", DUMP_PREFIX_NONE, 16, 1, | |
427 | dst2, *dst2_len, 1); | |
428 | */ | |
429 | ||
aaef3170 ID |
430 | out_sg: |
431 | teardown_sgtable(&sg_in); | |
432 | out_tfm: | |
e59dd982 | 433 | crypto_free_skcipher(tfm); |
aaef3170 | 434 | return ret; |
8b6e4f2d SW |
435 | } |
436 | ||
437 | ||
438 | int ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |
439 | const void *src, size_t src_len) | |
440 | { | |
441 | switch (secret->type) { | |
442 | case CEPH_CRYPTO_NONE: | |
443 | if (*dst_len < src_len) | |
444 | return -ERANGE; | |
445 | memcpy(dst, src, src_len); | |
446 | *dst_len = src_len; | |
447 | return 0; | |
448 | ||
449 | case CEPH_CRYPTO_AES: | |
450 | return ceph_aes_decrypt(secret->key, secret->len, dst, | |
451 | dst_len, src, src_len); | |
452 | ||
453 | default: | |
454 | return -EINVAL; | |
455 | } | |
456 | } | |
457 | ||
458 | int ceph_decrypt2(struct ceph_crypto_key *secret, | |
459 | void *dst1, size_t *dst1_len, | |
460 | void *dst2, size_t *dst2_len, | |
461 | const void *src, size_t src_len) | |
462 | { | |
463 | size_t t; | |
464 | ||
465 | switch (secret->type) { | |
466 | case CEPH_CRYPTO_NONE: | |
467 | if (*dst1_len + *dst2_len < src_len) | |
468 | return -ERANGE; | |
469 | t = min(*dst1_len, src_len); | |
470 | memcpy(dst1, src, t); | |
471 | *dst1_len = t; | |
472 | src += t; | |
473 | src_len -= t; | |
474 | if (src_len) { | |
475 | t = min(*dst2_len, src_len); | |
476 | memcpy(dst2, src, t); | |
477 | *dst2_len = t; | |
478 | } | |
479 | return 0; | |
480 | ||
481 | case CEPH_CRYPTO_AES: | |
482 | return ceph_aes_decrypt2(secret->key, secret->len, | |
483 | dst1, dst1_len, dst2, dst2_len, | |
484 | src, src_len); | |
485 | ||
486 | default: | |
487 | return -EINVAL; | |
488 | } | |
489 | } | |
490 | ||
491 | int ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |
492 | const void *src, size_t src_len) | |
493 | { | |
494 | switch (secret->type) { | |
495 | case CEPH_CRYPTO_NONE: | |
496 | if (*dst_len < src_len) | |
497 | return -ERANGE; | |
498 | memcpy(dst, src, src_len); | |
499 | *dst_len = src_len; | |
500 | return 0; | |
501 | ||
502 | case CEPH_CRYPTO_AES: | |
503 | return ceph_aes_encrypt(secret->key, secret->len, dst, | |
504 | dst_len, src, src_len); | |
505 | ||
506 | default: | |
507 | return -EINVAL; | |
508 | } | |
509 | } | |
510 | ||
511 | int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |
512 | const void *src1, size_t src1_len, | |
513 | const void *src2, size_t src2_len) | |
514 | { | |
515 | switch (secret->type) { | |
516 | case CEPH_CRYPTO_NONE: | |
517 | if (*dst_len < src1_len + src2_len) | |
518 | return -ERANGE; | |
519 | memcpy(dst, src1, src1_len); | |
520 | memcpy(dst + src1_len, src2, src2_len); | |
521 | *dst_len = src1_len + src2_len; | |
522 | return 0; | |
523 | ||
524 | case CEPH_CRYPTO_AES: | |
525 | return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len, | |
526 | src1, src1_len, src2, src2_len); | |
527 | ||
528 | default: | |
529 | return -EINVAL; | |
530 | } | |
531 | } | |
4b2a58ab | 532 | |
efa64c09 | 533 | static int ceph_key_preparse(struct key_preparsed_payload *prep) |
4b2a58ab TV |
534 | { |
535 | struct ceph_crypto_key *ckey; | |
cf7f601c | 536 | size_t datalen = prep->datalen; |
4b2a58ab TV |
537 | int ret; |
538 | void *p; | |
539 | ||
540 | ret = -EINVAL; | |
cf7f601c | 541 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
4b2a58ab TV |
542 | goto err; |
543 | ||
4b2a58ab TV |
544 | ret = -ENOMEM; |
545 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); | |
546 | if (!ckey) | |
547 | goto err; | |
548 | ||
549 | /* TODO ceph_crypto_key_decode should really take const input */ | |
cf7f601c DH |
550 | p = (void *)prep->data; |
551 | ret = ceph_crypto_key_decode(ckey, &p, (char*)prep->data+datalen); | |
4b2a58ab TV |
552 | if (ret < 0) |
553 | goto err_ckey; | |
554 | ||
146aa8b1 | 555 | prep->payload.data[0] = ckey; |
efa64c09 | 556 | prep->quotalen = datalen; |
4b2a58ab TV |
557 | return 0; |
558 | ||
559 | err_ckey: | |
560 | kfree(ckey); | |
561 | err: | |
562 | return ret; | |
563 | } | |
564 | ||
efa64c09 DH |
565 | static void ceph_key_free_preparse(struct key_preparsed_payload *prep) |
566 | { | |
146aa8b1 | 567 | struct ceph_crypto_key *ckey = prep->payload.data[0]; |
efa64c09 DH |
568 | ceph_crypto_key_destroy(ckey); |
569 | kfree(ckey); | |
570 | } | |
571 | ||
efa64c09 DH |
572 | static void ceph_key_destroy(struct key *key) |
573 | { | |
146aa8b1 | 574 | struct ceph_crypto_key *ckey = key->payload.data[0]; |
4b2a58ab TV |
575 | |
576 | ceph_crypto_key_destroy(ckey); | |
f0666b1a | 577 | kfree(ckey); |
4b2a58ab TV |
578 | } |
579 | ||
580 | struct key_type key_type_ceph = { | |
581 | .name = "ceph", | |
efa64c09 DH |
582 | .preparse = ceph_key_preparse, |
583 | .free_preparse = ceph_key_free_preparse, | |
584 | .instantiate = generic_key_instantiate, | |
4b2a58ab TV |
585 | .destroy = ceph_key_destroy, |
586 | }; | |
587 | ||
588 | int ceph_crypto_init(void) { | |
589 | return register_key_type(&key_type_ceph); | |
590 | } | |
591 | ||
592 | void ceph_crypto_shutdown(void) { | |
593 | unregister_key_type(&key_type_ceph); | |
594 | } |