Commit 9c79f34f authored by Michael Halcrow's avatar Michael Halcrow Committed by Linus Torvalds

eCryptfs: Filename Encryption: Tag 70 packets

This patchset implements filename encryption via a passphrase-derived
mount-wide Filename Encryption Key (FNEK) specified as a mount parameter.
Each encrypted filename has a fixed prefix indicating that eCryptfs should
try to decrypt the filename.  When eCryptfs encounters this prefix, it
decodes the filename into a tag 70 packet and then decrypts the packet
contents using the FNEK, setting the filename to the decrypted filename.
Both unencrypted and encrypted filenames can reside in the same lower
filesystem.

Because filename encryption expands the length of the filename during the
encoding stage, eCryptfs will not properly handle filenames that are
already near the maximum filename length.

In the present implementation, eCryptfs must be able to produce a match
against the lower encrypted and encoded filename representation when given
a plaintext filename.  Therefore, two files having the same plaintext name
will encrypt and encode into the same lower filename if they are both
encrypted using the same FNEK.  This can be changed by finding a way to
replace the prepended bytes in the blocked-aligned filename with random
characters; they are hashes of the FNEK right now, so that it is possible
to deterministically map from a plaintext filename to an encrypted and
encoded filename in the lower filesystem.  An implementation using random
characters will have to decode and decrypt every single directory entry in
any given directory any time an event occurs wherein the VFS needs to
determine whether a particular file exists in the lower directory and the
decrypted and decoded filenames have not yet been extracted for that
directory.

Thanks to Tyler Hicks and David Kleikamp for assistance in the development
of this patchset.

This patch:

