summaryrefslogtreecommitdiff
path: root/fs/ceph/crypto.h
blob: 176731f6499755edce0ee0b683bc5a293f1bf227 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Ceph fscrypt functionality
 */

#ifndef _CEPH_CRYPTO_H
#define _CEPH_CRYPTO_H

#include <crypto/sha2.h>
#include <linux/fscrypt.h>

struct ceph_fs_client;
struct ceph_acl_sec_ctx;
struct ceph_mds_request;

struct ceph_fscrypt_auth {
	__le32	cfa_version;
	__le32	cfa_blob_len;
	u8	cfa_blob[FSCRYPT_SET_CONTEXT_MAX_SIZE];
} __packed;

#define CEPH_FSCRYPT_AUTH_VERSION	1
static inline u32 ceph_fscrypt_auth_len(struct ceph_fscrypt_auth *fa)
{
	u32 ctxsize = le32_to_cpu(fa->cfa_blob_len);

	return offsetof(struct ceph_fscrypt_auth, cfa_blob) + ctxsize;
}

#ifdef CONFIG_FS_ENCRYPTION
/*
 * We want to encrypt filenames when creating them, but the encrypted
 * versions of those names may have illegal characters in them. To mitigate
 * that, we base64 encode them, but that gives us a result that can exceed
 * NAME_MAX.
 *
 * Follow a similar scheme to fscrypt itself, and cap the filename to a
 * smaller size. If the ciphertext name is longer than the value below, then
 * sha256 hash the remaining bytes.
 *
 * For the fscrypt_nokey_name struct the dirhash[2] member is useless in ceph
 * so the corresponding struct will be:
 *
 * struct fscrypt_ceph_nokey_name {
 *	u8 bytes[157];
 *	u8 sha256[SHA256_DIGEST_SIZE];
 * }; // 180 bytes => 240 bytes base64-encoded, which is <= NAME_MAX (255)
 *
 * (240 bytes is the maximum size allowed for snapshot names to take into
 *  account the format: '_<SNAPSHOT-NAME>_<INODE-NUMBER>'.)
 *
 * Note that for long names that end up having their tail portion hashed, we
 * must also store the full encrypted name (in the dentry's alternate_name
 * field).
 */
#define CEPH_NOHASH_NAME_MAX (180 - SHA256_DIGEST_SIZE)

#define CEPH_BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)

int ceph_base64_encode(const u8 *src, int srclen, char *dst);
int ceph_base64_decode(const char *src, int srclen, u8 *dst);

void ceph_fscrypt_set_ops(struct super_block *sb);

void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc);

int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode,
				 struct ceph_acl_sec_ctx *as);
void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
				struct ceph_acl_sec_ctx *as);
int ceph_encode_encrypted_fname(const struct inode *parent,
				struct dentry *dentry, char *buf);

#else /* CONFIG_FS_ENCRYPTION */

static inline void ceph_fscrypt_set_ops(struct super_block *sb)
{
}

static inline void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc)
{
}

static inline int ceph_fscrypt_prepare_context(struct inode *dir,
					       struct inode *inode,
					       struct ceph_acl_sec_ctx *as)
{
	if (IS_ENCRYPTED(dir))
		return -EOPNOTSUPP;
	return 0;
}

static inline void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
						struct ceph_acl_sec_ctx *as_ctx)
{
}

static inline int ceph_encode_encrypted_fname(const struct inode *parent,
					      struct dentry *dentry, char *buf)
{
	return -EOPNOTSUPP;
}
#endif /* CONFIG_FS_ENCRYPTION */

#endif