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

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
...@@ -66,6 +66,7 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx, ...@@ -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, ...@@ -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, ...@@ -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( ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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;
......
...@@ -110,6 +110,7 @@ int ext4_generate_encryption_key(struct inode *inode) ...@@ -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))
......
...@@ -37,6 +37,8 @@ static int ext4_is_encryption_context_consistent_with_policy( ...@@ -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( ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -911,6 +911,7 @@ struct ext4_inode_info { ...@@ -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;
......
...@@ -20,12 +20,20 @@ struct ext4_encryption_policy { ...@@ -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 { ...@@ -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 { ...@@ -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;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment