All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Monakhov <dmonlist@gmail.com>
To: Theodore Ts'o <tytso@mit.edu>,
	Ext4 Developers List <linux-ext4@vger.kernel.org>
Cc: mhalcrow@google.com, Ildar Muslukhov <muslukhovi@gmail.com>,
	Theodore Ts'o <tytso@mit.edu>
Subject: Re: [PATCH-v2 08/20] ext4 crypto: add encryption key management facilities
Date: Wed, 27 May 2015 16:39:57 +0300	[thread overview]
Message-ID: <87382im95e.fsf@openvz.org> (raw)
In-Reply-To: <1428894996-7852-9-git-send-email-tytso@mit.edu>

Theodore Ts'o <tytso@mit.edu> writes:

> From: Michael Halcrow <mhalcrow@google.com>
>
> Change-Id: I0cb5711a628554d3b05cefd15740d8346115cbaa
> Signed-off-by: Michael Halcrow <mhalcrow@google.com>
> Signed-off-by: Ildar Muslukhov <muslukhovi@gmail.com>
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Hi, hope that it is not too late for discussion minor things

I'm wondering whenever derivation key algo (AEC-CBC) is too weak because allow
 attacker get master key once attacker find key for any inode in a filesystem.
 IMHO sane key derivation should be done via HMAC (HMACSHA256) or any
 other one direction procedure. 

Read file connect w/o key. 
   Currently this is prohibited which breaks a lot of applications. For
   example my backup scenario looks like rsync like script which copy
   content of home directory to some archive. Script has no
   access to my keys, so encrypted files will be backed-up. This is bad.
   IMHO it is reasonable to allow to read content of the file even w/o key but
   return encrypted content (as it is stored on disk). This is very
   similar to what we do with filenames. AFAIU this will no break our
   security assumptions 'steal once' because even if attacker has access
   to several versions of the encrypted file this simply equals to
   several files with same ctx.nonce (effectively equals encrypted file
   with size = sum of all files)
   If everybody are ok with that I'll send a draft patch.
