Re: [RFC][PATCH 5/6] encrypted-keys: add ecryptfs format support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2010-12-23 at 18:35 +0100, Roberto Sassu wrote:
> The 'encrypted' key type defines its own payload format which contains a
> symmetric key randomly generated that cannot be used directly to mount
> an eCryptfs filesystem, because it expects an authentication token
> structure.
> 
> This patch introduces the new format 'ecryptfs' that allows to store an
> authentication token structure inside the encrypted key payload containing
> a randomly generated symmetric key, as the same for the format 'default'.
> 
> More details about the usage of encrypted keys with the eCryptfs
> filesystem can be found in the file 'Documentation/keys-ecryptfs.txt'.
> 
> Signed-off-by: Roberto Sassu <roberto.sassu@xxxxxxxxx>
> ---
>  Documentation/keys-ecryptfs.txt          |   60 +++++++++++++++++++++
>  Documentation/keys-trusted-encrypted.txt |    6 ++-
>  security/keys/Makefile                   |    2 +-
>  security/keys/encrypted_defined.c        |   83 +++++++++++++++++++++++++++---
>  security/keys/keys_ecryptfs.c            |   81 +++++++++++++++++++++++++++++
>  security/keys/keys_ecryptfs.h            |   30 +++++++++++
>  6 files changed, 252 insertions(+), 10 deletions(-)
>  create mode 100644 Documentation/keys-ecryptfs.txt
>  create mode 100644 security/keys/keys_ecryptfs.c
>  create mode 100644 security/keys/keys_ecryptfs.h
> 
> diff --git a/Documentation/keys-ecryptfs.txt b/Documentation/keys-ecryptfs.txt
> new file mode 100644
> index 0000000..991d19f
> --- /dev/null
> +++ b/Documentation/keys-ecryptfs.txt
> @@ -0,0 +1,60 @@
> +ECryptfs is a stacked filesystem which transparently encrypts and decrypts each
> +file using a randomly generated File Encryption Key (FEK).
> +Each FEK is in turn encrypted with a File Encryption Key Encryption Key (FEFEK)
> +either in kernel space or in user space with a daemon called 'ecryptfsd'.  In
> +the former case the operation is performed directly by the kernel CryptoAPI
> +using a key, the FEFEK, derived from a user prompted passphrase;  in the latter
> +the FEK is encrypted by 'ecryptfsd' with the help of external libraries in order
> +to support other mechanisms like public key cryptography, PKCS#11 and TPM based
> +operations.

Missing initial title. You might also want to reformat the text, with
double blank lines between paragraphs.

> +The data structure defined by eCryptfs to contain information required for the
> +FEK decryption is called authentication token and, currently, can be stored in a
> +kernel key of the 'user' type, inserted in the user's session specific keyring
> +by the userspace utility 'mount.ecryptfs' shipped with the package
> +'ecryptfs-utils'.
> +The 'encrypted' key type has been extended with the introduction of the new
> +format 'ecryptfs' that identify keys containing an eCryptfs authentication token
> +structure and a FEFEK randomly generated by the kernel.
> +In order to avoid known-plaintext attacks, the datablob obtained through
> +commands 'keyctl print' or 'keyctl pipe' does not contain the overall
> +authentication token, which content is well known, but only the symmetric key in
> +encrypted form.
> +The eCryptfs filesystem may really benefit from using encrypted keys in that the
> +required key can be securely generated by an Administrator and provided at boot
> +time after the unsealing of a 'trusted' key in order to perform the mount in a
> +controlled environment.  Another advantage is that the key is not exposed to
> +threats of malicious software, because it is available in clear form only at
> +kernel level.
> +
> +Usage:
> +    keyctl add encrypted name "new ecryptfs key-type:master-key-name
> +        keylen" ring

The line probably doesn't need to be split like this. At minimum how
about keeping 'keylen' with previous line?

