Commit 4dfea4f0 authored by Tyler Hicks's avatar Tyler Hicks

eCryptfs: Use the ablkcipher crypto API

Make the switch from the blkcipher kernel crypto interface to the
ablkcipher interface.

encrypt_scatterlist() and decrypt_scatterlist() now use the ablkcipher
interface but, from the eCryptfs standpoint, still treat the crypto
operation as a synchronous operation. They submit the async request and
then wait until the operation is finished before they return. Most of
the changes are contained inside those two functions.

Despite waiting for the completion of the crypto operation, the
ablkcipher interface provides performance increases in most cases when
used on AES-NI capable hardware.
Signed-off-by: default avatarTyler Hicks <tyhicks@canonical.com>
Acked-by: default avatarColin King <colin.king@canonical.com>
Reviewed-by: default avatarZeev Zilberman <zeev@annapurnaLabs.com>
Cc: Dustin Kirkland <dustin.kirkland@gazzang.com>
Cc: Tim Chen <tim.c.chen@intel.com>
Cc: Ying Huang <ying.huang@intel.com>
Cc: Thieu Le <thieule@google.com>
Cc: Li Wang <dragonylffly@163.com>
Cc: Jarkko Sakkinen <jarkko.sakkinen@iki.fi>
parent c1be5a5b
...@@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) ...@@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
struct ecryptfs_key_sig *key_sig, *key_sig_tmp; struct ecryptfs_key_sig *key_sig, *key_sig_tmp;
if (crypt_stat->tfm) if (crypt_stat->tfm)
crypto_free_blkcipher(crypt_stat->tfm); crypto_free_ablkcipher(crypt_stat->tfm);
if (crypt_stat->hash_tfm) if (crypt_stat->hash_tfm)
crypto_free_hash(crypt_stat->hash_tfm); crypto_free_hash(crypt_stat->hash_tfm);
list_for_each_entry_safe(key_sig, key_sig_tmp, list_for_each_entry_safe(key_sig, key_sig_tmp,
...@@ -319,6 +319,22 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg, ...@@ -319,6 +319,22 @@ int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
return i; return i;
} }
struct extent_crypt_result {
struct completion completion;
int rc;
};
static void extent_crypt_complete(struct crypto_async_request *req, int rc)
{
struct extent_crypt_result *ecr = req->data;
if (rc == -EINPROGRESS)
return;
ecr->rc = rc;
complete(&ecr->completion);
}
/** /**
* encrypt_scatterlist * encrypt_scatterlist
* @crypt_stat: Pointer to the crypt_stat struct to initialize. * @crypt_stat: Pointer to the crypt_stat struct to initialize.
...@@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, ...@@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
struct scatterlist *src_sg, int size, struct scatterlist *src_sg, int size,
unsigned char *iv) unsigned char *iv)
{ {
struct blkcipher_desc desc = { struct ablkcipher_request *req = NULL;
.tfm = crypt_stat->tfm, struct extent_crypt_result ecr;
.info = iv,
.flags = CRYPTO_TFM_REQ_MAY_SLEEP
};
int rc = 0; int rc = 0;
BUG_ON(!crypt_stat || !crypt_stat->tfm BUG_ON(!crypt_stat || !crypt_stat->tfm
...@@ -349,24 +362,47 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, ...@@ -349,24 +362,47 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
ecryptfs_dump_hex(crypt_stat->key, ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size); crypt_stat->key_size);
} }
/* Consider doing this once, when the file is opened */
init_completion(&ecr.completion);
mutex_lock(&crypt_stat->cs_tfm_mutex); mutex_lock(&crypt_stat->cs_tfm_mutex);
if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS);
rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, if (!req) {
crypt_stat->key_size);
crypt_stat->flags |= ECRYPTFS_KEY_SET;
}
if (rc) {
ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
rc);
mutex_unlock(&crypt_stat->cs_tfm_mutex); mutex_unlock(&crypt_stat->cs_tfm_mutex);
rc = -EINVAL; rc = -ENOMEM;
goto out; goto out;
} }
ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size); ablkcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
extent_crypt_complete, &ecr);
/* Consider doing this once, when the file is opened */
if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
crypt_stat->key_size);
if (rc) {
ecryptfs_printk(KERN_ERR,
"Error setting key; rc = [%d]\n",
rc);
mutex_unlock(&crypt_stat->cs_tfm_mutex);
rc = -EINVAL;
goto out;
}
crypt_stat->flags |= ECRYPTFS_KEY_SET;
}
mutex_unlock(&crypt_stat->cs_tfm_mutex); mutex_unlock(&crypt_stat->cs_tfm_mutex);
ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv);
rc = crypto_ablkcipher_encrypt(req);
if (rc == -EINPROGRESS || rc == -EBUSY) {
struct extent_crypt_result *ecr = req->base.data;
wait_for_completion(&ecr->completion);
rc = ecr->rc;
INIT_COMPLETION(ecr->completion);
}
out: out:
ablkcipher_request_free(req);
return rc; return rc;
} }
...@@ -624,35 +660,61 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, ...@@ -624,35 +660,61 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
struct scatterlist *src_sg, int size, struct scatterlist *src_sg, int size,
unsigned char *iv) unsigned char *iv)
{ {
struct blkcipher_desc desc = { struct ablkcipher_request *req = NULL;
.tfm = crypt_stat->tfm, struct extent_crypt_result ecr;
.info = iv,
.flags = CRYPTO_TFM_REQ_MAY_SLEEP
};
int rc = 0; int rc = 0;
/* Consider doing this once, when the file is opened */ BUG_ON(!crypt_stat || !crypt_stat->tfm
|| !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED));
if (unlikely(ecryptfs_verbosity > 0)) {
ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n",
crypt_stat->key_size);
ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size);
}
init_completion(&ecr.completion);
mutex_lock(&crypt_stat->cs_tfm_mutex); mutex_lock(&crypt_stat->cs_tfm_mutex);
rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS);
crypt_stat->key_size); if (!req) {
if (rc) {
ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
rc);
mutex_unlock(&crypt_stat->cs_tfm_mutex); mutex_unlock(&crypt_stat->cs_tfm_mutex);
rc = -EINVAL; rc = -ENOMEM;
goto out; goto out;
} }
ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size); ablkcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
extent_crypt_complete, &ecr);
/* Consider doing this once, when the file is opened */
if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
crypt_stat->key_size);
if (rc) {
ecryptfs_printk(KERN_ERR,
"Error setting key; rc = [%d]\n",
rc);
mutex_unlock(&crypt_stat->cs_tfm_mutex);
rc = -EINVAL;
goto out;
}
crypt_stat->flags |= ECRYPTFS_KEY_SET;
}
mutex_unlock(&crypt_stat->cs_tfm_mutex); mutex_unlock(&crypt_stat->cs_tfm_mutex);
if (rc) { ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv);
rc); rc = crypto_ablkcipher_decrypt(req);
goto out; if (rc == -EINPROGRESS || rc == -EBUSY) {
struct extent_crypt_result *ecr = req->base.data;
wait_for_completion(&ecr->completion);
rc = ecr->rc;
INIT_COMPLETION(ecr->completion);
} }
rc = size;
out: out:
ablkcipher_request_free(req);
return rc; return rc;
} }
/** /**
...@@ -746,8 +808,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) ...@@ -746,8 +808,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
crypt_stat->cipher, "cbc"); crypt_stat->cipher, "cbc");
if (rc) if (rc)
goto out_unlock; goto out_unlock;
crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0);
CRYPTO_ALG_ASYNC);
kfree(full_alg_name); kfree(full_alg_name);
if (IS_ERR(crypt_stat->tfm)) { if (IS_ERR(crypt_stat->tfm)) {
rc = PTR_ERR(crypt_stat->tfm); rc = PTR_ERR(crypt_stat->tfm);
...@@ -757,7 +818,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) ...@@ -757,7 +818,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
crypt_stat->cipher); crypt_stat->cipher);
goto out_unlock; goto out_unlock;
} }
crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY);
rc = 0; rc = 0;
out_unlock: out_unlock:
mutex_unlock(&crypt_stat->cs_tfm_mutex); mutex_unlock(&crypt_stat->cs_tfm_mutex);
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/ecryptfs.h> #include <linux/ecryptfs.h>
#include <linux/crypto.h>
#define ECRYPTFS_DEFAULT_IV_BYTES 16 #define ECRYPTFS_DEFAULT_IV_BYTES 16
#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
...@@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat { ...@@ -233,7 +234,7 @@ struct ecryptfs_crypt_stat {
size_t extent_shift; size_t extent_shift;
unsigned int extent_mask; unsigned int extent_mask;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat; struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
struct crypto_blkcipher *tfm; struct crypto_ablkcipher *tfm;
struct crypto_hash *hash_tfm; /* Crypto context for generating struct crypto_hash *hash_tfm; /* Crypto context for generating
* the initialization vectors */ * the initialization vectors */
unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE]; unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment