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