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: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
parent
5de0b4d0cd
commit
a44cd7a054
|
@ -66,6 +66,7 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
|
|||
int res = 0;
|
||||
char iv[EXT4_CRYPTO_BLOCK_SIZE];
|
||||
struct scatterlist sg[1];
|
||||
int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);
|
||||
char *workbuf;
|
||||
|
||||
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) ?
|
||||
EXT4_CRYPTO_BLOCK_SIZE : iname->len;
|
||||
ciphertext_len = ext4_fname_crypto_round_up(ciphertext_len, padding);
|
||||
ciphertext_len = (ciphertext_len > ctx->lim)
|
||||
? ctx->lim : ciphertext_len;
|
||||
|
||||
|
@ -101,7 +103,7 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
|
|||
/* Create encryption request */
|
||||
sg_init_table(sg, 1);
|
||||
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);
|
||||
if (res == -EINPROGRESS || res == -EBUSY) {
|
||||
BUG_ON(req->base.data != &ecr);
|
||||
|
@ -356,6 +358,7 @@ struct ext4_fname_crypto_ctx *ext4_get_fname_crypto_ctx(
|
|||
if (IS_ERR(ctx))
|
||||
return ctx;
|
||||
|
||||
ctx->flags = ei->i_crypt_policy_flags;
|
||||
if (ctx->has_valid_key) {
|
||||
if (ctx->key.mode != EXT4_ENCRYPTION_MODE_AES_256_CTS) {
|
||||
printk_once(KERN_WARNING
|
||||
|
@ -468,6 +471,7 @@ int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
|
|||
u32 namelen)
|
||||
{
|
||||
u32 ciphertext_len;
|
||||
int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);
|
||||
|
||||
if (ctx == NULL)
|
||||
return -EIO;
|
||||
|
@ -475,6 +479,7 @@ int ext4_fname_crypto_namelen_on_disk(struct ext4_fname_crypto_ctx *ctx,
|
|||
return -EACCES;
|
||||
ciphertext_len = (namelen < EXT4_CRYPTO_BLOCK_SIZE) ?
|
||||
EXT4_CRYPTO_BLOCK_SIZE : namelen;
|
||||
ciphertext_len = ext4_fname_crypto_round_up(ciphertext_len, padding);
|
||||
ciphertext_len = (ciphertext_len > ctx->lim)
|
||||
? ctx->lim : 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)
|
||||
{
|
||||
unsigned int olen;
|
||||
int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);
|
||||
|
||||
if (!ctx)
|
||||
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;
|
||||
if (olen < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2)
|
||||
olen = EXT4_FNAME_CRYPTO_DIGEST_SIZE*2;
|
||||
|
|
|
@ -110,6 +110,7 @@ int ext4_generate_encryption_key(struct inode *inode)
|
|||
}
|
||||
res = 0;
|
||||
|
||||
ei->i_crypt_policy_flags = ctx.flags;
|
||||
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))
|
||||
|
|
|
@ -37,6 +37,8 @@ static int ext4_is_encryption_context_consistent_with_policy(
|
|||
return 0;
|
||||
return (memcmp(ctx.master_key_descriptor, policy->master_key_descriptor,
|
||||
EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
|
||||
(ctx.flags ==
|
||||
policy->flags) &&
|
||||
(ctx.contents_encryption_mode ==
|
||||
policy->contents_encryption_mode) &&
|
||||
(ctx.filenames_encryption_mode ==
|
||||
|
@ -56,25 +58,25 @@ static int ext4_create_encryption_context_from_policy(
|
|||
printk(KERN_WARNING
|
||||
"%s: Invalid contents encryption mode %d\n", __func__,
|
||||
policy->contents_encryption_mode);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!ext4_valid_filenames_enc_mode(policy->filenames_encryption_mode)) {
|
||||
printk(KERN_WARNING
|
||||
"%s: Invalid filenames encryption mode %d\n", __func__,
|
||||
policy->filenames_encryption_mode);
|
||||
res = -EINVAL;
|
||||
goto out;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (policy->flags & ~EXT4_POLICY_FLAGS_VALID)
|
||||
return -EINVAL;
|
||||
ctx.contents_encryption_mode = policy->contents_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);
|
||||
get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE);
|
||||
|
||||
res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION,
|
||||
EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx,
|
||||
sizeof(ctx), 0);
|
||||
out:
|
||||
if (!res)
|
||||
ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT);
|
||||
return res;
|
||||
|
@ -115,6 +117,7 @@ int ext4_get_policy(struct inode *inode, struct ext4_encryption_policy *policy)
|
|||
policy->version = 0;
|
||||
policy->contents_encryption_mode = ctx.contents_encryption_mode;
|
||||
policy->filenames_encryption_mode = ctx.filenames_encryption_mode;
|
||||
policy->flags = ctx.flags;
|
||||
memcpy(&policy->master_key_descriptor, ctx.master_key_descriptor,
|
||||
EXT4_KEY_DESCRIPTOR_SIZE);
|
||||
return 0;
|
||||
|
@ -176,6 +179,7 @@ int ext4_inherit_context(struct inode *parent, struct inode *child)
|
|||
EXT4_ENCRYPTION_MODE_AES_256_XTS;
|
||||
ctx.filenames_encryption_mode =
|
||||
EXT4_ENCRYPTION_MODE_AES_256_CTS;
|
||||
ctx.flags = 0;
|
||||
memset(ctx.master_key_descriptor, 0x42,
|
||||
EXT4_KEY_DESCRIPTOR_SIZE);
|
||||
res = 0;
|
||||
|
|
|
@ -911,6 +911,7 @@ struct ext4_inode_info {
|
|||
|
||||
/* on-disk additional length */
|
||||
__u16 i_extra_isize;
|
||||
char i_crypt_policy_flags;
|
||||
|
||||
/* Indicate the inline data space. */
|
||||
u16 i_inline_off;
|
||||
|
|
|
@ -20,12 +20,20 @@ struct ext4_encryption_policy {
|
|||
char version;
|
||||
char contents_encryption_mode;
|
||||
char filenames_encryption_mode;
|
||||
char flags;
|
||||
char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define EXT4_ENCRYPTION_CONTEXT_FORMAT_V1 1
|
||||
#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
|
||||
*
|
||||
|
@ -41,7 +49,7 @@ struct ext4_encryption_context {
|
|||
char format;
|
||||
char contents_encryption_mode;
|
||||
char filenames_encryption_mode;
|
||||
char reserved;
|
||||
char flags;
|
||||
char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE];
|
||||
char nonce[EXT4_KEY_DERIVATION_NONCE_SIZE];
|
||||
} __attribute__((__packed__));
|
||||
|
@ -120,6 +128,7 @@ struct ext4_fname_crypto_ctx {
|
|||
struct crypto_hash *htfm;
|
||||
struct page *workpage;
|
||||
struct ext4_encryption_key key;
|
||||
unsigned flags : 8;
|
||||
unsigned has_valid_key : 1;
|
||||
unsigned ctfm_key_is_ready : 1;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue