[f2fs-dev] [PATCH 05/10] fs crypto: add fname.c to support filename encryption

2016-03-02 Thread Jaegeuk Kim
This patch adds fname.c supporting filename encryption.

1. general wrapper functions
 - fscrypt_fname_disk_to_usr
 - fscrypt_fname_usr_to_disk
 - fscrypt_setup_filename
 - fscrypt_free_filename

2. specific filename handling functions
 - fscrypt_fname_alloc_buffer
 - fscrypt_fname_free_buffer

Signed-off-by: Uday Savagaonkar 
Signed-off-by: Ildar Muslukhov 
Signed-off-by: Michael Halcrow 
Signed-off-by: Theodore Ts'o 
Signed-off-by: Jaegeuk Kim 
---
 fs/crypto/fname.c| 427 +++
 include/linux/fscrypto.h |  66 
 2 files changed, 493 insertions(+)
 create mode 100644 fs/crypto/fname.c

diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
new file mode 100644
index 000..5e4ddee
--- /dev/null
+++ b/fs/crypto/fname.c
@@ -0,0 +1,427 @@
+/*
+ * This contains functions for filename crypto management
+ *
+ * Copyright (C) 2015, Google, Inc.
+ * Copyright (C) 2015, Motorola Mobility
+ *
+ * Written by Uday Savagaonkar, 2014.
+ * Modified by Jaegeuk Kim, 2015.
+ *
+ * This has not yet undergone a rigorous security audit.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static u32 size_round_up(size_t size, size_t blksize)
+{
+   return ((size + blksize - 1) / blksize) * blksize;
+}
+
+/**
+ * dir_crypt_complete() -
+ */
+static void dir_crypt_complete(struct crypto_async_request *req, int res)
+{
+   struct fscrypt_completion_result *ecr = req->data;
+
+   if (res == -EINPROGRESS)
+   return;
+   ecr->res = res;
+   complete(>completion);
+}
+
+/**
+ * fname_encrypt() -
+ *
+ * This function encrypts the input filename, and returns the length of the
+ * ciphertext. Errors are returned as negative numbers.  We trust the caller to
+ * allocate sufficient memory to oname string.
+ */
+static int fname_encrypt(struct inode *inode,
+   const struct qstr *iname, struct fscrypt_str *oname)
+{
+   u32 ciphertext_len;
+   struct ablkcipher_request *req = NULL;
+   DECLARE_FS_COMPLETION_RESULT(ecr);
+   struct fscrypt_info *ci = inode->i_crypt_info;
+   struct crypto_ablkcipher *tfm = ci->ci_ctfm;
+   int res = 0;
+   char iv[FS_CRYPTO_BLOCK_SIZE];
+   struct scatterlist src_sg, dst_sg;
+   int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
+   char *workbuf, buf[32], *alloc_buf = NULL;
+   unsigned lim;
+
+   lim = inode->i_sb->s_cop->max_namelen(inode);
+   if (iname->len <= 0 || iname->len > lim)
+   return -EIO;
+
+   ciphertext_len = (iname->len < FS_CRYPTO_BLOCK_SIZE) ?
+   FS_CRYPTO_BLOCK_SIZE : iname->len;
+   ciphertext_len = size_round_up(ciphertext_len, padding);
+   ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len;
+
+   if (ciphertext_len <= sizeof(buf)) {
+   workbuf = buf;
+   } else {
+   alloc_buf = kmalloc(ciphertext_len, GFP_NOFS);
+   if (!alloc_buf)
+   return -ENOMEM;
+   workbuf = alloc_buf;
+   }
+
+   /* Allocate request */
+   req = ablkcipher_request_alloc(tfm, GFP_NOFS);
+   if (!req) {
+   printk_ratelimited(KERN_ERR
+   "%s: crypto_request_alloc() failed\n", __func__);
+   kfree(alloc_buf);
+   return -ENOMEM;
+   }
+   ablkcipher_request_set_callback(req,
+   CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
+   dir_crypt_complete, );
+
+   /* Copy the input */
+   memcpy(workbuf, iname->name, iname->len);
+   if (iname->len < ciphertext_len)
+   memset(workbuf + iname->len, 0, ciphertext_len - iname->len);
+
+   /* Initialize IV */
+   memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
+
+   /* Create encryption request */
+   sg_init_one(_sg, workbuf, ciphertext_len);
+   sg_init_one(_sg, oname->name, ciphertext_len);
+   ablkcipher_request_set_crypt(req, _sg, _sg, ciphertext_len, iv);
+   res = crypto_ablkcipher_encrypt(req);
+   if (res == -EINPROGRESS || res == -EBUSY) {
+   wait_for_completion();
+   res = ecr.res;
+   }
+   kfree(alloc_buf);
+   ablkcipher_request_free(req);
+   if (res < 0)
+   printk_ratelimited(KERN_ERR
+   "%s: Error (error code %d)\n", __func__, res);
+
+   oname->len = ciphertext_len;
+   return res;
+}
+
+/*
+ * fname_decrypt()
+ * This function decrypts the input filename, and returns
+ * the length of the plaintext.
+ * Errors are returned as negative numbers.
+ * We trust the caller to allocate sufficient memory to oname string.
+ */
+static int fname_decrypt(struct inode *inode,
+   const struct 

[f2fs-dev] [PATCH 05/10] fs crypto: add fname.c to support filename encryption

2016-02-25 Thread Jaegeuk Kim
This patch adds fname.c supporting filename encryption.

1. general wrapper functions
 - fscrypt_fname_disk_to_usr
 - fscrypt_fname_usr_to_disk
 - fscrypt_setup_filename
 - fscrypt_free_filename

2. specific filename handling functions
 - fscrypt_fname_alloc_buffer
 - fscrypt_fname_free_buffer

Signed-off-by: Uday Savagaonkar 
Signed-off-by: Ildar Muslukhov 
Signed-off-by: Michael Halcrow 
Signed-off-by: Theodore Ts'o 
Signed-off-by: Jaegeuk Kim 
---
 fs/crypto/fname.c| 437 +++
 include/linux/fscrypto.h |  13 ++
 2 files changed, 450 insertions(+)
 create mode 100644 fs/crypto/fname.c

diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
new file mode 100644
index 000..8488a96
--- /dev/null
+++ b/fs/crypto/fname.c
@@ -0,0 +1,437 @@
+/*
+ * This contains functions for filename crypto management
+ *
+ * Copyright (C) 2015, Google, Inc.
+ * Copyright (C) 2015, Motorola Mobility
+ *
+ * Written by Uday Savagaonkar, 2014.
+ * Modified by Jaegeuk Kim, 2015.
+ *
+ * This has not yet undergone a rigorous security audit.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static u32 size_round_up(size_t size, size_t blksize)
+{
+   return ((size + blksize - 1) / blksize) * blksize;
+}
+
+#ifdef CONFIG_FS_ENCRYPTION
+/**
+ * dir_crypt_complete() -
+ */
+static void dir_crypt_complete(struct crypto_async_request *req, int res)
+{
+   struct fscrypt_completion_result *ecr = req->data;
+
+   if (res == -EINPROGRESS)
+   return;
+   ecr->res = res;
+   complete(>completion);
+}
+
+/**
+ * fname_encrypt() -
+ *
+ * This function encrypts the input filename, and returns the length of the
+ * ciphertext. Errors are returned as negative numbers.  We trust the caller to
+ * allocate sufficient memory to oname string.
+ */
+static int fname_encrypt(struct inode *inode,
+   const struct qstr *iname, struct fscrypt_str *oname)
+{
+   u32 ciphertext_len;
+   struct ablkcipher_request *req = NULL;
+   DECLARE_FS_COMPLETION_RESULT(ecr);
+   struct fscrypt_info *ci = inode->i_crypt_info;
+   struct crypto_ablkcipher *tfm = ci->ci_ctfm;
+   int res = 0;
+   char iv[FS_CRYPTO_BLOCK_SIZE];
+   struct scatterlist src_sg, dst_sg;
+   int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
+   char *workbuf, buf[32], *alloc_buf = NULL;
+   unsigned lim;
+
+   lim = inode->i_sb->s_cop->max_namelen(inode);
+   if (iname->len <= 0 || iname->len > lim)
+   return -EIO;
+
+   ciphertext_len = (iname->len < FS_CRYPTO_BLOCK_SIZE) ?
+   FS_CRYPTO_BLOCK_SIZE : iname->len;
+   ciphertext_len = size_round_up(ciphertext_len, padding);
+   ciphertext_len = (ciphertext_len > lim) ? lim : ciphertext_len;
+
+   if (ciphertext_len <= sizeof(buf)) {
+   workbuf = buf;
+   } else {
+   alloc_buf = kmalloc(ciphertext_len, GFP_NOFS);
+   if (!alloc_buf)
+   return -ENOMEM;
+   workbuf = alloc_buf;
+   }
+
+   /* Allocate request */
+   req = ablkcipher_request_alloc(tfm, GFP_NOFS);
+   if (!req) {
+   printk_ratelimited(KERN_ERR
+   "%s: crypto_request_alloc() failed\n", __func__);
+   kfree(alloc_buf);
+   return -ENOMEM;
+   }
+   ablkcipher_request_set_callback(req,
+   CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
+   dir_crypt_complete, );
+
+   /* Copy the input */
+   memcpy(workbuf, iname->name, iname->len);
+   if (iname->len < ciphertext_len)
+   memset(workbuf + iname->len, 0, ciphertext_len - iname->len);
+
+   /* Initialize IV */
+   memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
+
+   /* Create encryption request */
+   sg_init_one(_sg, workbuf, ciphertext_len);
+   sg_init_one(_sg, oname->name, ciphertext_len);
+   ablkcipher_request_set_crypt(req, _sg, _sg, ciphertext_len, iv);
+   res = crypto_ablkcipher_encrypt(req);
+   if (res == -EINPROGRESS || res == -EBUSY) {
+   wait_for_completion();
+   res = ecr.res;
+   }
+   kfree(alloc_buf);
+   ablkcipher_request_free(req);
+   if (res < 0)
+   printk_ratelimited(KERN_ERR
+   "%s: Error (error code %d)\n", __func__, res);
+
+   oname->len = ciphertext_len;
+   return res;
+}
+
+/*
+ * fname_decrypt()
+ * This function decrypts the input filename, and returns
+ * the length of the plaintext.
+ * Errors are returned as negative numbers.
+ * We trust the caller to allocate sufficient memory to oname string.
+ */
+static int fname_decrypt(struct inode *inode,
+