> ---
>  fs/ext4/Makefile      |   2 +-
>  fs/ext4/crypto_key.c  | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/ext4/ext4.h        |  13 ++++
>  fs/ext4/ext4_crypto.h |   3 +
>  4 files changed, 179 insertions(+), 1 deletion(-)
>  create mode 100644 fs/ext4/crypto_key.c
>
> diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
> index 1b1c561..4e5af21 100644
> --- a/fs/ext4/Makefile
> +++ b/fs/ext4/Makefile
> @@ -12,4 +12,4 @@ ext4-y	:= balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
>  
>  ext4-$(CONFIG_EXT4_FS_POSIX_ACL)	+= acl.o
>  ext4-$(CONFIG_EXT4_FS_SECURITY)		+= xattr_security.o
> -ext4-$(CONFIG_EXT4_FS_ENCRYPTION)	+= crypto_policy.o crypto.o
> +ext4-$(CONFIG_EXT4_FS_ENCRYPTION)	+= crypto_policy.o crypto.o crypto_key.o
> diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c
> new file mode 100644
> index 0000000..572bd97
> --- /dev/null
> +++ b/fs/ext4/crypto_key.c
> @@ -0,0 +1,162 @@
> +/*
> + * linux/fs/ext4/crypto_key.c
> + *
> + * Copyright (C) 2015, Google, Inc.
> + *
> + * This contains encryption key functions for ext4
> + *
> + * Written by Michael Halcrow, Ildar Muslukhov, and Uday Savagaonkar, 2015.
> + */
> +
> +#include <keys/encrypted-type.h>
> +#include <keys/user-type.h>
> +#include <linux/random.h>
> +#include <linux/scatterlist.h>
> +#include <uapi/linux/keyctl.h>
> +
> +#include "ext4.h"
> +#include "xattr.h"
> +
> +static void derive_crypt_complete(struct crypto_async_request *req, int rc)
> +{
> +	struct ext4_completion_result *ecr = req->data;
> +
> +	if (rc == -EINPROGRESS)
> +		return;
> +
> +	ecr->res = rc;
> +	complete(&ecr->completion);
> +}
> +
> +/**
> + * ext4_derive_key_aes() - Derive a key using AES-128-ECB
> + * @deriving_key: Encryption key used for derivatio.
> + * @source_key:   Source key to which to apply derivation.
> + * @derived_key:  Derived key.
> + *
> + * Return: Zero on success; non-zero otherwise.
> + */
> +static int ext4_derive_key_aes(char deriving_key[EXT4_AES_128_ECB_KEY_SIZE],
> +			       char source_key[EXT4_AES_256_XTS_KEY_SIZE],
> +			       char derived_key[EXT4_AES_256_XTS_KEY_SIZE])
> +{
> +	int res = 0;
> +	struct ablkcipher_request *req = NULL;
> +	DECLARE_EXT4_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, &ecr);
> +	res = crypto_ablkcipher_setkey(tfm, deriving_key,
> +				       EXT4_AES_128_ECB_KEY_SIZE);
> +	if (res < 0)
> +		goto out;
> +	sg_init_one(&src_sg, source_key, EXT4_AES_256_XTS_KEY_SIZE);
> +	sg_init_one(&dst_sg, derived_key, EXT4_AES_256_XTS_KEY_SIZE);
> +	ablkcipher_request_set_crypt(req, &src_sg, &dst_sg,
> +				     EXT4_AES_256_XTS_KEY_SIZE, NULL);
> +	res = crypto_ablkcipher_encrypt(req);
> +	if (res == -EINPROGRESS || res == -EBUSY) {
> +		BUG_ON(req->base.data != &ecr);
> +		wait_for_completion(&ecr.completion);
> +		res = ecr.res;
> +	}
> +
> +out:
> +	if (req)
> +		ablkcipher_request_free(req);
> +	if (tfm)
> +		crypto_free_ablkcipher(tfm);
> +	return res;
> +}
> +
> +/**
> + * ext4_generate_encryption_key() - generates an encryption key
> + * @inode: The inode to generate the encryption key for.
> + */
> +int ext4_generate_encryption_key(struct inode *inode)
> +{
> +	struct ext4_inode_info *ei = EXT4_I(inode);
> +	struct ext4_encryption_key *crypt_key = &ei->i_encryption_key;
> +	char full_key_descriptor[EXT4_KEY_DESC_PREFIX_SIZE +
> +				 (EXT4_KEY_DESCRIPTOR_SIZE * 2) + 1];
> +	struct key *keyring_key = NULL;
> +	struct ext4_encryption_key *master_key;
> +	struct ext4_encryption_context ctx;
> +	struct user_key_payload *ukp;
> +	int res = ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION,
> +				 EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
> +				 &ctx, sizeof(ctx));
> +
> +	if (res != sizeof(ctx)) {
> +		if (res > 0)
> +			res = -EINVAL;
> +		goto out;
> +	}
> +	res = 0;
> +
> +	memcpy(full_key_descriptor, EXT4_KEY_DESC_PREFIX,
> +	       EXT4_KEY_DESC_PREFIX_SIZE);
> +	sprintf(full_key_descriptor + EXT4_KEY_DESC_PREFIX_SIZE,
> +		"%*phN", EXT4_KEY_DESCRIPTOR_SIZE,
> +		ctx.master_key_descriptor);
> +	full_key_descriptor[EXT4_KEY_DESC_PREFIX_SIZE +
> +			    (2 * EXT4_KEY_DESCRIPTOR_SIZE)] = '\0';
> +	keyring_key = request_key(&key_type_logon, full_key_descriptor, NULL);
> +	if (IS_ERR(keyring_key)) {
> +		res = PTR_ERR(keyring_key);
> +		keyring_key = NULL;
> +		goto out;
> +	}
> +	BUG_ON(keyring_key->type != &key_type_logon);
> +	ukp = ((struct user_key_payload *)keyring_key->payload.data);
> +	if (ukp->datalen != sizeof(struct ext4_encryption_key)) {
> +		res = -EINVAL;
> +		goto out;
> +	}
> +	master_key = (struct ext4_encryption_key *)ukp->data;
> +
> +	if (S_ISREG(inode->i_mode))
> +		crypt_key->mode = ctx.contents_encryption_mode;
> +	else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
> +		crypt_key->mode = ctx.filenames_encryption_mode;
> +	else {
> +		printk(KERN_ERR "ext4 crypto: Unsupported inode type.\n");
> +		BUG();
> +	}
> +	crypt_key->size = ext4_encryption_key_size(crypt_key->mode);
> +	BUG_ON(!crypt_key->size);
> +	BUILD_BUG_ON(EXT4_AES_128_ECB_KEY_SIZE !=
> +		     EXT4_KEY_DERIVATION_NONCE_SIZE);
> +	BUG_ON(master_key->size != EXT4_AES_256_XTS_KEY_SIZE);
> +	BUG_ON(crypt_key->size < EXT4_AES_256_CBC_KEY_SIZE);
> +	res = ext4_derive_key_aes(ctx.nonce, master_key->raw, crypt_key->raw);
> +out:
> +	if (keyring_key)
> +		key_put(keyring_key);
> +	if (res < 0)
> +		crypt_key->mode = EXT4_ENCRYPTION_MODE_INVALID;
> +	return res;
> +}
> +
> +int ext4_has_encryption_key(struct inode *inode)
> +{
> +	struct ext4_inode_info *ei = EXT4_I(inode);
> +	struct ext4_encryption_key *crypt_key = &ei->i_encryption_key;
> +
> +	return (crypt_key->mode != EXT4_ENCRYPTION_MODE_INVALID);
> +}
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index c4a51636..89b999f 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -2065,6 +2065,19 @@ static inline int ext4_sb_has_crypto(struct super_block *sb)
>  }
>  #endif
>  
> +/* crypto_key.c */
> +int ext4_generate_encryption_key(struct inode *inode);
> +
> +#ifdef CONFIG_EXT4_FS_ENCRYPTION
> +int ext4_has_encryption_key(struct inode *inode);
> +#else
> +static inline int ext4_has_encryption_key(struct inode *inode)
> +{
> +	return 0;
> +}
> +#endif
> +
> +
>  /* dir.c */
>  extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
>  				  struct file *,
> diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h
> index 9d5d2e5..6a7c0c0 100644
> --- a/fs/ext4/ext4_crypto.h
> +++ b/fs/ext4/ext4_crypto.h
> @@ -55,6 +55,9 @@ struct ext4_encryption_context {
>  #define EXT4_AES_256_XTS_KEY_SIZE 64
>  #define EXT4_MAX_KEY_SIZE 64
>  
> +#define EXT4_KEY_DESC_PREFIX "ext4:"
> +#define EXT4_KEY_DESC_PREFIX_SIZE 5
> +
>  struct ext4_encryption_key {
>  	uint32_t mode;
>  	char raw[EXT4_MAX_KEY_SIZE];
> -- 
> 2.3.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2015-05-27 13:42 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-13  3:16 [PATCH-v2 00/20] ext4 encryption patches Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 01/20] ext4 crypto: add ext4_mpage_readpages() Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 02/20] ext4 crypto: reserve codepoints used by the ext4 encryption feature Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 03/20] ext4 crypto: add ext4 encryption Kconfig Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 04/20] ext4 crypto: export ext4_empty_dir() Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 05/20] ext4 crypto: add encryption xattr support Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 06/20] ext4 crypto: add encryption policy and password salt support Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 07/20] ext4 crypto: add ext4 encryption facilities Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 08/20] ext4 crypto: add encryption key management facilities Theodore Ts'o
2015-05-27 13:39   ` Dmitry Monakhov [this message]
2015-05-27 17:06     ` Theodore Ts'o
2015-05-27 18:37       ` Theodore Ts'o
2015-05-29 17:55         ` Dmitry Monakhov
2015-05-29 18:12           ` Dmitry Monakhov
2015-05-29 20:03           ` Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 09/20] ext4 crypto: validate context consistency on lookup Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 10/20] ext4 crypto: inherit encryption policies on inode and directory create Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 11/20] ext4 crypto: implement the ext4 encryption write path Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 12/20] ext4 crypto: implement the ext4 decryption read path Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 13/20] ext4 crypto: filename encryption facilities Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 14/20] ext4 crypto: teach ext4_htree_store_dirent() to store decrypted filenames Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 15/20] ext4 crypto: insert encrypted filenames into a leaf directory block Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 16/20] ext4 crypto: partial update to namei.c for fname crypto Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 17/20] ext4 crypto: filename encryption modifications Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 18/20] ext4 crypto: enable filename encryption Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 19/20] ext4 crypto: Add symlink encryption Theodore Ts'o
2015-04-13  3:16 ` [PATCH-v2 20/20] ext4 crypto: enable encryption feature flag Theodore Ts'o

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87382im95e.fsf@openvz.org \
    --to=dmonlist@gmail.com \
    --cc=linux-ext4@vger.kernel.org \
    --cc=mhalcrow@google.com \
    --cc=muslukhovi@gmail.com \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.