Skip to content

Commit

Permalink
ext4 crypto: add padding to filenames before encrypting
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Theodore Ts'o committed May 1, 2015
1 parent 5de0b4d commit a44cd7a
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 8 deletions.
12 changes: 10 additions & 2 deletions fs/ext4/crypto_fname.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,15 @@ 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)
return -EIO;

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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -468,13 +471,15 @@ 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;
if (!(ctx->has_valid_key))
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;
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions fs/ext4/crypto_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
14 changes: 9 additions & 5 deletions fs/ext4/crypto_policy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ==
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions fs/ext4/ext4.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 10 additions & 1 deletion fs/ext4/ext4_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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__));
Expand Down Expand Up @@ -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;
};
Expand Down

0 comments on commit a44cd7a

Please sign in to comment.