Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8bba066f authored by Michael Halcrow's avatar Michael Halcrow Committed by Linus Torvalds
Browse files

[PATCH] eCryptfs: Cipher code to new crypto API



Update cipher block encryption code to the new crypto API.

Signed-off-by: default avatarMichael Halcrow <mhalcrow@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 565d9724
Loading
Loading
Loading
Loading
+71 −21
Original line number Diff line number Diff line
@@ -123,6 +123,28 @@ static int ecryptfs_calculate_md5(char *dst,
	return rc;
}

int ecryptfs_crypto_api_algify_cipher_name(char **algified_name,
					   char *cipher_name,
					   char *chaining_modifier)
{
	int cipher_name_len = strlen(cipher_name);
	int chaining_modifier_len = strlen(chaining_modifier);
	int algified_name_len;
	int rc;

	algified_name_len = (chaining_modifier_len + cipher_name_len + 3);
	(*algified_name) = kmalloc(algified_name_len, GFP_KERNEL);
	if (!(algified_name)) {
		rc = -ENOMEM;
		goto out;
	}
	snprintf((*algified_name), algified_name_len, "%s(%s)",
		 chaining_modifier, cipher_name);
	rc = 0;
out:
	return rc;
}

/**
 * ecryptfs_derive_iv
 * @iv: destination for the derived iv vale
@@ -197,7 +219,7 @@ ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
{
	if (crypt_stat->tfm)
		crypto_free_tfm(crypt_stat->tfm);
		crypto_free_blkcipher(crypt_stat->tfm);
	if (crypt_stat->hash_tfm)
		crypto_free_hash(crypt_stat->hash_tfm);
	memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
@@ -209,7 +231,7 @@ void ecryptfs_destruct_mount_crypt_stat(
	if (mount_crypt_stat->global_auth_tok_key)
		key_put(mount_crypt_stat->global_auth_tok_key);
	if (mount_crypt_stat->global_key_tfm)
		crypto_free_tfm(mount_crypt_stat->global_key_tfm);
		crypto_free_blkcipher(mount_crypt_stat->global_key_tfm);
	memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat));
}

@@ -275,6 +297,11 @@ 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
	};
	int rc = 0;

	BUG_ON(!crypt_stat || !crypt_stat->tfm
@@ -288,7 +315,7 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
	}
	/* Consider doing this once, when the file is opened */
	mutex_lock(&crypt_stat->cs_tfm_mutex);
	rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key,
	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",
@@ -298,7 +325,7 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
		goto out;
	}
	ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
	crypto_cipher_encrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size, iv);
	crypto_blkcipher_encrypt_iv(&desc, dest_sg, src_sg, size);
	mutex_unlock(&crypt_stat->cs_tfm_mutex);
out:
	return rc;
@@ -681,11 +708,16 @@ 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
	};
	int rc = 0;

	/* Consider doing this once, when the file is opened */
	mutex_lock(&crypt_stat->cs_tfm_mutex);
	rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key,
	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",
@@ -695,8 +727,7 @@ static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
		goto out;
	}
	ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
	rc = crypto_cipher_decrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size,
				      iv);
	rc = crypto_blkcipher_decrypt_iv(&desc, dest_sg, src_sg, size);
	mutex_unlock(&crypt_stat->cs_tfm_mutex);
	if (rc) {
		ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n",
@@ -765,6 +796,7 @@ ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
 */
int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
{
	char *full_alg_name;
	int rc = -EINVAL;

	if (!crypt_stat->cipher) {
@@ -781,16 +813,24 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
		goto out;
	}
	mutex_lock(&crypt_stat->cs_tfm_mutex);
	crypt_stat->tfm = crypto_alloc_tfm(crypt_stat->cipher,
					   ECRYPTFS_DEFAULT_CHAINING_MODE
					   | CRYPTO_TFM_REQ_WEAK_KEY);
	mutex_unlock(&crypt_stat->cs_tfm_mutex);
	rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name,
						    crypt_stat->cipher, "cbc");
	if (rc)
		goto out;
	crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0,
						 CRYPTO_ALG_ASYNC);
	kfree(full_alg_name);
	if (!crypt_stat->tfm) {
		ecryptfs_printk(KERN_ERR, "cryptfs: init_crypt_ctx(): "
				"Error initializing cipher [%s]\n",
				crypt_stat->cipher);
		mutex_unlock(&crypt_stat->cs_tfm_mutex);
		goto out;
	}
	crypto_blkcipher_set_flags(crypt_stat->tfm,
				   (ECRYPTFS_DEFAULT_CHAINING_MODE
				    | CRYPTO_TFM_REQ_WEAK_KEY));
	mutex_unlock(&crypt_stat->cs_tfm_mutex);
	rc = 0;