> +    keyctl add encrypted name "load hex_blob" ring
> +    keyctl update keyid "update key-type:master-key-name"
> +
> +name:= '<16 hexadecimal characters>'
> +key-type:= 'trusted' | 'user'
> +keylen:= 64
> +
> +
> +Example of encrypted key usage with the eCryptfs filesystem:
> +
> +Create an encrypted key "1000100010001000" of length 64 bytes with format
> +'ecryptfs' and save it using a previously loaded user key "test":
> +
> +    $ keyctl add encrypted 1000100010001000 "new ecryptfs user:test 64" @u
> +    19184530
> +
> +    $ keyctl print 19184530
> +    ecryptfs user:test 64 490045d4bfe48c99f0d465fbbbb79e7500da954178e2de0697
> +    dd85091f5450a0511219e9f7cd70dcd498038181466f78ac8d4c19504fcc72402bfc41c2
> +    f253a41b7507ccaa4b2b03fff19a69d1cc0b16e71746473f023a95488b6edfd86f7fdd40
> +    9d292e4bacded1258880122dd553a661
> +
> +    $ keyctl pipe 19184530 > ecryptfs.blob
> +
> +Mount an eCryptfs filesystem using the created encrypted key "1000100010001000"
> +into the '/secret' directory:
> +
> +    $ mount -i -t ecryptfs -oecryptfs_sig=1000100010001000,\
> +      ecryptfs_cipher=aes,ecryptfs_key_bytes=32 /secret /secret
> diff --git a/Documentation/keys-trusted-encrypted.txt b/Documentation/keys-trusted-encrypted.txt
> index 0afcb50..5f50cca 100644
> --- a/Documentation/keys-trusted-encrypted.txt
> +++ b/Documentation/keys-trusted-encrypted.txt
> @@ -63,7 +63,7 @@ Usage:
>      keyctl add encrypted name "load hex_blob" ring
>      keyctl update keyid "update key-type:master-key-name"
>  
> -format:= 'default'
> +format:= 'default | ecryptfs'
>  key-type:= 'trusted' | 'user'
>  
> 
> @@ -154,4 +154,6 @@ Load an encrypted key "evm" from saved blob:
>      24717c64 5972dcb82ab2dde83376d82b2e3c09ffc
>  
>  Other uses for trusted and encrypted keys, such as for disk and file encryption
> -are anticipated.
> +are anticipated.  In particular the new format 'ecryptfs' has been defined in
> +in order to use encrypted keys to mount an eCryptfs filesystem.  More details
> +about the usage can be found in the file 'Documentation/keys-ecryptfs.txt'.
> diff --git a/security/keys/Makefile b/security/keys/Makefile
> index 6c94105..c50b422 100644
> --- a/security/keys/Makefile
> +++ b/security/keys/Makefile
> @@ -14,7 +14,7 @@ obj-y := \
>  	user_defined.o
>  
>  obj-$(CONFIG_TRUSTED_KEYS) += trusted_defined.o
> -obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted_defined.o
> +obj-$(CONFIG_ENCRYPTED_KEYS) += keys_ecryptfs.o encrypted_defined.o
>  obj-$(CONFIG_KEYS_COMPAT) += compat.o
>  obj-$(CONFIG_PROC_FS) += proc.o
>  obj-$(CONFIG_SYSCTL) += sysctl.o
> diff --git a/security/keys/encrypted_defined.c b/security/keys/encrypted_defined.c
> index 7a914ab..1faf41f 100644
> --- a/security/keys/encrypted_defined.c
> +++ b/security/keys/encrypted_defined.c
> @@ -29,11 +29,13 @@
>  #include <linux/rcupdate.h>
>  #include <linux/scatterlist.h>
>  #include <linux/crypto.h>
> +#include <linux/ctype.h>
>  #include <crypto/hash.h>
>  #include <crypto/sha.h>
>  #include <crypto/aes.h>
>  
>  #include "encrypted_defined.h"
> +#include "keys_ecryptfs.h"
>  
>  static const char KEY_TRUSTED_PREFIX[] = "trusted:";
>  static const char KEY_USER_PREFIX[] = "user:";
> @@ -41,11 +43,13 @@ static const char hash_alg[] = "sha256";
>  static const char hmac_alg[] = "hmac(sha256)";
>  static const char blkcipher_alg[] = "cbc(aes)";
>  static const char key_format_default[] = "default";
> +static const char key_format_ecryptfs[] = "ecryptfs";
>  static unsigned int ivsize;
>  static int blksize;
>  
>  #define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
>  #define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
> +#define KEY_ECRYPTFS_DESC_LEN 16
>  #define HASH_SIZE SHA256_DIGEST_SIZE
>  #define MAX_DATA_SIZE 4096
>  #define MIN_DATA_SIZE  20
> @@ -63,11 +67,12 @@ enum {
>  };
>  
>  enum {
> -	Opt_error = -1, Opt_default
> +	Opt_error = -1, Opt_default, Opt_ecryptfs
>  };
>  
>  static const match_table_t key_format_tokens = {
>  	{Opt_default, "default"},
> +	{Opt_ecryptfs, "ecryptfs"},
>  	{Opt_error, NULL}
>  };
>  
> @@ -95,6 +100,42 @@ static int aes_get_sizes(void)
>  }
>  
>  /*
> + * valid_ecryptfs_desc - verify the description of a new/loaded encrypted key
> + *
> + * The description of a encrypted key with format 'ecryptfs' must contain
> + * exactly 16 hexadecimal characters.
> + *
> + */
> +static int valid_ecryptfs_desc(const char *ecryptfs_desc)
> +{
> +	int ret = 0;
> +	int i;
> +
> +	if (strlen(ecryptfs_desc) != KEY_ECRYPTFS_DESC_LEN) {
> +		pr_err("encrypted_key: key description must be %d hexadecimal "
> +		       "characters long\n", KEY_ECRYPTFS_DESC_LEN);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < KEY_ECRYPTFS_DESC_LEN; i++) {
> +		char ch = ecryptfs_desc[i];
> +
> +		if ((ch >= '0' && ch <= '9'))
> +			continue;
> +
> +		ch = tolower(ch);
> +		if ((ch >= 'a') && (ch <= 'f'))
> +			continue;
> +
> +		pr_err("encrypted_key: key description must contain only "
> +		       "hexadecimal characters\n");
> +		return -EINVAL;
> +	}

Could you use isxdigit() instead?

thanks,

Mimi

> +	return ret;
> +}
> +
> +/*
>   * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
>   *
>   * key-type:= "trusted:" | "user:"
> @@ -158,7 +199,7 @@ static int datablob_parse(char *datablob, const char **format,
>  	}
>  	key_cmd = match_token(keyword, key_tokens, args);
>  
> -	/* Get optional format: default */
> +	/* Get optional format: default | ecryptfs */
>  	p = strsep(&datablob, " \t");
>  	if (!p) {
>  		pr_err("encrypted_key: insufficient parameters specified\n");
> @@ -167,6 +208,7 @@ static int datablob_parse(char *datablob, const char **format,
>  
>  	key_format = match_token(p, key_format_tokens, args);
>  	switch (key_format) {
> +	case Opt_ecryptfs:
>  	case Opt_default:
>  		*format = p;
>  		*master_desc = strsep(&datablob, " \t");
> @@ -598,6 +640,17 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
>  	format_len = (!format) ? strlen(key_format_default) : strlen(format);
>  	decrypted_datalen = dlen;
>  	payload_datalen = decrypted_datalen;
> +	if (format && !strcmp(format, key_format_ecryptfs)) {
> +		if (dlen != ECRYPTFS_MAX_KEY_BYTES) {
> +			pr_err("encrypted_key: keylen for the ecryptfs format "
> +			       "must be equal to %d bytes\n",
> +			       ECRYPTFS_MAX_KEY_BYTES);
> +			return ERR_PTR(-EINVAL);
> +		}
> +		decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES;
> +		payload_datalen = sizeof(struct ecryptfs_auth_tok);
> +	}
> +
>  	encrypted_datalen = roundup(decrypted_datalen, blksize);
>  
>  	datablob_len = format_len + 1 + strlen(master_desc) + 1
> @@ -683,8 +736,14 @@ static void __ekey_init(struct encrypted_key_payload *epayload,
>  
>  	if (!format)
>  		memcpy(epayload->format, key_format_default, format_len);
> -	else
> +	else {
> +		if (!strcmp(format, key_format_ecryptfs))
> +			epayload->decrypted_data =
> +				ecryptfs_get_auth_tok_key((struct ecryptfs_auth_tok *)epayload->payload_data);
> +
>  		memcpy(epayload->format, format, format_len);
> +	}
> +
>  	memcpy(epayload->master_desc, master_desc, strlen(master_desc));
>  	memcpy(epayload->datalen, datalen, strlen(datalen));
>  }
> @@ -696,11 +755,21 @@ static void __ekey_init(struct encrypted_key_payload *epayload,
>   * itself.  For an old key, decrypt the hex encoded data.
>   */
>  static int encrypted_init(struct encrypted_key_payload *epayload,
> -			  const char *format, const char *master_desc,
> -			  const char *datalen, const char *hex_encoded_iv)
> +			  const char *key_desc, const char *format,
> +			  const char *master_desc, const char *datalen,
> +			  const char *hex_encoded_iv)
>  {
>  	int ret = 0;
>  
> +	if (format && !strcmp(format, key_format_ecryptfs)) {
> +		ret = valid_ecryptfs_desc(key_desc);
> +		if (ret < 0)
> +			return ret;
> +
> +		ecryptfs_fill_auth_tok((struct ecryptfs_auth_tok *)epayload->payload_data,
> +				       key_desc);
> +	}
> +
>  	__ekey_init(epayload, format, master_desc, datalen);
>  	if (!hex_encoded_iv) {
>  		get_random_bytes(epayload->iv, ivsize);
> @@ -750,8 +819,8 @@ static int encrypted_instantiate(struct key *key, const void *data,
>  		ret = PTR_ERR(epayload);
>  		goto out;
>  	}
> -	ret = encrypted_init(epayload, format, master_desc, decrypted_datalen,
> -			     hex_encoded_iv);
> +	ret = encrypted_init(epayload, key->description, format, master_desc,
> +			     decrypted_datalen, hex_encoded_iv);
>  	if (ret < 0) {
>  		kfree(epayload);
>  		goto out;
> diff --git a/security/keys/keys_ecryptfs.c b/security/keys/keys_ecryptfs.c
> new file mode 100644
> index 0000000..6144b91
> --- /dev/null
> +++ b/security/keys/keys_ecryptfs.c
> @@ -0,0 +1,81 @@
> +/*
> + * keys_ecryptfs.c: helper functions for the encrypted key type
> + *
> + * Copyright (C) 2006 International Business Machines Corp.
> + * Copyright (C) 2010 Politecnico di Torino, Italy
> + *                    TORSEC group -- http://security.polito.it
> + *
> + * Authors:
> + * Michael A. Halcrow <mahalcro@xxxxxxxxxx>
> + * Tyler Hicks <tyhicks@xxxxxx>
> + * Roberto Sassu <roberto.sassu@xxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, version 2 of the License.
> + */
> +
> +#include <linux/module.h>
> +#include "keys_ecryptfs.h"
> +
> +u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok)
> +{
> +	return auth_tok->token.password.session_key_encryption_key;
> +}
> +EXPORT_SYMBOL(ecryptfs_get_auth_tok_key);
> +
> +/*
> + * ecryptfs_get_versions()
> + *
> + * Source code taken from the software 'ecryptfs-utils' version 83.
> + *
> + */
> +void ecryptfs_get_versions(int *major, int *minor, int *file_version)
> +{
> +	*major = ECRYPTFS_VERSION_MAJOR;
> +	*minor = ECRYPTFS_VERSION_MINOR;
> +	if (file_version)
> +		*file_version = ECRYPTFS_SUPPORTED_FILE_VERSION;
> +}
> +EXPORT_SYMBOL(ecryptfs_get_versions);
> +
> +/*
> + * ecryptfs_fill_auth_tok - fill the ecryptfs_auth_tok structure
> + *
> + * Fill the ecryptfs_auth_tok structure with required ecryptfs data.
> + * The source code is inspired to the original function generate_payload()
> + * shipped with the software 'ecryptfs-utils' version 83.
> + *
> + */
> +int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok,
> +			   const char *key_desc)
> +{
> +	int major, minor;
> +
> +	ecryptfs_get_versions(&major, &minor, NULL);
> +	auth_tok->version = (((uint16_t)(major << 8) & 0xFF00)
> +			     | ((uint16_t)minor & 0x00FF));
> +	auth_tok->token_type = ECRYPTFS_PASSWORD;
> +	strncpy((char *)auth_tok->token.password.signature, key_desc,
> +		ECRYPTFS_PASSWORD_SIG_SIZE);
> +	auth_tok->token.password.session_key_encryption_key_bytes =
> +		ECRYPTFS_MAX_KEY_BYTES;
> +	/*
> +	 * Removed auth_tok->token.password.salt and
> +	 * auth_tok->token.password.session_key_encryption_key
> +	 * initialization from the original code
> +	 */
> +	/* TODO: Make the hash parameterizable via policy */
> +	auth_tok->token.password.flags |=
> +		ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET;
> +	/* The kernel code will encrypt the session key. */
> +	auth_tok->session_key.encrypted_key[0] = 0;
> +	auth_tok->session_key.encrypted_key_size = 0;
> +	/* Default; subject to change by kernel eCryptfs */
> +	auth_tok->token.password.hash_algo = PGP_DIGEST_ALGO_SHA512;
> +	auth_tok->token.password.flags &= ~(ECRYPTFS_PERSISTENT_PASSWORD);
> +	return 0;
> +}
> +EXPORT_SYMBOL(ecryptfs_fill_auth_tok);
> +
> +MODULE_LICENSE("GPL");
> diff --git a/security/keys/keys_ecryptfs.h b/security/keys/keys_ecryptfs.h
> new file mode 100644
> index 0000000..87f77ca
> --- /dev/null
> +++ b/security/keys/keys_ecryptfs.h
> @@ -0,0 +1,30 @@
> +/*
> + * keys_ecryptfs.h: helper functions for the encrypted key type
> + *
> + * Copyright (C) 2006 International Business Machines Corp.
> + * Copyright (C) 2010 Politecnico di Torino, Italy
> + *                    TORSEC group -- http://security.polito.it
> + *
> + * Authors:
> + * Michael A. Halcrow <mahalcro@xxxxxxxxxx>
> + * Tyler Hicks <tyhicks@xxxxxx>
> + * Roberto Sassu <roberto.sassu@xxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, version 2 of the License.
> + */
> +
> +#ifndef __KEYS_ECRYPTFS_H
> +#define __KEYS_ECRYPTFS_H
> +
> +#include <linux/ecryptfs.h>
> +
> +#define PGP_DIGEST_ALGO_SHA512   10
> +
> +u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok);
> +void ecryptfs_get_versions(int *major, int *minor, int *file_version);
> +int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok,
> +			   const char *key_desc);
> +
> +#endif /* __KEYS_ECRYPTFS_H */


--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux