Skip to contentSkip to conversation

Enable GCM support in eCryptfs

RFC In review Will Morrison 2 participants 2 messages Jan 18, 2014 – Jan 22, 2014 Ecrypt file system

lore
Share & tools
lore
#0 lore raw

RFC 3/3 Enable GCM support in eCryptfs

This patch adds support for GCM as a cipher mode in eCryptfs. If a file is encrypted in this mode, the layout of the lower file will change to accomodate it. This is due to the need to store auth tags as well as encrypted data.

The file layout being used is as follows. After the header, the first extent will hold auth tags. After this auth tag extent, data extents are written until the first auth tag extent becomes full, at which point another auth tag extent is created, and subsequent data extents have auth tags stored in that new extent until it fills up, etc. The last extent in the file should always be a data extent, except in the case of a zero length upper file, in which case it is the header. This makes it so that the lower file will never have a case where it needs to move extents around or have large gaps in the file.

---
 fs/ecryptfs/Kconfig           |    1 +
 fs/ecryptfs/crypto.c          |  342 ++++++++++++++++++++++++++++++++++++-----
 fs/ecryptfs/ecryptfs_kernel.h |    3 +-
 fs/ecryptfs/inode.c           |   12 +-
 fs/ecryptfs/main.c            |    2 +-
 fs/ecryptfs/mmap.c            |    1 -
 fs/ecryptfs/super.c           |    3 +
 include/linux/ecryptfs.h      |    1 +
 8 files changed, 319 insertions(+), 46 deletions(-)
fs/ecryptfs/Kconfig +1 -0
index 434aa31..b11e555 100644
@@ -4,6 +4,7 @@ config ECRYPT_FS
 	select CRYPTO_ECB
 	select CRYPTO_CBC
 	select CRYPTO_MD5
+	select CRYPTO_GCM
 	help
 	  Encrypted filesystem that operates on the VFS layer.  See
 	  <file:Documentation/filesystems/ecryptfs.txt> to learn more about
fs/ecryptfs/crypto.c +300 -42

514 lines not on this page · raw message

fs/ecryptfs/ecryptfs_kernel.h +2 -1
index 392f710..2d227e4 100644
@@ -129,6 +129,7 @@ ecryptfs_get_key_payload_data(struct key *key)
 #define ECRYPTFS_MAX_NUM_ENC_KEYS 64
 #define ECRYPTFS_MAX_IV_BYTES 16	/* 128 bits */
 #define ECRYPTFS_SALT_BYTES 2
+#define ECRYPTFS_GCM_TAG_SIZE 16
 #define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
 #define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8	/* 4*2 */
 #define ECRYPTFS_FILE_SIZE_BYTES (sizeof(u64))
@@ -236,7 +237,7 @@ struct ecryptfs_crypt_stat {
 	size_t extent_shift;
 	unsigned int extent_mask;
 	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
-	struct crypto_ablkcipher *tfm;
+	struct crypto_tfm *tfm;
 	struct crypto_hash *hash_tfm; /* Crypto context for generating
 				       * the initialization vectors */
 	unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
fs/ecryptfs/inode.c +11 -1
index 87ad33e..41cd682 100644
@@ -720,6 +720,8 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
 			 loff_t upper_size)
 {
 	loff_t lower_size;
+	int mode_code = ecryptfs_code_for_cipher_mode_string(
+			crypt_stat->cipher_mode);
 
 	lower_size = ecryptfs_lower_header_size(crypt_stat);
 	if (upper_size != 0) {
@@ -728,7 +730,15 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
 		num_extents = upper_size >> crypt_stat->extent_shift;
 		if (upper_size & ~crypt_stat->extent_mask)
 			num_extents++;
-		lower_size += (num_extents * crypt_stat->extent_size);
+
+		if (mode_code == ECRYPTFS_CIPHER_MODE_GCM) {
+			lower_size +=
+				(num_extents + ((num_extents + 255) >> 8)) *
+				crypt_stat->extent_size;
+		} else {
+			lower_size += num_extents * crypt_stat->extent_size;
+
+		}
 	}
 	return lower_size;
 }
fs/ecryptfs/main.c +1 -1
index 0e912f7..7c087ef 100644
@@ -260,7 +260,7 @@ static void ecryptfs_init_mount_crypt_stat(
 static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
 				  uid_t *check_ruid)
 {
-	const char *mode_white_list[] = {"cbc"};
+	const char *mode_white_list[] = {"cbc", "gcm"};
 	char *p;
 	int i = 0;
 	int rc = 0;
fs/ecryptfs/mmap.c +0 -1
index 564a1fa..5e9acbd 100644
@@ -163,7 +163,6 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
 			loff_t lower_offset =
 				((view_extent_num * crypt_stat->extent_size)
 				 - crypt_stat->metadata_size);
-
 			rc = ecryptfs_read_lower_page_segment(
 				page, (lower_offset >> PAGE_CACHE_SHIFT),
 				(lower_offset & ~PAGE_CACHE_MASK),
fs/ecryptfs/super.c +3 -0
index e879cf8..54d61f9 100644
@@ -164,6 +164,9 @@ static int ecryptfs_show_options(struct seq_file *m, struct dentry *root)
 	seq_printf(m, ",ecryptfs_cipher=%s",
 		mount_crypt_stat->global_default_cipher_name);
 
+	seq_printf(m, ",ecryptfs_cipher_mode=%s",
+		mount_crypt_stat->global_default_cipher_mode_name);
+
 	if (mount_crypt_stat->global_default_cipher_key_size)
 		seq_printf(m, ",ecryptfs_key_bytes=%zd",
 			   mount_crypt_stat->global_default_cipher_key_size);
include/linux/ecryptfs.h +1 -0
index 8244e03..770ee13 100644
@@ -45,6 +45,7 @@
 #define RFC2440_CIPHER_RSA 0x01
 
 #define ECRYPTFS_CIPHER_MODE_CBC 0x01
+#define ECRYPTFS_CIPHER_MODE_GCM 0x02
 
 /**
  * For convenience, we may need to pass around the encrypted session
Signature · 1 line
1.7.10.4
#1 lore raw
Quoted 4 lines · Will Morrison

This patch adds support for GCM as a cipher mode in eCryptfs. If a file is encrypted in this mode, the layout of the lower file will change to accomodate it. This is due to the need to store auth tags as well as encrypted data.

Using a stream cipher mode like GCM without choosing a new random IV for every write will destroy eCryptfs's security.

In GCM, the ciphertext is simply XORed with a key stream generated by encrypting a counter. This means that the first time you write an extent, you get:

ciphertext1 = keystream ^ plaintext1

The second time you write to that extent (without changing the IV, which I believe is not done), you get:

ciphertext2 = keystream ^ plaintext2

An attacker can XOR ciphertext1 with ciphertext2 to get:

ciphertext1 ^ ciphertext2 = plaintext1 ^ plaintext2

Which reveals them lots of information about the plaintext. Other disk encryption software all use block modes like CBC-ESSIV or XTS to prevent this.

See also the "Security Audit" thread.

Signature · 1 line
Taylor Hornby