A tag 70 packet contains a filename encrypted with a Filename Encryption
Key (FNEK).  This patch implements functions for writing and parsing tag
70 packets.  This patch also adds definitions and extends structures to
support filename encryption.
Signed-off-by: default avatarMichael Halcrow <mhalcrow@us.ibm.com>
Cc: Dustin Kirkland <dustin.kirkland@gmail.com>
Cc: Eric Sandeen <sandeen@redhat.com>
Cc: Tyler Hicks <tchicks@us.ibm.com>
Cc: David Kleikamp <shaggy@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 14bca6c3
...@@ -1149,19 +1149,20 @@ ecryptfs_cipher_code_str_map[] = { ...@@ -1149,19 +1149,20 @@ ecryptfs_cipher_code_str_map[] = {
/** /**
* ecryptfs_code_for_cipher_string * ecryptfs_code_for_cipher_string
* @crypt_stat: The cryptographic context * @cipher_name: The string alias for the cipher
* @key_bytes: Length of key in bytes; used for AES code selection
* *
* Returns zero on no match, or the cipher code on match * Returns zero on no match, or the cipher code on match
*/ */
u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat) u8 ecryptfs_code_for_cipher_string(char *cipher_name, size_t key_bytes)
{ {
int i; int i;
u8 code = 0; u8 code = 0;
struct ecryptfs_cipher_code_str_map_elem *map = struct ecryptfs_cipher_code_str_map_elem *map =
ecryptfs_cipher_code_str_map; ecryptfs_cipher_code_str_map;
if (strcmp(crypt_stat->cipher, "aes") == 0) { if (strcmp(cipher_name, "aes") == 0) {
switch (crypt_stat->key_size) { switch (key_bytes) {
case 16: case 16:
code = RFC2440_CIPHER_AES_128; code = RFC2440_CIPHER_AES_128;
break; break;
...@@ -1173,7 +1174,7 @@ u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat) ...@@ -1173,7 +1174,7 @@ u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
} }
} else { } else {
for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++) for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
if (strcmp(crypt_stat->cipher, map[i].cipher_str) == 0){ if (strcmp(cipher_name, map[i].cipher_str) == 0) {
code = map[i].cipher_code; code = map[i].cipher_code;
break; break;
} }
......
...@@ -199,6 +199,7 @@ ecryptfs_get_key_payload_data(struct key *key) ...@@ -199,6 +199,7 @@ ecryptfs_get_key_payload_data(struct key *key)
#define ECRYPTFS_DEFAULT_CIPHER "aes" #define ECRYPTFS_DEFAULT_CIPHER "aes"
#define ECRYPTFS_DEFAULT_KEY_BYTES 16 #define ECRYPTFS_DEFAULT_KEY_BYTES 16
#define ECRYPTFS_DEFAULT_HASH "md5" #define ECRYPTFS_DEFAULT_HASH "md5"
#define ECRYPTFS_TAG_70_DIGEST ECRYPTFS_DEFAULT_HASH
#define ECRYPTFS_TAG_1_PACKET_TYPE 0x01 #define ECRYPTFS_TAG_1_PACKET_TYPE 0x01
#define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C #define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C
#define ECRYPTFS_TAG_11_PACKET_TYPE 0xED #define ECRYPTFS_TAG_11_PACKET_TYPE 0xED
...@@ -206,7 +207,25 @@ ecryptfs_get_key_payload_data(struct key *key) ...@@ -206,7 +207,25 @@ ecryptfs_get_key_payload_data(struct key *key)
#define ECRYPTFS_TAG_65_PACKET_TYPE 0x41 #define ECRYPTFS_TAG_65_PACKET_TYPE 0x41
#define ECRYPTFS_TAG_66_PACKET_TYPE 0x42 #define ECRYPTFS_TAG_66_PACKET_TYPE 0x42
#define ECRYPTFS_TAG_67_PACKET_TYPE 0x43 #define ECRYPTFS_TAG_67_PACKET_TYPE 0x43
#define ECRYPTFS_TAG_70_PACKET_TYPE 0x46 /* FNEK-encrypted filename
* as dentry name */
#define ECRYPTFS_TAG_71_PACKET_TYPE 0x47 /* FNEK-encrypted filename in
* metadata */
#define ECRYPTFS_TAG_72_PACKET_TYPE 0x48 /* FEK-encrypted filename as
* dentry name */
#define ECRYPTFS_TAG_73_PACKET_TYPE 0x49 /* FEK-encrypted filename as
* metadata */
/* Constraint: ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES >=
* ECRYPTFS_MAX_IV_BYTES */
#define ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES 16
#define ECRYPTFS_NON_NULL 0x42 /* A reasonable substitute for NULL */
#define MD5_DIGEST_SIZE 16 #define MD5_DIGEST_SIZE 16
#define ECRYPTFS_TAG_70_DIGEST_SIZE MD5_DIGEST_SIZE
#define ECRYPTFS_FEK_ENCRYPTED_FILENAME_PREFIX "ECRYPTFS_FEK_ENCRYPTED."
#define ECRYPTFS_FEK_ENCRYPTED_FILENAME_PREFIX_SIZE 23
#define ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX "ECRYPTFS_FNEK_ENCRYPTED."
#define ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE 24
#define ECRYPTFS_ENCRYPTED_DENTRY_NAME_LEN (18 + 1 + 4 + 1 + 32)
struct ecryptfs_key_sig { struct ecryptfs_key_sig {
struct list_head crypt_stat_list; struct list_head crypt_stat_list;
...@@ -332,13 +351,20 @@ struct ecryptfs_mount_crypt_stat { ...@@ -332,13 +351,20 @@ struct ecryptfs_mount_crypt_stat {
#define ECRYPTFS_XATTR_METADATA_ENABLED 0x00000002 #define ECRYPTFS_XATTR_METADATA_ENABLED 0x00000002
#define ECRYPTFS_ENCRYPTED_VIEW_ENABLED 0x00000004 #define ECRYPTFS_ENCRYPTED_VIEW_ENABLED 0x00000004
#define ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED 0x00000008 #define ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED 0x00000008
#define ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES 0x00000010
#define ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK 0x00000020
#define ECRYPTFS_GLOBAL_ENCFN_USE_FEK 0x00000040
u32 flags; u32 flags;
struct list_head global_auth_tok_list; struct list_head global_auth_tok_list;
struct mutex global_auth_tok_list_mutex; struct mutex global_auth_tok_list_mutex;
size_t num_global_auth_toks; size_t num_global_auth_toks;
size_t global_default_cipher_key_size; size_t global_default_cipher_key_size;
size_t global_default_fn_cipher_key_bytes;
unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE
+ 1]; + 1];
unsigned char global_default_fn_cipher_name[
ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];
char global_default_fnek_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
}; };
/* superblock private data. */ /* superblock private data. */
...@@ -599,7 +625,7 @@ int ecryptfs_read_and_validate_header_region(char *data, ...@@ -599,7 +625,7 @@ int ecryptfs_read_and_validate_header_region(char *data,
struct inode *ecryptfs_inode); struct inode *ecryptfs_inode);
int ecryptfs_read_and_validate_xattr_region(char *page_virt, int ecryptfs_read_and_validate_xattr_region(char *page_virt,
struct dentry *ecryptfs_dentry); struct dentry *ecryptfs_dentry);
u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat); u8 ecryptfs_code_for_cipher_string(char *cipher_name, size_t key_bytes);
int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code); int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code);
void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat); void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
int ecryptfs_generate_key_packet_set(char *dest_base, int ecryptfs_generate_key_packet_set(char *dest_base,
...@@ -694,5 +720,15 @@ int ecryptfs_privileged_open(struct file **lower_file, ...@@ -694,5 +720,15 @@ int ecryptfs_privileged_open(struct file **lower_file,
struct vfsmount *lower_mnt, struct vfsmount *lower_mnt,
const struct cred *cred); const struct cred *cred);
int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry); int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry);
int
ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,
size_t *packet_size,
struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
char *filename, size_t filename_size);
int
ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,
size_t *packet_size,
struct ecryptfs_mount_crypt_stat *mount_crypt_stat,
char *data, size_t max_packet_size);
#endif /* #ifndef ECRYPTFS_KERNEL_H */ #endif /* #ifndef ECRYPTFS_KERNEL_H */
This diff is collapsed.
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