out:
	return rc;
@@ -1588,10 +1628,11 @@ ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
 * event, regardless of whether this function succeeds for fails.
 */
int
ecryptfs_process_cipher(struct crypto_tfm **key_tfm, char *cipher_name,
ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name,
			size_t *key_size)
{
	char dummy_key[ECRYPTFS_MAX_KEY_BYTES];
	char *full_alg_name;
	int rc;

	*key_tfm = NULL;
@@ -1601,17 +1642,26 @@ ecryptfs_process_cipher(struct crypto_tfm **key_tfm, char *cipher_name,
		      "allowable is [%d]\n", *key_size, ECRYPTFS_MAX_KEY_BYTES);
		goto out;
	}
	*key_tfm = crypto_alloc_tfm(cipher_name, CRYPTO_TFM_REQ_WEAK_KEY);
	if (!(*key_tfm)) {
		rc = -EINVAL;
	rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name, cipher_name,
						    "ecb");
	if (rc)
		goto out;
	*key_tfm = crypto_alloc_blkcipher(full_alg_name, 0, CRYPTO_ALG_ASYNC);
	kfree(full_alg_name);
	if (IS_ERR(*key_tfm)) {
		rc = PTR_ERR(*key_tfm);
		printk(KERN_ERR "Unable to allocate crypto cipher with name "
		       "[%s]\n", cipher_name);
		       "[%s]; rc = [%d]\n", cipher_name, rc);
		goto out;
	}
	if (*key_size == 0)
		*key_size = crypto_tfm_alg_max_keysize(*key_tfm);
	crypto_blkcipher_set_flags(*key_tfm, CRYPTO_TFM_REQ_WEAK_KEY);
	if (*key_size == 0) {
		struct blkcipher_alg *alg = crypto_blkcipher_alg(*key_tfm);

		*key_size = alg->max_keysize;
	}
	get_random_bytes(dummy_key, *key_size);
	rc = crypto_cipher_setkey(*key_tfm, dummy_key, *key_size);
	rc = crypto_blkcipher_setkey(*key_tfm, dummy_key, *key_size);
	if (rc) {
		printk(KERN_ERR "Error attempting to set key of size [%Zd] for "
		       "cipher [%s]; rc = [%d]\n", *key_size, cipher_name, rc);
+6 −3
Original line number Diff line number Diff line
@@ -205,7 +205,7 @@ struct ecryptfs_crypt_stat {
	size_t extent_shift;
	unsigned int extent_mask;
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
	struct crypto_tfm *tfm;
	struct crypto_blkcipher *tfm;
	struct crypto_hash *hash_tfm; /* Crypto context for generating
				       * the initialization vectors */
	unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
@@ -245,7 +245,7 @@ struct ecryptfs_mount_crypt_stat {
	struct ecryptfs_auth_tok *global_auth_tok;
	struct key *global_auth_tok_key;
	size_t global_default_cipher_key_size;
	struct crypto_tfm *global_key_tfm;
	struct crypto_blkcipher *global_key_tfm;
	struct mutex global_key_tfm_mutex;
	unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE
						 + 1];
@@ -426,6 +426,9 @@ void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
void ecryptfs_destruct_mount_crypt_stat(
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);
int ecryptfs_crypto_api_algify_cipher_name(char **algified_name,
					   char *cipher_name,
					   char *chaining_modifier);
int ecryptfs_write_inode_size_to_header(struct file *lower_file,
					struct inode *lower_inode,
					struct inode *inode);
@@ -474,7 +477,7 @@ ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
			  unsigned char *src, struct dentry *ecryptfs_dentry);
int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
int
ecryptfs_process_cipher(struct crypto_tfm **key_tfm, char *cipher_name,
ecryptfs_process_cipher(struct crypto_blkcipher **key_tfm, char *cipher_name,
			size_t *key_size);
int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
+67 −34
Original line number Diff line number Diff line
@@ -458,14 +458,16 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents,
static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
			       struct ecryptfs_crypt_stat *crypt_stat)
{
	int rc = 0;
	struct ecryptfs_password *password_s_ptr;
	struct crypto_tfm *tfm = NULL;
	struct scatterlist src_sg[2], dst_sg[2];
	struct mutex *tfm_mutex = NULL;
	/* TODO: Use virt_to_scatterlist for these */
	char *encrypted_session_key;
	char *session_key;
	struct blkcipher_desc desc = {
		.flags = CRYPTO_TFM_REQ_MAY_SLEEP
	};
	int rc = 0;

	password_s_ptr = &auth_tok->token.password;
	if (ECRYPTFS_CHECK_FLAG(password_s_ptr->flags,
@@ -482,20 +484,30 @@ static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
	if (!strcmp(crypt_stat->cipher,
		    crypt_stat->mount_crypt_stat->global_default_cipher_name)
	    && crypt_stat->mount_crypt_stat->global_key_tfm) {
		tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
		desc.tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
		tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
	} else {
		tfm = crypto_alloc_tfm(crypt_stat->cipher,
				       CRYPTO_TFM_REQ_WEAK_KEY);
		if (!tfm) {
			printk(KERN_ERR "Error allocating crypto context\n");
			rc = -ENOMEM;
		char *full_alg_name;

		rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name,
							    crypt_stat->cipher,
							    "ecb");
		if (rc)
			goto out;
		desc.tfm = crypto_alloc_blkcipher(full_alg_name, 0,
						  CRYPTO_ALG_ASYNC);
		kfree(full_alg_name);
		if (IS_ERR(desc.tfm)) {
			rc = PTR_ERR(desc.tfm);
			printk(KERN_ERR "Error allocating crypto context; "
			       "rc = [%d]\n", rc);
			goto out;
		}
		crypto_blkcipher_set_flags(desc.tfm, CRYPTO_TFM_REQ_WEAK_KEY);
	}
	if (tfm_mutex)
		mutex_lock(tfm_mutex);
	rc = crypto_cipher_setkey(tfm,
	rc = crypto_blkcipher_setkey(desc.tfm,
				     password_s_ptr->session_key_encryption_key,
				     crypt_stat->key_size);
	if (rc < 0) {
@@ -528,9 +540,12 @@ static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
	auth_tok->session_key.decrypted_key_size =
	    auth_tok->session_key.encrypted_key_size;
	dst_sg[0].length = auth_tok->session_key.encrypted_key_size;
	/* TODO: Handle error condition */
	crypto_cipher_decrypt(tfm, dst_sg, src_sg,
	rc = crypto_blkcipher_decrypt(&desc, dst_sg, src_sg,
				      auth_tok->session_key.encrypted_key_size);
	if (rc) {
		printk(KERN_ERR "Error decrypting; rc = [%d]\n", rc);
		goto out_free_memory;
	}
	auth_tok->session_key.decrypted_key_size =
	    auth_tok->session_key.encrypted_key_size;
	memcpy(auth_tok->session_key.decrypted_key, session_key,
@@ -543,6 +558,7 @@ static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
	if (ecryptfs_verbosity > 0)
		ecryptfs_dump_hex(crypt_stat->key,
				  crypt_stat->key_size);
out_free_memory:
	memset(encrypted_session_key, 0, PAGE_CACHE_SIZE);
	free_page((unsigned long)encrypted_session_key);
	memset(session_key, 0, PAGE_CACHE_SIZE);
@@ -551,7 +567,7 @@ static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
	if (tfm_mutex)
		mutex_unlock(tfm_mutex);
	else
		crypto_free_tfm(tfm);
		crypto_free_blkcipher(desc.tfm);
out:
	return rc;
}
@@ -800,19 +816,21 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok,
		   struct ecryptfs_crypt_stat *crypt_stat,
		   struct ecryptfs_key_record *key_rec, size_t *packet_size)
{
	int rc = 0;

	size_t i;
	size_t signature_is_valid = 0;
	size_t encrypted_session_key_valid = 0;
	char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
	struct scatterlist dest_sg[2];
	struct scatterlist src_sg[2];
	struct crypto_tfm *tfm = NULL;
	struct mutex *tfm_mutex = NULL;
	size_t key_rec_size;
	size_t packet_size_length;
	size_t cipher_code;
	struct blkcipher_desc desc = {
		.tfm = NULL,
		.flags = CRYPTO_TFM_REQ_MAY_SLEEP
	};
	int rc = 0;

	(*packet_size) = 0;
	/* Check for a valid signature on the auth_tok */
@@ -879,33 +897,48 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok,
	if (!strcmp(crypt_stat->cipher,
		    crypt_stat->mount_crypt_stat->global_default_cipher_name)
	    && crypt_stat->mount_crypt_stat->global_key_tfm) {
		tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
		desc.tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
		tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
	} else
		tfm = crypto_alloc_tfm(crypt_stat->cipher, 0);
	if (!tfm) {
	} else {
		char *full_alg_name;

		rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name,
							    crypt_stat->cipher,
							    "ecb");
		if (rc)
			goto out;
		desc.tfm = crypto_alloc_blkcipher(full_alg_name, 0,
						  CRYPTO_ALG_ASYNC);
		kfree(full_alg_name);
		if (IS_ERR(desc.tfm)) {
			rc = PTR_ERR(desc.tfm);
			ecryptfs_printk(KERN_ERR, "Could not initialize crypto "
				"context for cipher [%s]\n",
				crypt_stat->cipher);
		rc = -EINVAL;
					"context for cipher [%s]; rc = [%d]\n",
					crypt_stat->cipher, rc);
			goto out;
		}
		crypto_blkcipher_set_flags(desc.tfm, CRYPTO_TFM_REQ_WEAK_KEY);
	}
	if (tfm_mutex)
		mutex_lock(tfm_mutex);
	rc = crypto_cipher_setkey(tfm, session_key_encryption_key,
	rc = crypto_blkcipher_setkey(desc.tfm, session_key_encryption_key,
				     crypt_stat->key_size);
	if (rc < 0) {
		if (tfm_mutex)
			mutex_unlock(tfm_mutex);
		ecryptfs_printk(KERN_ERR, "Error setting key for crypto "
				"context\n");
				"context; rc = [%d]\n", rc);
		goto out;
	}
	rc = 0;
	ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",
			crypt_stat->key_size);
	crypto_cipher_encrypt(tfm, dest_sg, src_sg,
	rc = crypto_blkcipher_encrypt(&desc, dest_sg, src_sg,
				      (*key_rec).enc_key_size);
	if (rc) {
		printk(KERN_ERR "Error encrypting; rc = [%d]\n", rc);
		goto out;
	}
	if (tfm_mutex)
		mutex_unlock(tfm_mutex);
	ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n");
@@ -968,8 +1001,8 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok,
	       (*key_rec).enc_key_size);
	(*packet_size) += (*key_rec).enc_key_size;
out:
	if (tfm && !tfm_mutex)
		crypto_free_tfm(tfm);
	if (desc.tfm && !tfm_mutex)
		crypto_free_blkcipher(desc.tfm);
	if (rc)
		(*packet_size) = 0;
	return rc;
+2 −0
Original line number Diff line number Diff line
@@ -315,6 +315,8 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options)
		       "with key size [%Zd] bytes; rc = [%d]\n",
		       mount_crypt_stat->global_default_cipher_name,
		       mount_crypt_stat->global_default_cipher_key_size, rc);
		mount_crypt_stat->global_key_tfm = NULL;
		mount_crypt_stat->global_auth_tok_key = NULL;
		rc = -EINVAL;
		goto out;
	}