summaryrefslogtreecommitdiff
path: root/fs/ceph/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ceph/crypto.c')
-rw-r--r--fs/ceph/crypto.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c
index 0bb4d8e9f3b0..6dc723e8d395 100644
--- a/fs/ceph/crypto.c
+++ b/fs/ceph/crypto.c
@@ -191,3 +191,56 @@ void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req,
{
swap(req->r_fscrypt_auth, as->fscrypt_auth);
}
+
+int ceph_encode_encrypted_fname(const struct inode *parent,
+ struct dentry *dentry, char *buf)
+{
+ u32 len;
+ int elen;
+ int ret;
+ u8 *cryptbuf;
+
+ WARN_ON_ONCE(!fscrypt_has_encryption_key(parent));
+
+ /*
+ * Convert cleartext d_name to ciphertext. If result is longer than
+ * CEPH_NOHASH_NAME_MAX, sha256 the remaining bytes
+ *
+ * See: fscrypt_setup_filename
+ */
+ if (!fscrypt_fname_encrypted_size(parent, dentry->d_name.len, NAME_MAX,
+ &len))
+ return -ENAMETOOLONG;
+
+ /* Allocate a buffer appropriate to hold the result */
+ cryptbuf = kmalloc(len > CEPH_NOHASH_NAME_MAX ? NAME_MAX : len,
+ GFP_KERNEL);
+ if (!cryptbuf)
+ return -ENOMEM;
+
+ ret = fscrypt_fname_encrypt(parent, &dentry->d_name, cryptbuf, len);
+ if (ret) {
+ kfree(cryptbuf);
+ return ret;
+ }
+
+ /* hash the end if the name is long enough */
+ if (len > CEPH_NOHASH_NAME_MAX) {
+ u8 hash[SHA256_DIGEST_SIZE];
+ u8 *extra = cryptbuf + CEPH_NOHASH_NAME_MAX;
+
+ /*
+ * hash the extra bytes and overwrite crypttext beyond that
+ * point with it
+ */
+ sha256(extra, len - CEPH_NOHASH_NAME_MAX, hash);
+ memcpy(extra, hash, SHA256_DIGEST_SIZE);
+ len = CEPH_NOHASH_NAME_MAX + SHA256_DIGEST_SIZE;
+ }
+
+ /* base64 encode the encrypted name */
+ elen = ceph_base64_encode(cryptbuf, len, buf);
+ kfree(cryptbuf);
+ dout("base64-encoded ciphertext name = %.*s\n", elen, buf);
+ return elen;
+}