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

Commit a44cd7a0 authored by Theodore Ts'o's avatar Theodore Ts'o
Browse files

ext4 crypto: add padding to filenames before encrypting



This obscures the length of the filenames, to decrease the amount of
information leakage.  By default, we pad the filenames to the next 4
byte boundaries.  This costs nothing, since the directory entries are
aligned to 4 byte boundaries anyway.  Filenames can also be padded to
8, 16, or 32 bytes, which will consume more directory space.

Change-Id: Ibb7a0fb76d2c48e2061240a709358ff40b14f322
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent 5de0b4d0
Loading
Loading
Loading
Loading
+10 −2
Original line number Original line Diff line number Diff line
@@ -66,6 +66,7 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
	int res = 0;
	int res = 0;
	char iv[EXT4_CRYPTO_BLOCK_SIZE];
	char iv[EXT4_CRYPTO_BLOCK_SIZE];
	struct scatterlist sg[1];
	struct scatterlist sg[1];
	int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);
	char *workbuf;
	char *workbuf;


	if (iname->len <= 0 || iname->len > ctx->lim)
	if (iname->len <= 0 || iname->len > ctx->lim)
@@ -73,6 +74,7 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,


	ciphertext_len = (iname->len < EXT4_CRYPTO_BLOCK_SIZE) ?
	ciphertext_len = (iname->len < EXT4_CRYPTO_BLOCK_SIZE) ?
		EXT4_CRYPTO_BLOCK_SIZE : iname->len;
		EXT4_CRYPTO_BLOCK_SIZE : iname->len;
	ciphertext_len = ext4_fname_crypto_round_up(ciphertext_len, padding);
	ciphertext_len = (ciphertext_len > ctx->lim)
	ciphertext_len = (ciphertext_len > ctx->lim)
			? ctx->lim : ciphertext_len;
			? ctx->lim : ciphertext_len;


@@ -101,7 +103,7 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
	/* Create encryption request */
	/* Create encryption request */
	sg_init_table(sg, 1);
	sg_init_table(sg, 1);
	sg_set_page(sg, ctx->workpage, PAGE_SIZE, 0);
	sg_set_page(sg, ctx->workpage, PAGE_SIZE, 0);
	ablkcipher_request_set_crypt(req, sg, sg, iname->len, iv);
	ablkcipher_request_set_crypt(req, sg, sg, ciphertext_len, iv);
	res = crypto_ablkcipher_encrypt(req);
	res = crypto_ablkcipher_encrypt(req);
	if (res == -EINPROGRESS || res == -EBUSY) {
	if (res == -EINPROGRESS || res == -EBUSY) {
		BUG_ON(req->base.data != &ecr);
		BUG_ON(req->base.data != &ecr);
@@ -356,6 +358,7 @@ struct ext4_fname_crypto_ctx *ext4_get_fname_crypto_ctx(
	if (IS_ERR(ctx))
	if (IS_ERR(ctx))
		return ctx;
		return ctx;


	ctx->flags = ei->i_crypt_policy_flags;
	if (ctx->has_valid_key) {
	if (ctx->has_valid_key) {
		if (ctx->key.mode != EXT4_ENCRYPTION_MODE_AES_256_CTS) {
		if (ctx->key.mode != EXT4_ENCRYPTION_MODE_AES_256_CTS) {
			printk_once(KERN_WARNING
			printk_once(KERN_WARNING
@@ -468,6 +471,7 @@ int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
				      u32 namelen)
				      u32 namelen)
{
{
	u32 ciphertext_len;
	u32 ciphertext_len;
	int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);


	if (ctx == NULL)
	if (ctx == NULL)
		return -EIO;
		return -EIO;
@@ -475,6 +479,7 @@ int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
		return -EACCES;
		return -EACCES;
	ciphertext_len = (namelen < EXT4_CRYPTO_BLOCK_SIZE) ?
	ciphertext_len = (namelen < EXT4_CRYPTO_BLOCK_SIZE) ?
		EXT4_CRYPTO_BLOCK_SIZE : namelen;
		EXT4_CRYPTO_BLOCK_SIZE : namelen;
	ciphertext_len = ext4_fname_crypto_round_up(ciphertext_len, padding);
	ciphertext_len = (ciphertext_len > ctx->lim)
	ciphertext_len = (ciphertext_len > ctx->lim)
			? ctx->lim : ciphertext_len;
			? ctx->lim : ciphertext_len;
	return (int) ciphertext_len;
	return (int) ciphertext_len;
@@ -490,10 +495,13 @@ int ext4_fname_crypto_alloc_buffer(struct ext4_fname_crypto_ctx *ctx,
				   u32 ilen, struct ext4_str *crypto_str)
				   u32 ilen, struct ext4_str *crypto_str)
{
{
	unsigned int olen;
	unsigned int olen;
	int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);


	if (!ctx)
	if (!ctx)
		return -EIO;
		return -EIO;
	olen = ext4_fname_crypto_round_up(ilen, EXT4_CRYPTO_BLOCK_SIZE);
	if (padding < EXT4_CRYPTO_BLOCK_SIZE)
		padding = EXT4_CRYPTO_BLOCK_SIZE;
	olen = ext4_fname_crypto_round_up(ilen, padding);
	crypto_str->len = olen;
	crypto_str->len = olen;
	if (olen < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2)
	if (olen < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2)
		olen = EXT4_FNAME_CRYPTO_DIGEST_SIZE*2;
		olen = EXT4_FNAME_CRYPTO_DIGEST_SIZE*2;
+1 −0
Original line number Original line Diff line number Diff line
@@ -110,6 +110,7 @@ int ext4_generate_encryption_key(struct inode *inode)
	}
	}
	res = 0;
	res = 0;


	ei->i_crypt_policy_flags = ctx.flags;
	if (S_ISREG(inode->i_mode))
	if (S_ISREG(inode->i_mode))
		crypt_key->mode = ctx.contents_encryption_mode;
		crypt_key->mode = ctx.contents_encryption_mode;
	else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
	else if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
+9 −5
Original line number Original line Diff line number Diff line
@@ -37,6 +37,8 @@ static int ext4_is_encryption_context_consistent_with_policy(
		return 0;
		return 0;
	return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
	return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
			EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
			EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
		(ctx.flags ==
		 policy->flags) &&
		(ctx.contents_encryption_mode ==
		(ctx.contents_encryption_mode ==
		 policy->contents_encryption_mode) &&
		 policy->contents_encryption_mode) &&
		(ctx.filenames_encryption_mode ==
		(ctx.filenames_encryption_mode ==
@@ -56,25 +58,25 @@ static int ext4_create_encryption_context_from_policy(
		printk(KERN_WARNING
		printk(KERN_WARNING
		       "%s: Invalid contents encryption mode %d\n", __func__,
		       "%s: Invalid contents encryption mode %d\n", __func__,
			policy->contents_encryption_mode);
			policy->contents_encryption_mode);
		res = -EINVAL;
		return -EINVAL;
		goto out;
	}
	}
	if (!ext4_valid_filenames_enc_mode(policy->filenames_encryption_mode)) {
	if (!ext4_valid_filenames_enc_mode(policy->filenames_encryption_mode)) {
		printk(KERN_WARNING
		printk(KERN_WARNING
		       "%s: Invalid filenames encryption mode %d\n", __func__,
		       "%s: Invalid filenames encryption mode %d\n", __func__,
			policy->filenames_encryption_mode);
			policy->filenames_encryption_mode);
		res = -EINVAL;
		return -EINVAL;
		goto out;
	}
	}
	if (policy->flags & ~EXT4_POLICY_FLAGS_VALID)
		return -EINVAL;
	ctx.contents_encryption_mode = policy->contents_encryption_mode;
	ctx.contents_encryption_mode = policy->contents_encryption_mode;
	ctx.filenames_encryption_mode = policy->filenames_encryption_mode;
	ctx.filenames_encryption_mode = policy->filenames_encryption_mode;
	ctx.flags = policy->flags;
	BUILD_BUG_ON(sizeof(ctx.nonce) != EXT4_KEY_DERIVATION_NONCE_SIZE);
	BUILD_BUG_ON(sizeof(ctx.nonce) != EXT4_KEY_DERIVATION_NONCE_SIZE);
	get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
	get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);


	res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
	res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
			     EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
			     EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
			     sizeof(ctx), 0);
			     sizeof(ctx), 0);
out:
	if (!res)
	if (!res)
		ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
		ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
	return res;
	return res;
@@ -115,6 +117,7 @@ int ext4_get_policy(struct inode *inode, struct ext4_encryption_policy *policy)
	policy->version = 0;
	policy->version = 0;
	policy->contents_encryption_mode = ctx.contents_encryption_mode;
	policy->contents_encryption_mode = ctx.contents_encryption_mode;
	policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
	policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
	policy->flags = ctx.flags;
	memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
	memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
	       EXT4_KEY_DESCRIPTOR_SIZE);
	       EXT4_KEY_DESCRIPTOR_SIZE);
	return 0;
	return 0;
@@ -176,6 +179,7 @@ int ext4_inherit_context(struct inode *parent, struct inode *child)
				EXT4_ENCRYPTION_MODE_AES_256_XTS;
				EXT4_ENCRYPTION_MODE_AES_256_XTS;
			ctx.filenames_encryption_mode =
			ctx.filenames_encryption_mode =
				EXT4_ENCRYPTION_MODE_AES_256_CTS;
				EXT4_ENCRYPTION_MODE_AES_256_CTS;
			ctx.flags = 0;
			memset(ctx.master_key_descriptor, 0x42,
			memset(ctx.master_key_descriptor, 0x42,
			       EXT4_KEY_DESCRIPTOR_SIZE);
			       EXT4_KEY_DESCRIPTOR_SIZE);
			res = 0;
			res = 0;
+1 −0
Original line number Original line Diff line number Diff line
@@ -911,6 +911,7 @@ struct ext4_inode_info {


	/* on-disk additional length */
	/* on-disk additional length */
	__u16 i_extra_isize;
	__u16 i_extra_isize;
	char i_crypt_policy_flags;


	/* Indicate the inline data space. */
	/* Indicate the inline data space. */
	u16 i_inline_off;
	u16 i_inline_off;
+10 −1
Original line number Original line Diff line number Diff line
@@ -20,12 +20,20 @@ struct ext4_encryption_policy {
	char version;
	char version;
	char contents_encryption_mode;
	char contents_encryption_mode;
	char filenames_encryption_mode;
	char filenames_encryption_mode;
	char flags;
	char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
	char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
} __attribute__((__packed__));
} __attribute__((__packed__));


#define EXT4_ENCRYPTION_CONTEXT_FORMAT_V1 1
#define EXT4_ENCRYPTION_CONTEXT_FORMAT_V1 1
#define EXT4_KEY_DERIVATION_NONCE_SIZE 16
#define EXT4_KEY_DERIVATION_NONCE_SIZE 16


#define EXT4_POLICY_FLAGS_PAD_4		0x00
#define EXT4_POLICY_FLAGS_PAD_8		0x01
#define EXT4_POLICY_FLAGS_PAD_16	0x02
#define EXT4_POLICY_FLAGS_PAD_32	0x03
#define EXT4_POLICY_FLAGS_PAD_MASK	0x03
#define EXT4_POLICY_FLAGS_VALID		0x03

/**
/**
 * Encryption context for inode
 * Encryption context for inode
 *
 *
@@ -41,7 +49,7 @@ struct ext4_encryption_context {
	char format;
	char format;
	char contents_encryption_mode;
	char contents_encryption_mode;
	char filenames_encryption_mode;
	char filenames_encryption_mode;
	char reserved;
	char flags;
	char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
	char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
	char nonce[EXT4_KEY_DERIVATION_NONCE_SIZE];
	char nonce[EXT4_KEY_DERIVATION_NONCE_SIZE];
} __attribute__((__packed__));
} __attribute__((__packed__));
@@ -120,6 +128,7 @@ struct ext4_fname_crypto_ctx {
	struct crypto_hash *htfm;
	struct crypto_hash *htfm;
	struct page *workpage;
	struct page *workpage;
	struct ext4_encryption_key key;
	struct ext4_encryption_key key;
	unsigned flags : 8;
	unsigned has_valid_key : 1;
	unsigned has_valid_key : 1;
	unsigned ctfm_key_is_ready : 1;
	unsigned ctfm_key_is_ready : 1;
};
};