]>
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> |
3d14c5d2 | 11 | #include <linux/ceph/decode.h> |
8b6e4f2d | 12 | #include "crypto.h" |
8b6e4f2d | 13 | |
8323c3aa TV |
14 | int ceph_crypto_key_clone(struct ceph_crypto_key *dst, |
15 | const struct ceph_crypto_key *src) | |
16 | { | |
17 | memcpy(dst, src, sizeof(struct ceph_crypto_key)); | |
18648256 | 18 | dst->key = kmemdup(src->key, src->len, GFP_NOFS); |
8323c3aa TV |
19 | if (!dst->key) |
20 | return -ENOMEM; | |
8323c3aa TV |
21 | return 0; |
22 | } | |
23 | ||
8b6e4f2d SW |
24 | int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end) |
25 | { | |
26 | if (*p + sizeof(u16) + sizeof(key->created) + | |
27 | sizeof(u16) + key->len > end) | |
28 | return -ERANGE; | |
29 | ceph_encode_16(p, key->type); | |
30 | ceph_encode_copy(p, &key->created, sizeof(key->created)); | |
31 | ceph_encode_16(p, key->len); | |
32 | ceph_encode_copy(p, key->key, key->len); | |
33 | return 0; | |
34 | } | |
35 | ||
36 | int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end) | |
37 | { | |
38 | ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad); | |
39 | key->type = ceph_decode_16(p); | |
40 | ceph_decode_copy(p, &key->created, sizeof(key->created)); | |
41 | key->len = ceph_decode_16(p); | |
42 | ceph_decode_need(p, end, key->len, bad); | |
43 | key->key = kmalloc(key->len, GFP_NOFS); | |
44 | if (!key->key) | |
45 | return -ENOMEM; | |
46 | ceph_decode_copy(p, key->key, key->len); | |
47 | return 0; | |
48 | ||
49 | bad: | |
50 | dout("failed to decode crypto key\n"); | |
51 | return -EINVAL; | |
52 | } | |
53 | ||
54 | int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey) | |
55 | { | |
56 | int inlen = strlen(inkey); | |
57 | int blen = inlen * 3 / 4; | |
58 | void *buf, *p; | |
59 | int ret; | |
60 | ||
61 | dout("crypto_key_unarmor %s\n", inkey); | |
62 | buf = kmalloc(blen, GFP_NOFS); | |
63 | if (!buf) | |
64 | return -ENOMEM; | |
65 | blen = ceph_unarmor(buf, inkey, inkey+inlen); | |
66 | if (blen < 0) { | |
67 | kfree(buf); | |
68 | return blen; | |
69 | } | |
70 | ||
71 | p = buf; | |
72 | ret = ceph_crypto_key_decode(key, &p, p + blen); | |
73 | kfree(buf); | |
74 | if (ret) | |
75 | return ret; | |
76 | dout("crypto_key_unarmor key %p type %d len %d\n", key, | |
77 | key->type, key->len); | |
78 | return 0; | |
79 | } | |
80 | ||
81 | ||
82 | ||
83 | #define AES_KEY_SIZE 16 | |
84 | ||
85 | static struct crypto_blkcipher *ceph_crypto_alloc_cipher(void) | |
86 | { | |
87 | return crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); | |
88 | } | |
89 | ||
cbbfe499 | 90 | static const u8 *aes_iv = (u8 *)CEPH_AES_IV; |
8b6e4f2d | 91 | |
cd84db6e YS |
92 | static int ceph_aes_encrypt(const void *key, int key_len, |
93 | void *dst, size_t *dst_len, | |
94 | const void *src, size_t src_len) | |
8b6e4f2d SW |
95 | { |
96 | struct scatterlist sg_in[2], sg_out[1]; | |
97 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); | |
98 | struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 }; | |
99 | int ret; | |
100 | void *iv; | |
101 | int ivsize; | |
102 | size_t zero_padding = (0x10 - (src_len & 0x0f)); | |
103 | char pad[16]; | |
104 | ||
105 | if (IS_ERR(tfm)) | |
106 | return PTR_ERR(tfm); | |
107 | ||
108 | memset(pad, zero_padding, zero_padding); | |
109 | ||
110 | *dst_len = src_len + zero_padding; | |
111 | ||
112 | crypto_blkcipher_setkey((void *)tfm, key, key_len); | |
113 | sg_init_table(sg_in, 2); | |
114 | sg_set_buf(&sg_in[0], src, src_len); | |
115 | sg_set_buf(&sg_in[1], pad, zero_padding); | |
116 | sg_init_table(sg_out, 1); | |
117 | sg_set_buf(sg_out, dst, *dst_len); | |
118 | iv = crypto_blkcipher_crt(tfm)->iv; | |
119 | ivsize = crypto_blkcipher_ivsize(tfm); | |
120 | ||
121 | memcpy(iv, aes_iv, ivsize); | |
122 | /* | |
123 | print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1, | |
124 | key, key_len, 1); | |
125 | print_hex_dump(KERN_ERR, "enc src: ", DUMP_PREFIX_NONE, 16, 1, | |
126 | src, src_len, 1); | |
127 | print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1, | |
128 | pad, zero_padding, 1); | |
129 | */ | |
130 | ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, | |
131 | src_len + zero_padding); | |
132 | crypto_free_blkcipher(tfm); | |
133 | if (ret < 0) | |
134 | pr_err("ceph_aes_crypt failed %d\n", ret); | |
135 | /* | |
136 | print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1, | |
137 | dst, *dst_len, 1); | |
138 | */ | |
139 | return 0; | |
140 | } | |
141 | ||
cd84db6e YS |
142 | static int ceph_aes_encrypt2(const void *key, int key_len, void *dst, |
143 | size_t *dst_len, | |
144 | const void *src1, size_t src1_len, | |
145 | const void *src2, size_t src2_len) | |
8b6e4f2d SW |
146 | { |
147 | struct scatterlist sg_in[3], sg_out[1]; | |
148 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); | |
149 | struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 }; | |
150 | int ret; | |
151 | void *iv; | |
152 | int ivsize; | |
153 | size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f)); | |
154 | char pad[16]; | |
155 | ||
156 | if (IS_ERR(tfm)) | |
157 | return PTR_ERR(tfm); | |
158 | ||
159 | memset(pad, zero_padding, zero_padding); | |
160 | ||
161 | *dst_len = src1_len + src2_len + zero_padding; | |
162 | ||
163 | crypto_blkcipher_setkey((void *)tfm, key, key_len); | |
164 | sg_init_table(sg_in, 3); | |
165 | sg_set_buf(&sg_in[0], src1, src1_len); | |
166 | sg_set_buf(&sg_in[1], src2, src2_len); | |
167 | sg_set_buf(&sg_in[2], pad, zero_padding); | |
168 | sg_init_table(sg_out, 1); | |
169 | sg_set_buf(sg_out, dst, *dst_len); | |
170 | iv = crypto_blkcipher_crt(tfm)->iv; | |
171 | ivsize = crypto_blkcipher_ivsize(tfm); | |
172 | ||
173 | memcpy(iv, aes_iv, ivsize); | |
174 | /* | |
175 | print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1, | |
176 | key, key_len, 1); | |
177 | print_hex_dump(KERN_ERR, "enc src1: ", DUMP_PREFIX_NONE, 16, 1, | |
178 | src1, src1_len, 1); | |
179 | print_hex_dump(KERN_ERR, "enc src2: ", DUMP_PREFIX_NONE, 16, 1, | |
180 | src2, src2_len, 1); | |
181 | print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1, | |
182 | pad, zero_padding, 1); | |
183 | */ | |
184 | ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, | |
185 | src1_len + src2_len + zero_padding); | |
186 | crypto_free_blkcipher(tfm); | |
187 | if (ret < 0) | |
188 | pr_err("ceph_aes_crypt2 failed %d\n", ret); | |
189 | /* | |
190 | print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1, | |
191 | dst, *dst_len, 1); | |
192 | */ | |
193 | return 0; | |
194 | } | |
195 | ||
cd84db6e YS |
196 | static int ceph_aes_decrypt(const void *key, int key_len, |
197 | void *dst, size_t *dst_len, | |
198 | const void *src, size_t src_len) | |
8b6e4f2d SW |
199 | { |
200 | struct scatterlist sg_in[1], sg_out[2]; | |
201 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); | |
202 | struct blkcipher_desc desc = { .tfm = tfm }; | |
203 | char pad[16]; | |
204 | void *iv; | |
205 | int ivsize; | |
206 | int ret; | |
207 | int last_byte; | |
208 | ||
209 | if (IS_ERR(tfm)) | |
210 | return PTR_ERR(tfm); | |
211 | ||
212 | crypto_blkcipher_setkey((void *)tfm, key, key_len); | |
213 | sg_init_table(sg_in, 1); | |
214 | sg_init_table(sg_out, 2); | |
215 | sg_set_buf(sg_in, src, src_len); | |
216 | sg_set_buf(&sg_out[0], dst, *dst_len); | |
217 | sg_set_buf(&sg_out[1], pad, sizeof(pad)); | |
218 | ||
219 | iv = crypto_blkcipher_crt(tfm)->iv; | |
220 | ivsize = crypto_blkcipher_ivsize(tfm); | |
221 | ||
222 | memcpy(iv, aes_iv, ivsize); | |
223 | ||
224 | /* | |
225 | print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1, | |
226 | key, key_len, 1); | |
227 | print_hex_dump(KERN_ERR, "dec in: ", DUMP_PREFIX_NONE, 16, 1, | |
228 | src, src_len, 1); | |
229 | */ | |
230 | ||
231 | ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len); | |
232 | crypto_free_blkcipher(tfm); | |
233 | if (ret < 0) { | |
234 | pr_err("ceph_aes_decrypt failed %d\n", ret); | |
235 | return ret; | |
236 | } | |
237 | ||
238 | if (src_len <= *dst_len) | |
239 | last_byte = ((char *)dst)[src_len - 1]; | |
240 | else | |
241 | last_byte = pad[src_len - *dst_len - 1]; | |
242 | if (last_byte <= 16 && src_len >= last_byte) { | |
243 | *dst_len = src_len - last_byte; | |
244 | } else { | |
245 | pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n", | |
246 | last_byte, (int)src_len); | |
247 | return -EPERM; /* bad padding */ | |
248 | } | |
249 | /* | |
250 | print_hex_dump(KERN_ERR, "dec out: ", DUMP_PREFIX_NONE, 16, 1, | |
251 | dst, *dst_len, 1); | |
252 | */ | |
253 | return 0; | |
254 | } | |
255 | ||
cd84db6e YS |
256 | static int ceph_aes_decrypt2(const void *key, int key_len, |
257 | void *dst1, size_t *dst1_len, | |
258 | void *dst2, size_t *dst2_len, | |
259 | const void *src, size_t src_len) | |
8b6e4f2d SW |
260 | { |
261 | struct scatterlist sg_in[1], sg_out[3]; | |
262 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); | |
263 | struct blkcipher_desc desc = { .tfm = tfm }; | |
264 | char pad[16]; | |
265 | void *iv; | |
266 | int ivsize; | |
267 | int ret; | |
268 | int last_byte; | |
269 | ||
270 | if (IS_ERR(tfm)) | |
271 | return PTR_ERR(tfm); | |
272 | ||
273 | sg_init_table(sg_in, 1); | |
274 | sg_set_buf(sg_in, src, src_len); | |
275 | sg_init_table(sg_out, 3); | |
276 | sg_set_buf(&sg_out[0], dst1, *dst1_len); | |
277 | sg_set_buf(&sg_out[1], dst2, *dst2_len); | |
278 | sg_set_buf(&sg_out[2], pad, sizeof(pad)); | |
279 | ||
280 | crypto_blkcipher_setkey((void *)tfm, key, key_len); | |
281 | iv = crypto_blkcipher_crt(tfm)->iv; | |
282 | ivsize = crypto_blkcipher_ivsize(tfm); | |
283 | ||
284 | memcpy(iv, aes_iv, ivsize); | |
285 | ||
286 | /* | |
287 | print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1, | |
288 | key, key_len, 1); | |
289 | print_hex_dump(KERN_ERR, "dec in: ", DUMP_PREFIX_NONE, 16, 1, | |
290 | src, src_len, 1); | |
291 | */ | |
292 | ||
293 | ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len); | |
294 | crypto_free_blkcipher(tfm); | |
295 | if (ret < 0) { | |
296 | pr_err("ceph_aes_decrypt failed %d\n", ret); | |
297 | return ret; | |
298 | } | |
299 | ||
300 | if (src_len <= *dst1_len) | |
301 | last_byte = ((char *)dst1)[src_len - 1]; | |
302 | else if (src_len <= *dst1_len + *dst2_len) | |
303 | last_byte = ((char *)dst2)[src_len - *dst1_len - 1]; | |
304 | else | |
305 | last_byte = pad[src_len - *dst1_len - *dst2_len - 1]; | |
306 | if (last_byte <= 16 && src_len >= last_byte) { | |
307 | src_len -= last_byte; | |
308 | } else { | |
309 | pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n", | |
310 | last_byte, (int)src_len); | |
311 | return -EPERM; /* bad padding */ | |
312 | } | |
313 | ||
314 | if (src_len < *dst1_len) { | |
315 | *dst1_len = src_len; | |
316 | *dst2_len = 0; | |
317 | } else { | |
318 | *dst2_len = src_len - *dst1_len; | |
319 | } | |
320 | /* | |
321 | print_hex_dump(KERN_ERR, "dec out1: ", DUMP_PREFIX_NONE, 16, 1, | |
322 | dst1, *dst1_len, 1); | |
323 | print_hex_dump(KERN_ERR, "dec out2: ", DUMP_PREFIX_NONE, 16, 1, | |
324 | dst2, *dst2_len, 1); | |
325 | */ | |
326 | ||
327 | return 0; | |
328 | } | |
329 | ||
330 | ||
331 | int ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |
332 | const void *src, size_t src_len) | |
333 | { | |
334 | switch (secret->type) { | |
335 | case CEPH_CRYPTO_NONE: | |
336 | if (*dst_len < src_len) | |
337 | return -ERANGE; | |
338 | memcpy(dst, src, src_len); | |
339 | *dst_len = src_len; | |
340 | return 0; | |
341 | ||
342 | case CEPH_CRYPTO_AES: | |
343 | return ceph_aes_decrypt(secret->key, secret->len, dst, | |
344 | dst_len, src, src_len); | |
345 | ||
346 | default: | |
347 | return -EINVAL; | |
348 | } | |
349 | } | |
350 | ||
351 | int ceph_decrypt2(struct ceph_crypto_key *secret, | |
352 | void *dst1, size_t *dst1_len, | |
353 | void *dst2, size_t *dst2_len, | |
354 | const void *src, size_t src_len) | |
355 | { | |
356 | size_t t; | |
357 | ||
358 | switch (secret->type) { | |
359 | case CEPH_CRYPTO_NONE: | |
360 | if (*dst1_len + *dst2_len < src_len) | |
361 | return -ERANGE; | |
362 | t = min(*dst1_len, src_len); | |
363 | memcpy(dst1, src, t); | |
364 | *dst1_len = t; | |
365 | src += t; | |
366 | src_len -= t; | |
367 | if (src_len) { | |
368 | t = min(*dst2_len, src_len); | |
369 | memcpy(dst2, src, t); | |
370 | *dst2_len = t; | |
371 | } | |
372 | return 0; | |
373 | ||
374 | case CEPH_CRYPTO_AES: | |
375 | return ceph_aes_decrypt2(secret->key, secret->len, | |
376 | dst1, dst1_len, dst2, dst2_len, | |
377 | src, src_len); | |
378 | ||
379 | default: | |
380 | return -EINVAL; | |
381 | } | |
382 | } | |
383 | ||
384 | int ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |
385 | const void *src, size_t src_len) | |
386 | { | |
387 | switch (secret->type) { | |
388 | case CEPH_CRYPTO_NONE: | |
389 | if (*dst_len < src_len) | |
390 | return -ERANGE; | |
391 | memcpy(dst, src, src_len); | |
392 | *dst_len = src_len; | |
393 | return 0; | |
394 | ||
395 | case CEPH_CRYPTO_AES: | |
396 | return ceph_aes_encrypt(secret->key, secret->len, dst, | |
397 | dst_len, src, src_len); | |
398 | ||
399 | default: | |
400 | return -EINVAL; | |
401 | } | |
402 | } | |
403 | ||
404 | int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len, | |
405 | const void *src1, size_t src1_len, | |
406 | const void *src2, size_t src2_len) | |
407 | { | |
408 | switch (secret->type) { | |
409 | case CEPH_CRYPTO_NONE: | |
410 | if (*dst_len < src1_len + src2_len) | |
411 | return -ERANGE; | |
412 | memcpy(dst, src1, src1_len); | |
413 | memcpy(dst + src1_len, src2, src2_len); | |
414 | *dst_len = src1_len + src2_len; | |
415 | return 0; | |
416 | ||
417 | case CEPH_CRYPTO_AES: | |
418 | return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len, | |
419 | src1, src1_len, src2, src2_len); | |
420 | ||
421 | default: | |
422 | return -EINVAL; | |
423 | } | |
424 | } | |
4b2a58ab TV |
425 | |
426 | int ceph_key_instantiate(struct key *key, const void *data, size_t datalen) | |
427 | { | |
428 | struct ceph_crypto_key *ckey; | |
429 | int ret; | |
430 | void *p; | |
431 | ||
432 | ret = -EINVAL; | |
433 | if (datalen <= 0 || datalen > 32767 || !data) | |
434 | goto err; | |
435 | ||
436 | ret = key_payload_reserve(key, datalen); | |
437 | if (ret < 0) | |
438 | goto err; | |
439 | ||
440 | ret = -ENOMEM; | |
441 | ckey = kmalloc(sizeof(*ckey), GFP_KERNEL); | |
442 | if (!ckey) | |
443 | goto err; | |
444 | ||
445 | /* TODO ceph_crypto_key_decode should really take const input */ | |
ea110733 | 446 | p = (void *)data; |
4b2a58ab TV |
447 | ret = ceph_crypto_key_decode(ckey, &p, (char*)data+datalen); |
448 | if (ret < 0) | |
449 | goto err_ckey; | |
450 | ||
451 | key->payload.data = ckey; | |
452 | return 0; | |
453 | ||
454 | err_ckey: | |
455 | kfree(ckey); | |
456 | err: | |
457 | return ret; | |
458 | } | |
459 | ||
460 | int ceph_key_match(const struct key *key, const void *description) | |
461 | { | |
462 | return strcmp(key->description, description) == 0; | |
463 | } | |
464 | ||
465 | void ceph_key_destroy(struct key *key) { | |
466 | struct ceph_crypto_key *ckey = key->payload.data; | |
467 | ||
468 | ceph_crypto_key_destroy(ckey); | |
f0666b1a | 469 | kfree(ckey); |
4b2a58ab TV |
470 | } |
471 | ||
472 | struct key_type key_type_ceph = { | |
473 | .name = "ceph", | |
474 | .instantiate = ceph_key_instantiate, | |
475 | .match = ceph_key_match, | |
476 | .destroy = ceph_key_destroy, | |
477 | }; | |
478 | ||
479 | int ceph_crypto_init(void) { | |
480 | return register_key_type(&key_type_ceph); | |
481 | } | |
482 | ||
483 | void ceph_crypto_shutdown(void) { | |
484 | unregister_key_type(&key_type_ceph); | |
485 | } |