diff options
Diffstat (limited to 'fs/ecryptfs/crypto.c')
| -rw-r--r-- | fs/ecryptfs/crypto.c | 141 | 
1 files changed, 101 insertions, 40 deletions
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index d5c25db4398f..f71ec125290d 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -243,7 +243,7 @@ void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)  	struct ecryptfs_key_sig *key_sig, *key_sig_tmp;  	if (crypt_stat->tfm) -		crypto_free_blkcipher(crypt_stat->tfm); +		crypto_free_ablkcipher(crypt_stat->tfm);  	if (crypt_stat->hash_tfm)  		crypto_free_hash(crypt_stat->hash_tfm);  	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,  	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   * @crypt_stat: Pointer to the crypt_stat struct to initialize. @@ -334,11 +350,8 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,  			       struct scatterlist *src_sg, int size,  			       unsigned char *iv)  { -	struct blkcipher_desc desc = { -		.tfm = crypt_stat->tfm, -		.info = iv, -		.flags = CRYPTO_TFM_REQ_MAY_SLEEP -	}; +	struct ablkcipher_request *req = NULL; +	struct extent_crypt_result ecr;  	int rc = 0;  	BUG_ON(!crypt_stat || !crypt_stat->tfm @@ -349,24 +362,47 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,  		ecryptfs_dump_hex(crypt_stat->key,  				  crypt_stat->key_size);  	} -	/* Consider doing this once, when the file is opened */ + +	init_completion(&ecr.completion); +  	mutex_lock(&crypt_stat->cs_tfm_mutex); -	if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { -		rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, -					     crypt_stat->key_size); -		crypt_stat->flags |= ECRYPTFS_KEY_SET; -	} -	if (rc) { -		ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", -				rc); +	req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); +	if (!req) {  		mutex_unlock(&crypt_stat->cs_tfm_mutex); -		rc = -EINVAL; +		rc = -ENOMEM;  		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); +	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: +	ablkcipher_request_free(req);  	return rc;  } @@ -624,35 +660,61 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,  			       struct scatterlist *src_sg, int size,  			       unsigned char *iv)  { -	struct blkcipher_desc desc = { -		.tfm = crypt_stat->tfm, -		.info = iv, -		.flags = CRYPTO_TFM_REQ_MAY_SLEEP -	}; +	struct ablkcipher_request *req = NULL; +	struct extent_crypt_result ecr;  	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); -	rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, -				     crypt_stat->key_size); -	if (rc) { -		ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", -				rc); +	req = ablkcipher_request_alloc(crypt_stat->tfm, GFP_NOFS); +	if (!req) {  		mutex_unlock(&crypt_stat->cs_tfm_mutex); -		rc = -EINVAL; +		rc = -ENOMEM;  		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); -	if (rc) { -		ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n", -				rc); -		goto out; +	ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size); +	ablkcipher_request_set_crypt(req, src_sg, dest_sg, size, iv); +	rc = crypto_ablkcipher_decrypt(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);  	} -	rc = size;  out: +	ablkcipher_request_free(req);  	return rc; +  }  /** @@ -746,8 +808,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)  						    crypt_stat->cipher, "cbc");  	if (rc)  		goto out_unlock; -	crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0, -						 CRYPTO_ALG_ASYNC); +	crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0);  	kfree(full_alg_name);  	if (IS_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)  				crypt_stat->cipher);  		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;  out_unlock:  	mutex_unlock(&crypt_stat->cs_tfm_mutex);  |