[f2fs-dev] [PATCH 04/10] fs crypto: add keyinfo.c to handle permissions

2016-03-02 Thread Jaegeuk Kim
This patch adds keyinfo.c supporting key management.

 - fscrypt_get_encryption_info
 - fscrypt_free_encryption_info

Signed-off-by: Michael Halcrow 
Signed-off-by: Ildar Muslukhov 
Signed-off-by: Theodore Ts'o 
Signed-off-by: Jaegeuk Kim 
---
 fs/crypto/keyinfo.c  | 278 +++
 include/linux/fscrypto.h |  16 +++
 2 files changed, 294 insertions(+)
 create mode 100644 fs/crypto/keyinfo.c

diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
new file mode 100644
index 000..cb61842
--- /dev/null
+++ b/fs/crypto/keyinfo.c
@@ -0,0 +1,278 @@
+/*
+ * key management facility for FS encryption support.
+ *
+ * Copyright (C) 2015, Google, Inc.
+ *
+ * This contains encryption key functions.
+ *
+ * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static void derive_crypt_complete(struct crypto_async_request *req, int rc)
+{
+   struct fscrypt_completion_result *ecr = req->data;
+
+   if (rc == -EINPROGRESS)
+   return;
+
+   ecr->res = rc;
+   complete(>completion);
+}
+
+/**
+ * derive_key_aes() - Derive a key using AES-128-ECB
+ * @deriving_key: Encryption key used for derivation.
+ * @source_key:   Source key to which to apply derivation.
+ * @derived_key:  Derived key.
+ *
+ * Return: Zero on success; non-zero otherwise.
+ */
+static int derive_key_aes(u8 deriving_key[FS_AES_128_ECB_KEY_SIZE],
+   u8 source_key[FS_AES_256_XTS_KEY_SIZE],
+   u8 derived_key[FS_AES_256_XTS_KEY_SIZE])
+{
+   int res = 0;
+   struct ablkcipher_request *req = NULL;
+   DECLARE_FS_COMPLETION_RESULT(ecr);
+   struct scatterlist src_sg, dst_sg;
+   struct crypto_ablkcipher *tfm = crypto_alloc_ablkcipher("ecb(aes)", 0,
+   0);
+
+   if (IS_ERR(tfm)) {
+   res = PTR_ERR(tfm);
+   tfm = NULL;
+   goto out;
+   }
+   crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+   req = ablkcipher_request_alloc(tfm, GFP_NOFS);
+   if (!req) {
+   res = -ENOMEM;
+   goto out;
+   }
+   ablkcipher_request_set_callback(req,
+   CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
+   derive_crypt_complete, );
+   res = crypto_ablkcipher_setkey(tfm, deriving_key,
+   FS_AES_128_ECB_KEY_SIZE);
+   if (res < 0)
+   goto out;
+
+   sg_init_one(_sg, source_key, FS_AES_256_XTS_KEY_SIZE);
+   sg_init_one(_sg, derived_key, FS_AES_256_XTS_KEY_SIZE);
+   ablkcipher_request_set_crypt(req, _sg, _sg,
+   FS_AES_256_XTS_KEY_SIZE, NULL);
+   res = crypto_ablkcipher_encrypt(req);
+   if (res == -EINPROGRESS || res == -EBUSY) {
+   wait_for_completion();
+   res = ecr.res;
+   }
+out:
+   if (req)
+   ablkcipher_request_free(req);
+   if (tfm)
+   crypto_free_ablkcipher(tfm);
+   return res;
+}
+
+static void put_crypt_info(struct fscrypt_info *ci)
+{
+   if (!ci)
+   return;
+
+   if (ci->ci_keyring_key)
+   key_put(ci->ci_keyring_key);
+   crypto_free_ablkcipher(ci->ci_ctfm);
+   kmem_cache_free(fscrypt_info_cachep, ci);
+}
+
+int get_crypt_info(struct inode *inode)
+{
+   struct fscrypt_info *crypt_info;
+   u8 full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
+   (FS_KEY_DESCRIPTOR_SIZE * 2) + 1];
+   struct key *keyring_key = NULL;
+   struct fscrypt_key *master_key;
+   struct fscrypt_context ctx;
+   const struct user_key_payload *ukp;
+   struct crypto_ablkcipher *ctfm;
+   const char *cipher_str;
+   u8 raw_key[FS_MAX_KEY_SIZE];
+   u8 mode;
+   int res;
+
+   res = fscrypt_initialize();
+   if (res)
+   return res;
+
+   if (!inode->i_sb->s_cop->get_context)
+   return -EOPNOTSUPP;
+retry:
+   crypt_info = ACCESS_ONCE(inode->i_crypt_info);
+   if (crypt_info) {
+   if (!crypt_info->ci_keyring_key ||
+   key_validate(crypt_info->ci_keyring_key) == 0)
+   return 0;
+   fscrypt_put_encryption_info(inode, crypt_info);
+   goto retry;
+   }
+
+   res = inode->i_sb->s_cop->get_context(inode, , sizeof(ctx));
+   if (res < 0) {
+   if (!fscrypt_dummy_context_enabled(inode))
+   return res;
+   ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
+   ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
+   ctx.flags = 0;
+   } 

[f2fs-dev] [PATCH 04/10] fs crypto: add keyinfo.c to handle permissions

2016-02-25 Thread Jaegeuk Kim
This patch adds keyinfo.c supporting key management.

 - fscrypt_get_encryption_info
 - fscrypt_free_encryption_info

Signed-off-by: Michael Halcrow 
Signed-off-by: Ildar Muslukhov 
Signed-off-by: Theodore Ts'o 
Signed-off-by: Jaegeuk Kim 
---
 fs/crypto/keyinfo.c  | 278 +++
 include/linux/fscrypto.h |  22 
 2 files changed, 300 insertions(+)
 create mode 100644 fs/crypto/keyinfo.c

diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
new file mode 100644
index 000..c662103
--- /dev/null
+++ b/fs/crypto/keyinfo.c
@@ -0,0 +1,278 @@
+/*
+ * key management facility for FS encryption support.
+ *
+ * Copyright (C) 2015, Google, Inc.
+ *
+ * This contains encryption key functions.
+ *
+ * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static void derive_crypt_complete(struct crypto_async_request *req, int rc)
+{
+   struct fscrypt_completion_result *ecr = req->data;
+
+   if (rc == -EINPROGRESS)
+   return;
+
+   ecr->res = rc;
+   complete(>completion);
+}
+
+/**
+ * derive_key_aes() - Derive a key using AES-128-ECB
+ * @deriving_key: Encryption key used for derivation.
+ * @source_key:   Source key to which to apply derivation.
+ * @derived_key:  Derived key.
+ *
+ * Return: Zero on success; non-zero otherwise.
+ */
+static int derive_key_aes(char deriving_key[FS_AES_128_ECB_KEY_SIZE],
+   char source_key[FS_AES_256_XTS_KEY_SIZE],
+   char derived_key[FS_AES_256_XTS_KEY_SIZE])
+{
+   int res = 0;
+   struct ablkcipher_request *req = NULL;
+   DECLARE_FS_COMPLETION_RESULT(ecr);
+   struct scatterlist src_sg, dst_sg;
+   struct crypto_ablkcipher *tfm = crypto_alloc_ablkcipher("ecb(aes)", 0,
+   0);
+
+   if (IS_ERR(tfm)) {
+   res = PTR_ERR(tfm);
+   tfm = NULL;
+   goto out;
+   }
+   crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);
+   req = ablkcipher_request_alloc(tfm, GFP_NOFS);
+   if (!req) {
+   res = -ENOMEM;
+   goto out;
+   }
+   ablkcipher_request_set_callback(req,
+   CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
+   derive_crypt_complete, );
+   res = crypto_ablkcipher_setkey(tfm, deriving_key,
+   FS_AES_128_ECB_KEY_SIZE);
+   if (res < 0)
+   goto out;
+
+   sg_init_one(_sg, source_key, FS_AES_256_XTS_KEY_SIZE);
+   sg_init_one(_sg, derived_key, FS_AES_256_XTS_KEY_SIZE);
+   ablkcipher_request_set_crypt(req, _sg, _sg,
+   FS_AES_256_XTS_KEY_SIZE, NULL);
+   res = crypto_ablkcipher_encrypt(req);
+   if (res == -EINPROGRESS || res == -EBUSY) {
+   wait_for_completion();
+   res = ecr.res;
+   }
+out:
+   if (req)
+   ablkcipher_request_free(req);
+   if (tfm)
+   crypto_free_ablkcipher(tfm);
+   return res;
+}
+
+static void put_crypt_info(struct fscrypt_info *ci)
+{
+   if (!ci)
+   return;
+
+   if (ci->ci_keyring_key)
+   key_put(ci->ci_keyring_key);
+   crypto_free_ablkcipher(ci->ci_ctfm);
+   kmem_cache_free(fscrypt_info_cachep, ci);
+}
+
+int get_crypt_info(struct inode *inode)
+{
+   struct fscrypt_info *crypt_info;
+   char full_key_descriptor[FS_KEY_DESC_PREFIX_SIZE +
+   (FS_KEY_DESCRIPTOR_SIZE * 2) + 1];
+   struct key *keyring_key = NULL;
+   struct fscrypt_key *master_key;
+   struct fscrypt_context ctx;
+   const struct user_key_payload *ukp;
+   struct crypto_ablkcipher *ctfm;
+   const char *cipher_str;
+   char raw_key[FS_MAX_KEY_SIZE];
+   char mode;
+   int res;
+
+   res = fscrypt_initialize();
+   if (res)
+   return res;
+
+   if (!inode->i_sb->s_cop->get_context)
+   return -EOPNOTSUPP;
+retry:
+   crypt_info = ACCESS_ONCE(inode->i_crypt_info);
+   if (crypt_info) {
+   if (!crypt_info->ci_keyring_key ||
+   key_validate(crypt_info->ci_keyring_key) == 0)
+   return 0;
+   fscrypt_put_encryption_info(inode, crypt_info);
+   goto retry;
+   }
+
+   res = inode->i_sb->s_cop->get_context(inode, , sizeof(ctx));
+   if (res < 0) {
+   if (!fscrypt_dummy_context_enabled(inode))
+   return res;
+   ctx.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
+   ctx.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
+   ctx.flags = 0;