162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Ceph fscrypt functionality
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#ifndef _CEPH_CRYPTO_H
762306a36Sopenharmony_ci#define _CEPH_CRYPTO_H
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <crypto/sha2.h>
1062306a36Sopenharmony_ci#include <linux/fscrypt.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define CEPH_FSCRYPT_BLOCK_SHIFT   12
1362306a36Sopenharmony_ci#define CEPH_FSCRYPT_BLOCK_SIZE    (_AC(1, UL) << CEPH_FSCRYPT_BLOCK_SHIFT)
1462306a36Sopenharmony_ci#define CEPH_FSCRYPT_BLOCK_MASK	   (~(CEPH_FSCRYPT_BLOCK_SIZE-1))
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct ceph_fs_client;
1762306a36Sopenharmony_cistruct ceph_acl_sec_ctx;
1862306a36Sopenharmony_cistruct ceph_mds_request;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct ceph_fname {
2162306a36Sopenharmony_ci	struct inode	*dir;
2262306a36Sopenharmony_ci	char		*name;		// b64 encoded, possibly hashed
2362306a36Sopenharmony_ci	unsigned char	*ctext;		// binary crypttext (if any)
2462306a36Sopenharmony_ci	u32		name_len;	// length of name buffer
2562306a36Sopenharmony_ci	u32		ctext_len;	// length of crypttext
2662306a36Sopenharmony_ci	bool		no_copy;
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/*
3062306a36Sopenharmony_ci * Header for the crypted file when truncating the size, this
3162306a36Sopenharmony_ci * will be sent to MDS, and the MDS will update the encrypted
3262306a36Sopenharmony_ci * last block and then truncate the size.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_cistruct ceph_fscrypt_truncate_size_header {
3562306a36Sopenharmony_ci	__u8  ver;
3662306a36Sopenharmony_ci	__u8  compat;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/*
3962306a36Sopenharmony_ci	 * It will be sizeof(assert_ver + file_offset + block_size)
4062306a36Sopenharmony_ci	 * if the last block is empty when it's located in a file
4162306a36Sopenharmony_ci	 * hole. Or the data_len will plus CEPH_FSCRYPT_BLOCK_SIZE.
4262306a36Sopenharmony_ci	 */
4362306a36Sopenharmony_ci	__le32 data_len;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	__le64 change_attr;
4662306a36Sopenharmony_ci	__le64 file_offset;
4762306a36Sopenharmony_ci	__le32 block_size;
4862306a36Sopenharmony_ci} __packed;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistruct ceph_fscrypt_auth {
5162306a36Sopenharmony_ci	__le32	cfa_version;
5262306a36Sopenharmony_ci	__le32	cfa_blob_len;
5362306a36Sopenharmony_ci	u8	cfa_blob[FSCRYPT_SET_CONTEXT_MAX_SIZE];
5462306a36Sopenharmony_ci} __packed;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define CEPH_FSCRYPT_AUTH_VERSION	1
5762306a36Sopenharmony_cistatic inline u32 ceph_fscrypt_auth_len(struct ceph_fscrypt_auth *fa)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	u32 ctxsize = le32_to_cpu(fa->cfa_blob_len);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return offsetof(struct ceph_fscrypt_auth, cfa_blob) + ctxsize;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#ifdef CONFIG_FS_ENCRYPTION
6562306a36Sopenharmony_ci/*
6662306a36Sopenharmony_ci * We want to encrypt filenames when creating them, but the encrypted
6762306a36Sopenharmony_ci * versions of those names may have illegal characters in them. To mitigate
6862306a36Sopenharmony_ci * that, we base64 encode them, but that gives us a result that can exceed
6962306a36Sopenharmony_ci * NAME_MAX.
7062306a36Sopenharmony_ci *
7162306a36Sopenharmony_ci * Follow a similar scheme to fscrypt itself, and cap the filename to a
7262306a36Sopenharmony_ci * smaller size. If the ciphertext name is longer than the value below, then
7362306a36Sopenharmony_ci * sha256 hash the remaining bytes.
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci * For the fscrypt_nokey_name struct the dirhash[2] member is useless in ceph
7662306a36Sopenharmony_ci * so the corresponding struct will be:
7762306a36Sopenharmony_ci *
7862306a36Sopenharmony_ci * struct fscrypt_ceph_nokey_name {
7962306a36Sopenharmony_ci *	u8 bytes[157];
8062306a36Sopenharmony_ci *	u8 sha256[SHA256_DIGEST_SIZE];
8162306a36Sopenharmony_ci * }; // 180 bytes => 240 bytes base64-encoded, which is <= NAME_MAX (255)
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci * (240 bytes is the maximum size allowed for snapshot names to take into
8462306a36Sopenharmony_ci *  account the format: '_<SNAPSHOT-NAME>_<INODE-NUMBER>'.)
8562306a36Sopenharmony_ci *
8662306a36Sopenharmony_ci * Note that for long names that end up having their tail portion hashed, we
8762306a36Sopenharmony_ci * must also store the full encrypted name (in the dentry's alternate_name
8862306a36Sopenharmony_ci * field).
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_ci#define CEPH_NOHASH_NAME_MAX (180 - SHA256_DIGEST_SIZE)
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define CEPH_BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ciint ceph_base64_encode(const u8 *src, int srclen, char *dst);
9562306a36Sopenharmony_ciint ceph_base64_decode(const char *src, int srclen, u8 *dst);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_civoid ceph_fscrypt_set_ops(struct super_block *sb);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_civoid ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ciint ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode,
10262306a36Sopenharmony_ci				 struct ceph_acl_sec_ctx *as);
10362306a36Sopenharmony_civoid ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
10462306a36Sopenharmony_ci				struct ceph_acl_sec_ctx *as);
10562306a36Sopenharmony_ciint ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,
10662306a36Sopenharmony_ci				char *buf);
10762306a36Sopenharmony_ciint ceph_encode_encrypted_fname(struct inode *parent, struct dentry *dentry,
10862306a36Sopenharmony_ci				char *buf);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic inline int ceph_fname_alloc_buffer(struct inode *parent,
11162306a36Sopenharmony_ci					  struct fscrypt_str *fname)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	if (!IS_ENCRYPTED(parent))
11462306a36Sopenharmony_ci		return 0;
11562306a36Sopenharmony_ci	return fscrypt_fname_alloc_buffer(NAME_MAX, fname);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline void ceph_fname_free_buffer(struct inode *parent,
11962306a36Sopenharmony_ci					  struct fscrypt_str *fname)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	if (IS_ENCRYPTED(parent))
12262306a36Sopenharmony_ci		fscrypt_fname_free_buffer(fname);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ciint ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *tname,
12662306a36Sopenharmony_ci		      struct fscrypt_str *oname, bool *is_nokey);
12762306a36Sopenharmony_ciint ceph_fscrypt_prepare_readdir(struct inode *dir);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic inline unsigned int ceph_fscrypt_blocks(u64 off, u64 len)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	/* crypto blocks cannot span more than one page */
13262306a36Sopenharmony_ci	BUILD_BUG_ON(CEPH_FSCRYPT_BLOCK_SHIFT > PAGE_SHIFT);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return ((off+len+CEPH_FSCRYPT_BLOCK_SIZE-1) >> CEPH_FSCRYPT_BLOCK_SHIFT) -
13562306a36Sopenharmony_ci		(off >> CEPH_FSCRYPT_BLOCK_SHIFT);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/*
13962306a36Sopenharmony_ci * If we have an encrypted inode then we must adjust the offset and
14062306a36Sopenharmony_ci * range of the on-the-wire read to cover an entire encryption block.
14162306a36Sopenharmony_ci * The copy will be done using the original offset and length, after
14262306a36Sopenharmony_ci * we've decrypted the result.
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_cistatic inline void ceph_fscrypt_adjust_off_and_len(struct inode *inode,
14562306a36Sopenharmony_ci						   u64 *off, u64 *len)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	if (IS_ENCRYPTED(inode)) {
14862306a36Sopenharmony_ci		*len = ceph_fscrypt_blocks(*off, *len) * CEPH_FSCRYPT_BLOCK_SIZE;
14962306a36Sopenharmony_ci		*off &= CEPH_FSCRYPT_BLOCK_MASK;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ciint ceph_fscrypt_decrypt_block_inplace(const struct inode *inode,
15462306a36Sopenharmony_ci				  struct page *page, unsigned int len,
15562306a36Sopenharmony_ci				  unsigned int offs, u64 lblk_num);
15662306a36Sopenharmony_ciint ceph_fscrypt_encrypt_block_inplace(const struct inode *inode,
15762306a36Sopenharmony_ci				  struct page *page, unsigned int len,
15862306a36Sopenharmony_ci				  unsigned int offs, u64 lblk_num,
15962306a36Sopenharmony_ci				  gfp_t gfp_flags);
16062306a36Sopenharmony_ciint ceph_fscrypt_decrypt_pages(struct inode *inode, struct page **page,
16162306a36Sopenharmony_ci			       u64 off, int len);
16262306a36Sopenharmony_ciint ceph_fscrypt_decrypt_extents(struct inode *inode, struct page **page,
16362306a36Sopenharmony_ci				 u64 off, struct ceph_sparse_extent *map,
16462306a36Sopenharmony_ci				 u32 ext_cnt);
16562306a36Sopenharmony_ciint ceph_fscrypt_encrypt_pages(struct inode *inode, struct page **page, u64 off,
16662306a36Sopenharmony_ci			       int len, gfp_t gfp);
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic inline struct page *ceph_fscrypt_pagecache_page(struct page *page)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	return fscrypt_is_bounce_page(page) ? fscrypt_pagecache_page(page) : page;
17162306a36Sopenharmony_ci}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#else /* CONFIG_FS_ENCRYPTION */
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic inline void ceph_fscrypt_set_ops(struct super_block *sb)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic inline void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic inline int ceph_fscrypt_prepare_context(struct inode *dir,
18462306a36Sopenharmony_ci					       struct inode *inode,
18562306a36Sopenharmony_ci					       struct ceph_acl_sec_ctx *as)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	if (IS_ENCRYPTED(dir))
18862306a36Sopenharmony_ci		return -EOPNOTSUPP;
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic inline void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
19362306a36Sopenharmony_ci						struct ceph_acl_sec_ctx *as_ctx)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic inline int ceph_encode_encrypted_dname(struct inode *parent,
19862306a36Sopenharmony_ci					      struct qstr *d_name, char *buf)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	memcpy(buf, d_name->name, d_name->len);
20162306a36Sopenharmony_ci	return d_name->len;
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic inline int ceph_encode_encrypted_fname(struct inode *parent,
20562306a36Sopenharmony_ci					      struct dentry *dentry, char *buf)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	return -EOPNOTSUPP;
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic inline int ceph_fname_alloc_buffer(struct inode *parent,
21162306a36Sopenharmony_ci					  struct fscrypt_str *fname)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	return 0;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic inline void ceph_fname_free_buffer(struct inode *parent,
21762306a36Sopenharmony_ci					  struct fscrypt_str *fname)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic inline int ceph_fname_to_usr(const struct ceph_fname *fname,
22262306a36Sopenharmony_ci				    struct fscrypt_str *tname,
22362306a36Sopenharmony_ci				    struct fscrypt_str *oname, bool *is_nokey)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	oname->name = fname->name;
22662306a36Sopenharmony_ci	oname->len = fname->name_len;
22762306a36Sopenharmony_ci	return 0;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic inline int ceph_fscrypt_prepare_readdir(struct inode *dir)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	return 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic inline void ceph_fscrypt_adjust_off_and_len(struct inode *inode,
23662306a36Sopenharmony_ci						   u64 *off, u64 *len)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic inline int ceph_fscrypt_decrypt_block_inplace(const struct inode *inode,
24162306a36Sopenharmony_ci					  struct page *page, unsigned int len,
24262306a36Sopenharmony_ci					  unsigned int offs, u64 lblk_num)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_cistatic inline int ceph_fscrypt_encrypt_block_inplace(const struct inode *inode,
24862306a36Sopenharmony_ci					  struct page *page, unsigned int len,
24962306a36Sopenharmony_ci					  unsigned int offs, u64 lblk_num,
25062306a36Sopenharmony_ci					  gfp_t gfp_flags)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	return 0;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic inline int ceph_fscrypt_decrypt_pages(struct inode *inode,
25662306a36Sopenharmony_ci					     struct page **page, u64 off,
25762306a36Sopenharmony_ci					     int len)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	return 0;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic inline int ceph_fscrypt_decrypt_extents(struct inode *inode,
26362306a36Sopenharmony_ci					       struct page **page, u64 off,
26462306a36Sopenharmony_ci					       struct ceph_sparse_extent *map,
26562306a36Sopenharmony_ci					       u32 ext_cnt)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	return 0;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic inline int ceph_fscrypt_encrypt_pages(struct inode *inode,
27162306a36Sopenharmony_ci					     struct page **page, u64 off,
27262306a36Sopenharmony_ci					     int len, gfp_t gfp)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic inline struct page *ceph_fscrypt_pagecache_page(struct page *page)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	return page;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci#endif /* CONFIG_FS_ENCRYPTION */
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic inline loff_t ceph_fscrypt_page_offset(struct page *page)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	return page_offset(ceph_fscrypt_pagecache_page(page));
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci#endif /* _CEPH_CRYPTO_H */
289