forked from mirrors/linux
		
	ceph: aes crypto and base64 encode/decode helpers
Helpers to encrypt/decrypt AES and base64. Signed-off-by: Yehuda Sadeh <yehuda@hq.newdream.net> Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
		
							parent
							
								
									c7e337d649
								
							
						
					
					
						commit
						8b6e4f2d8b
					
				
					 5 changed files with 557 additions and 0 deletions
				
			
		| 
						 | 
					@ -2,6 +2,7 @@ config CEPH_FS
 | 
				
			||||||
        tristate "Ceph distributed file system (EXPERIMENTAL)"
 | 
					        tristate "Ceph distributed file system (EXPERIMENTAL)"
 | 
				
			||||||
	depends on INET && EXPERIMENTAL
 | 
						depends on INET && EXPERIMENTAL
 | 
				
			||||||
	select LIBCRC32C
 | 
						select LIBCRC32C
 | 
				
			||||||
 | 
						select CONFIG_CRYPTO_AES
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Choose Y or M here to include support for mounting the
 | 
						  Choose Y or M here to include support for mounting the
 | 
				
			||||||
	  experimental Ceph distributed file system.  Ceph is an extremely
 | 
						  experimental Ceph distributed file system.  Ceph is an extremely
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ ceph-objs := super.o inode.o dir.o file.o addr.o ioctl.o \
 | 
				
			||||||
	osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \
 | 
						osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \
 | 
				
			||||||
	debugfs.o \
 | 
						debugfs.o \
 | 
				
			||||||
	auth.o auth_none.o \
 | 
						auth.o auth_none.o \
 | 
				
			||||||
 | 
						crypto.o armor.o \
 | 
				
			||||||
	ceph_fs.o ceph_strings.o ceph_hash.o ceph_frag.o
 | 
						ceph_fs.o ceph_strings.o ceph_hash.o ceph_frag.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										99
									
								
								fs/ceph/armor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								fs/ceph/armor.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,99 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * base64 encode/decode.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *pem_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int encode_bits(int c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return pem_key[c];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int decode_bits(char c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (c >= 'A' && c <= 'Z')
 | 
				
			||||||
 | 
							return c - 'A';
 | 
				
			||||||
 | 
						if (c >= 'a' && c <= 'z')
 | 
				
			||||||
 | 
							return c - 'a' + 26;
 | 
				
			||||||
 | 
						if (c >= '0' && c <= '9')
 | 
				
			||||||
 | 
							return c - '0' + 52;
 | 
				
			||||||
 | 
						if (c == '+')
 | 
				
			||||||
 | 
							return 62;
 | 
				
			||||||
 | 
						if (c == '/')
 | 
				
			||||||
 | 
							return 63;
 | 
				
			||||||
 | 
						if (c == '=')
 | 
				
			||||||
 | 
							return 0; /* just non-negative, please */
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_armor(char *dst, const char *src, const char *end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int olen = 0;
 | 
				
			||||||
 | 
						int line = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (src < end) {
 | 
				
			||||||
 | 
							unsigned char a, b, c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							a = *src++;
 | 
				
			||||||
 | 
							*dst++ = encode_bits(a >> 2);
 | 
				
			||||||
 | 
							if (src < end) {
 | 
				
			||||||
 | 
								b = *src++;
 | 
				
			||||||
 | 
								*dst++ = encode_bits(((a & 3) << 4) | (b >> 4));
 | 
				
			||||||
 | 
								if (src < end) {
 | 
				
			||||||
 | 
									c = *src++;
 | 
				
			||||||
 | 
									*dst++ = encode_bits(((b & 15) << 2) |
 | 
				
			||||||
 | 
											     (c >> 6));
 | 
				
			||||||
 | 
									*dst++ = encode_bits(c & 63);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									*dst++ = encode_bits((b & 15) << 2);
 | 
				
			||||||
 | 
									*dst++ = '=';
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								*dst++ = encode_bits(((a & 3) << 4));
 | 
				
			||||||
 | 
								*dst++ = '=';
 | 
				
			||||||
 | 
								*dst++ = '=';
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							olen += 4;
 | 
				
			||||||
 | 
							line += 4;
 | 
				
			||||||
 | 
							if (line == 64) {
 | 
				
			||||||
 | 
								line = 0;
 | 
				
			||||||
 | 
								*(dst++) = '\n';
 | 
				
			||||||
 | 
								olen++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return olen;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_unarmor(char *dst, const char *src, const char *end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int olen = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (src < end) {
 | 
				
			||||||
 | 
							int a, b, c, d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (src < end && src[0] == '\n')
 | 
				
			||||||
 | 
								src++;
 | 
				
			||||||
 | 
							if (src + 4 > end)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							a = decode_bits(src[0]);
 | 
				
			||||||
 | 
							b = decode_bits(src[1]);
 | 
				
			||||||
 | 
							c = decode_bits(src[2]);
 | 
				
			||||||
 | 
							d = decode_bits(src[3]);
 | 
				
			||||||
 | 
							if (a < 0 || b < 0 || c < 0 || d < 0)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							*dst++ = (a << 2) | (b >> 4);
 | 
				
			||||||
 | 
							if (src[2] == '=')
 | 
				
			||||||
 | 
								return olen + 1;
 | 
				
			||||||
 | 
							*dst++ = ((b & 15) << 4) | (c >> 2);
 | 
				
			||||||
 | 
							if (src[3] == '=')
 | 
				
			||||||
 | 
								return olen + 2;
 | 
				
			||||||
 | 
							*dst++ = ((c & 3) << 6) | d;
 | 
				
			||||||
 | 
							olen += 3;
 | 
				
			||||||
 | 
							src += 4;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return olen;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										408
									
								
								fs/ceph/crypto.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										408
									
								
								fs/ceph/crypto.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,408 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "ceph_debug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/err.h>
 | 
				
			||||||
 | 
					#include <linux/scatterlist.h>
 | 
				
			||||||
 | 
					#include <crypto/hash.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "crypto.h"
 | 
				
			||||||
 | 
					#include "decode.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (*p + sizeof(u16) + sizeof(key->created) +
 | 
				
			||||||
 | 
						    sizeof(u16) + key->len > end)
 | 
				
			||||||
 | 
							return -ERANGE;
 | 
				
			||||||
 | 
						ceph_encode_16(p, key->type);
 | 
				
			||||||
 | 
						ceph_encode_copy(p, &key->created, sizeof(key->created));
 | 
				
			||||||
 | 
						ceph_encode_16(p, key->len);
 | 
				
			||||||
 | 
						ceph_encode_copy(p, key->key, key->len);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_crypto_key_decode(struct ceph_crypto_key *key, void **p, void *end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						ceph_decode_need(p, end, 2*sizeof(u16) + sizeof(key->created), bad);
 | 
				
			||||||
 | 
						key->type = ceph_decode_16(p);
 | 
				
			||||||
 | 
						ceph_decode_copy(p, &key->created, sizeof(key->created));
 | 
				
			||||||
 | 
						key->len = ceph_decode_16(p);
 | 
				
			||||||
 | 
						ceph_decode_need(p, end, key->len, bad);
 | 
				
			||||||
 | 
						key->key = kmalloc(key->len, GFP_NOFS);
 | 
				
			||||||
 | 
						if (!key->key)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						ceph_decode_copy(p, key->key, key->len);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bad:
 | 
				
			||||||
 | 
						dout("failed to decode crypto key\n");
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int inlen = strlen(inkey);
 | 
				
			||||||
 | 
						int blen = inlen * 3 / 4;
 | 
				
			||||||
 | 
						void *buf, *p;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dout("crypto_key_unarmor %s\n", inkey);
 | 
				
			||||||
 | 
						buf = kmalloc(blen, GFP_NOFS);
 | 
				
			||||||
 | 
						if (!buf)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						blen = ceph_unarmor(buf, inkey, inkey+inlen);
 | 
				
			||||||
 | 
						if (blen < 0) {
 | 
				
			||||||
 | 
							kfree(buf);
 | 
				
			||||||
 | 
							return blen;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p = buf;
 | 
				
			||||||
 | 
						ret = ceph_crypto_key_decode(key, &p, p + blen);
 | 
				
			||||||
 | 
						kfree(buf);
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						dout("crypto_key_unarmor key %p type %d len %d\n", key,
 | 
				
			||||||
 | 
						     key->type, key->len);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define AES_KEY_SIZE 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct crypto_blkcipher *ceph_crypto_alloc_cipher(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const u8 *aes_iv = "cephsageyudagreg";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_aes_encrypt(const void *key, int key_len, void *dst, size_t *dst_len,
 | 
				
			||||||
 | 
							     const void *src, size_t src_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct scatterlist sg_in[2], sg_out[1];
 | 
				
			||||||
 | 
						struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
 | 
				
			||||||
 | 
						struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						void *iv;
 | 
				
			||||||
 | 
						int ivsize;
 | 
				
			||||||
 | 
						size_t zero_padding = (0x10 - (src_len & 0x0f));
 | 
				
			||||||
 | 
						char pad[16];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(tfm))
 | 
				
			||||||
 | 
							return PTR_ERR(tfm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(pad, zero_padding, zero_padding);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*dst_len = src_len + zero_padding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						crypto_blkcipher_setkey((void *)tfm, key, key_len);
 | 
				
			||||||
 | 
						sg_init_table(sg_in, 2);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_in[0], src, src_len);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_in[1], pad, zero_padding);
 | 
				
			||||||
 | 
						sg_init_table(sg_out, 1);
 | 
				
			||||||
 | 
						sg_set_buf(sg_out, dst, *dst_len);
 | 
				
			||||||
 | 
						iv = crypto_blkcipher_crt(tfm)->iv;
 | 
				
			||||||
 | 
						ivsize = crypto_blkcipher_ivsize(tfm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(iv, aes_iv, ivsize);
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "enc key: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       key, key_len, 1);
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "enc src: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
								src, src_len, 1);
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "enc pad: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
								pad, zero_padding, 1);
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
 | 
				
			||||||
 | 
									     src_len + zero_padding);
 | 
				
			||||||
 | 
						crypto_free_blkcipher(tfm);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							pr_err("ceph_aes_crypt failed %d\n", ret);
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "enc out: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       dst, *dst_len, 1);
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_aes_encrypt2(const void *key, int key_len, void *dst, size_t *dst_len,
 | 
				
			||||||
 | 
							      const void *src1, size_t src1_len,
 | 
				
			||||||
 | 
							      const void *src2, size_t src2_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct scatterlist sg_in[3], sg_out[1];
 | 
				
			||||||
 | 
						struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
 | 
				
			||||||
 | 
						struct blkcipher_desc desc = { .tfm = tfm, .flags = 0 };
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						void *iv;
 | 
				
			||||||
 | 
						int ivsize;
 | 
				
			||||||
 | 
						size_t zero_padding = (0x10 - ((src1_len + src2_len) & 0x0f));
 | 
				
			||||||
 | 
						char pad[16];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(tfm))
 | 
				
			||||||
 | 
							return PTR_ERR(tfm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(pad, zero_padding, zero_padding);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*dst_len = src1_len + src2_len + zero_padding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						crypto_blkcipher_setkey((void *)tfm, key, key_len);
 | 
				
			||||||
 | 
						sg_init_table(sg_in, 3);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_in[0], src1, src1_len);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_in[1], src2, src2_len);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_in[2], pad, zero_padding);
 | 
				
			||||||
 | 
						sg_init_table(sg_out, 1);
 | 
				
			||||||
 | 
						sg_set_buf(sg_out, dst, *dst_len);
 | 
				
			||||||
 | 
						iv = crypto_blkcipher_crt(tfm)->iv;
 | 
				
			||||||
 | 
						ivsize = crypto_blkcipher_ivsize(tfm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(iv, aes_iv, ivsize);
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "enc  key: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       key, key_len, 1);
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "enc src1: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
								src1, src1_len, 1);
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "enc src2: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
								src2, src2_len, 1);
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "enc  pad: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
								pad, zero_padding, 1);
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
 | 
				
			||||||
 | 
									     src1_len + src2_len + zero_padding);
 | 
				
			||||||
 | 
						crypto_free_blkcipher(tfm);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							pr_err("ceph_aes_crypt2 failed %d\n", ret);
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "enc  out: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       dst, *dst_len, 1);
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_aes_decrypt(const void *key, int key_len, void *dst, size_t *dst_len,
 | 
				
			||||||
 | 
							     const void *src, size_t src_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct scatterlist sg_in[1], sg_out[2];
 | 
				
			||||||
 | 
						struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
 | 
				
			||||||
 | 
						struct blkcipher_desc desc = { .tfm = tfm };
 | 
				
			||||||
 | 
						char pad[16];
 | 
				
			||||||
 | 
						void *iv;
 | 
				
			||||||
 | 
						int ivsize;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						int last_byte;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(tfm))
 | 
				
			||||||
 | 
							return PTR_ERR(tfm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						crypto_blkcipher_setkey((void *)tfm, key, key_len);
 | 
				
			||||||
 | 
						sg_init_table(sg_in, 1);
 | 
				
			||||||
 | 
						sg_init_table(sg_out, 2);
 | 
				
			||||||
 | 
						sg_set_buf(sg_in, src, src_len);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_out[0], dst, *dst_len);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_out[1], pad, sizeof(pad));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						iv = crypto_blkcipher_crt(tfm)->iv;
 | 
				
			||||||
 | 
						ivsize = crypto_blkcipher_ivsize(tfm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(iv, aes_iv, ivsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "dec key: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       key, key_len, 1);
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "dec  in: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       src, src_len, 1);
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
 | 
				
			||||||
 | 
						crypto_free_blkcipher(tfm);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							pr_err("ceph_aes_decrypt failed %d\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (src_len <= *dst_len)
 | 
				
			||||||
 | 
							last_byte = ((char *)dst)[src_len - 1];
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							last_byte = pad[src_len - *dst_len - 1];
 | 
				
			||||||
 | 
						if (last_byte <= 16 && src_len >= last_byte) {
 | 
				
			||||||
 | 
							*dst_len = src_len - last_byte;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
 | 
				
			||||||
 | 
							       last_byte, (int)src_len);
 | 
				
			||||||
 | 
							return -EPERM;  /* bad padding */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "dec out: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       dst, *dst_len, 1);
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_aes_decrypt2(const void *key, int key_len,
 | 
				
			||||||
 | 
							      void *dst1, size_t *dst1_len,
 | 
				
			||||||
 | 
							      void *dst2, size_t *dst2_len,
 | 
				
			||||||
 | 
							      const void *src, size_t src_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct scatterlist sg_in[1], sg_out[3];
 | 
				
			||||||
 | 
						struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher();
 | 
				
			||||||
 | 
						struct blkcipher_desc desc = { .tfm = tfm };
 | 
				
			||||||
 | 
						char pad[16];
 | 
				
			||||||
 | 
						void *iv;
 | 
				
			||||||
 | 
						int ivsize;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
						int last_byte;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(tfm))
 | 
				
			||||||
 | 
							return PTR_ERR(tfm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sg_init_table(sg_in, 1);
 | 
				
			||||||
 | 
						sg_set_buf(sg_in, src, src_len);
 | 
				
			||||||
 | 
						sg_init_table(sg_out, 3);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_out[0], dst1, *dst1_len);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_out[1], dst2, *dst2_len);
 | 
				
			||||||
 | 
						sg_set_buf(&sg_out[2], pad, sizeof(pad));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						crypto_blkcipher_setkey((void *)tfm, key, key_len);
 | 
				
			||||||
 | 
						iv = crypto_blkcipher_crt(tfm)->iv;
 | 
				
			||||||
 | 
						ivsize = crypto_blkcipher_ivsize(tfm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(iv, aes_iv, ivsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "dec  key: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       key, key_len, 1);
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "dec   in: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       src, src_len, 1);
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, src_len);
 | 
				
			||||||
 | 
						crypto_free_blkcipher(tfm);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							pr_err("ceph_aes_decrypt failed %d\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (src_len <= *dst1_len)
 | 
				
			||||||
 | 
							last_byte = ((char *)dst1)[src_len - 1];
 | 
				
			||||||
 | 
						else if (src_len <= *dst1_len + *dst2_len)
 | 
				
			||||||
 | 
							last_byte = ((char *)dst2)[src_len - *dst1_len - 1];
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							last_byte = pad[src_len - *dst1_len - *dst2_len - 1];
 | 
				
			||||||
 | 
						if (last_byte <= 16 && src_len >= last_byte) {
 | 
				
			||||||
 | 
							src_len -= last_byte;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pr_err("ceph_aes_decrypt got bad padding %d on src len %d\n",
 | 
				
			||||||
 | 
							       last_byte, (int)src_len);
 | 
				
			||||||
 | 
							return -EPERM;  /* bad padding */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (src_len < *dst1_len) {
 | 
				
			||||||
 | 
							*dst1_len = src_len;
 | 
				
			||||||
 | 
							*dst2_len = 0;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							*dst2_len = src_len - *dst1_len;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "dec  out1: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       dst1, *dst1_len, 1);
 | 
				
			||||||
 | 
						print_hex_dump(KERN_ERR, "dec  out2: ", DUMP_PREFIX_NONE, 16, 1,
 | 
				
			||||||
 | 
							       dst2, *dst2_len, 1);
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_decrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
 | 
				
			||||||
 | 
							 const void *src, size_t src_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (secret->type) {
 | 
				
			||||||
 | 
						case CEPH_CRYPTO_NONE:
 | 
				
			||||||
 | 
							if (*dst_len < src_len)
 | 
				
			||||||
 | 
								return -ERANGE;
 | 
				
			||||||
 | 
							memcpy(dst, src, src_len);
 | 
				
			||||||
 | 
							*dst_len = src_len;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case CEPH_CRYPTO_AES:
 | 
				
			||||||
 | 
							return ceph_aes_decrypt(secret->key, secret->len, dst,
 | 
				
			||||||
 | 
										dst_len, src, src_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_decrypt2(struct ceph_crypto_key *secret,
 | 
				
			||||||
 | 
								void *dst1, size_t *dst1_len,
 | 
				
			||||||
 | 
								void *dst2, size_t *dst2_len,
 | 
				
			||||||
 | 
								const void *src, size_t src_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (secret->type) {
 | 
				
			||||||
 | 
						case CEPH_CRYPTO_NONE:
 | 
				
			||||||
 | 
							if (*dst1_len + *dst2_len < src_len)
 | 
				
			||||||
 | 
								return -ERANGE;
 | 
				
			||||||
 | 
							t = min(*dst1_len, src_len);
 | 
				
			||||||
 | 
							memcpy(dst1, src, t);
 | 
				
			||||||
 | 
							*dst1_len = t;
 | 
				
			||||||
 | 
							src += t;
 | 
				
			||||||
 | 
							src_len -= t;
 | 
				
			||||||
 | 
							if (src_len) {
 | 
				
			||||||
 | 
								t = min(*dst2_len, src_len);
 | 
				
			||||||
 | 
								memcpy(dst2, src, t);
 | 
				
			||||||
 | 
								*dst2_len = t;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case CEPH_CRYPTO_AES:
 | 
				
			||||||
 | 
							return ceph_aes_decrypt2(secret->key, secret->len,
 | 
				
			||||||
 | 
										 dst1, dst1_len, dst2, dst2_len,
 | 
				
			||||||
 | 
										 src, src_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_encrypt(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
 | 
				
			||||||
 | 
							 const void *src, size_t src_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (secret->type) {
 | 
				
			||||||
 | 
						case CEPH_CRYPTO_NONE:
 | 
				
			||||||
 | 
							if (*dst_len < src_len)
 | 
				
			||||||
 | 
								return -ERANGE;
 | 
				
			||||||
 | 
							memcpy(dst, src, src_len);
 | 
				
			||||||
 | 
							*dst_len = src_len;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case CEPH_CRYPTO_AES:
 | 
				
			||||||
 | 
							return ceph_aes_encrypt(secret->key, secret->len, dst,
 | 
				
			||||||
 | 
										dst_len, src, src_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
 | 
				
			||||||
 | 
							  const void *src1, size_t src1_len,
 | 
				
			||||||
 | 
							  const void *src2, size_t src2_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (secret->type) {
 | 
				
			||||||
 | 
						case CEPH_CRYPTO_NONE:
 | 
				
			||||||
 | 
							if (*dst_len < src1_len + src2_len)
 | 
				
			||||||
 | 
								return -ERANGE;
 | 
				
			||||||
 | 
							memcpy(dst, src1, src1_len);
 | 
				
			||||||
 | 
							memcpy(dst + src1_len, src2, src2_len);
 | 
				
			||||||
 | 
							*dst_len = src1_len + src2_len;
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case CEPH_CRYPTO_AES:
 | 
				
			||||||
 | 
							return ceph_aes_encrypt2(secret->key, secret->len, dst, dst_len,
 | 
				
			||||||
 | 
										 src1, src1_len, src2, src2_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										48
									
								
								fs/ceph/crypto.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								fs/ceph/crypto.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,48 @@
 | 
				
			||||||
 | 
					#ifndef _FS_CEPH_CRYPTO_H
 | 
				
			||||||
 | 
					#define _FS_CEPH_CRYPTO_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "types.h"
 | 
				
			||||||
 | 
					#include "buffer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * cryptographic secret
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct ceph_crypto_key {
 | 
				
			||||||
 | 
						int type;
 | 
				
			||||||
 | 
						struct ceph_timespec created;
 | 
				
			||||||
 | 
						int len;
 | 
				
			||||||
 | 
						void *key;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						kfree(key->key);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int ceph_crypto_key_encode(struct ceph_crypto_key *key,
 | 
				
			||||||
 | 
									  void **p, void *end);
 | 
				
			||||||
 | 
					extern int ceph_crypto_key_decode(struct ceph_crypto_key *key,
 | 
				
			||||||
 | 
									  void **p, void *end);
 | 
				
			||||||
 | 
					extern int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *in);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* crypto.c */
 | 
				
			||||||
 | 
					extern int ceph_decrypt(struct ceph_crypto_key *secret,
 | 
				
			||||||
 | 
								void *dst, size_t *dst_len,
 | 
				
			||||||
 | 
								const void *src, size_t src_len);
 | 
				
			||||||
 | 
					extern int ceph_encrypt(struct ceph_crypto_key *secret,
 | 
				
			||||||
 | 
								void *dst, size_t *dst_len,
 | 
				
			||||||
 | 
								const void *src, size_t src_len);
 | 
				
			||||||
 | 
					extern int ceph_decrypt2(struct ceph_crypto_key *secret,
 | 
				
			||||||
 | 
								void *dst1, size_t *dst1_len,
 | 
				
			||||||
 | 
								void *dst2, size_t *dst2_len,
 | 
				
			||||||
 | 
								const void *src, size_t src_len);
 | 
				
			||||||
 | 
					extern int ceph_encrypt2(struct ceph_crypto_key *secret,
 | 
				
			||||||
 | 
								 void *dst, size_t *dst_len,
 | 
				
			||||||
 | 
								 const void *src1, size_t src1_len,
 | 
				
			||||||
 | 
								 const void *src2, size_t src2_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* armor.c */
 | 
				
			||||||
 | 
					extern int ceph_armor(char *dst, const void *src, const void *end);
 | 
				
			||||||
 | 
					extern int ceph_unarmor(void *dst, const char *src, const char *end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		Loading…
	
		Reference in a new issue