summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/ecryptfs/crypto.c39
-rw-r--r--fs/ecryptfs/debug.c13
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h15
-rw-r--r--fs/ecryptfs/events.c146
-rw-r--r--fs/ecryptfs/keystore.c68
-rw-r--r--fs/ecryptfs/main.c19
-rw-r--r--include/linux/ecryptfs.h7
-rw-r--r--security/pfe/pfk.c52
-rw-r--r--security/pfe/pfk_ice.c40
-rw-r--r--security/pfe/pfk_ice.h2
-rw-r--r--security/pfe/pfk_kc.c145
-rw-r--r--security/pfe/pfk_kc.h5
12 files changed, 485 insertions, 66 deletions
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 75a68cc247b5..f68e4aa0165e 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -351,9 +351,9 @@ static int crypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
|| !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED));
if (unlikely(ecryptfs_verbosity > 0)) {
ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n",
- crypt_stat->key_size);
+ ecryptfs_get_key_size_to_enc_data(crypt_stat));
ecryptfs_dump_hex(crypt_stat->key,
- crypt_stat->key_size);
+ ecryptfs_get_key_size_to_enc_data(crypt_stat));
}
init_completion(&ecr.completion);
@@ -372,7 +372,7 @@ static int crypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
/* Consider doing this once, when the file is opened */
if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
- crypt_stat->key_size);
+ ecryptfs_get_key_size_to_enc_data(crypt_stat));
if (rc) {
ecryptfs_printk(KERN_ERR,
"Error setting key; rc = [%d]\n",
@@ -693,7 +693,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
"Initializing cipher [%s]; strlen = [%d]; "
"key_size_bits = [%zd]\n",
crypt_stat->cipher, (int)strlen(crypt_stat->cipher),
- crypt_stat->key_size << 3);
+ ecryptfs_get_key_size_to_enc_data(crypt_stat) << 3);
mutex_lock(&crypt_stat->cs_tfm_mutex);
if (crypt_stat->tfm) {
rc = 0;
@@ -775,7 +775,7 @@ int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat)
goto out;
}
rc = ecryptfs_calculate_md5(dst, crypt_stat, crypt_stat->key,
- crypt_stat->key_size);
+ ecryptfs_get_key_size_to_enc_data(crypt_stat));
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
"MD5 while generating root IV\n");
@@ -802,6 +802,33 @@ static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat)
}
}
+static int ecryptfs_generate_new_salt(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ size_t salt_size = 0;
+
+ salt_size = ecryptfs_get_salt_size_for_cipher(
+ ecryptfs_get_full_cipher(crypt_stat->cipher,
+ crypt_stat->cipher_mode));
+
+ if (0 == salt_size)
+ return 0;
+
+ if (!ecryptfs_check_space_for_salt(crypt_stat->key_size, salt_size)) {
+ ecryptfs_printk(KERN_WARNING, "not enough space for salt\n");
+ crypt_stat->flags |= ECRYPTFS_SECURITY_WARNING;
+ return -EINVAL;
+ }
+
+ get_random_bytes(crypt_stat->key + crypt_stat->key_size, salt_size);
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Generated new session salt:\n");
+ ecryptfs_dump_hex(crypt_stat->key + crypt_stat->key_size,
+ salt_size);
+ }
+
+ return 0;
+}
+
/**
* ecryptfs_copy_mount_wide_flags_to_inode_flags
* @crypt_stat: The inode's cryptographic context
@@ -928,6 +955,8 @@ int ecryptfs_new_file_context(struct inode *ecryptfs_inode)
crypt_stat->key_size =
mount_crypt_stat->global_default_cipher_key_size;
ecryptfs_generate_new_key(crypt_stat);
+ ecryptfs_generate_new_salt(crypt_stat);
+
rc = ecryptfs_init_crypt_ctx(crypt_stat);
if (rc)
ecryptfs_printk(KERN_ERR, "Error initializing cryptographic "
diff --git a/fs/ecryptfs/debug.c b/fs/ecryptfs/debug.c
index 3d2bdf546ec6..1276764f3716 100644
--- a/fs/ecryptfs/debug.c
+++ b/fs/ecryptfs/debug.c
@@ -119,3 +119,16 @@ void ecryptfs_dump_hex(char *data, int bytes)
printk("\n");
}
+void ecryptfs_dump_salt_hex(char *data, int key_size, char *cipher)
+{
+ size_t salt_size = ecryptfs_get_salt_size_for_cipher(cipher);
+
+ if (0 == salt_size)
+ return;
+
+ if (!ecryptfs_check_space_for_salt(key_size, salt_size))
+ return;
+
+ ecryptfs_printk(KERN_DEBUG, "Decrypted session salt key:\n");
+ ecryptfs_dump_hex(data + key_size, salt_size);
+}
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index c02926a677bc..1c04de22e258 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -623,6 +623,7 @@ int ecryptfs_encrypt_and_encode_filename(
const char *name, size_t name_size);
struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
void ecryptfs_dump_hex(char *data, int bytes);
+void ecryptfs_dump_salt_hex(char *data, int key_size, char *cipher);
int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
int sg_size);
int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
@@ -777,4 +778,18 @@ void ecryptfs_freepage(struct page *page);
struct ecryptfs_events *get_events(void);
+size_t ecryptfs_get_salt_size_for_cipher(const char *cipher);
+
+size_t ecryptfs_get_key_size_to_enc_data(
+ struct ecryptfs_crypt_stat *crypt_stat);
+
+size_t ecryptfs_get_key_size_to_store_key(
+ struct ecryptfs_crypt_stat *crypt_stat);
+
+size_t ecryptfs_get_key_size_to_restore_key(size_t stored_key_size,
+ const char *cipher);
+
+bool ecryptfs_check_space_for_salt(const size_t key_size,
+ const size_t salt_size);
+
#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/events.c b/fs/ecryptfs/events.c
index efce062f5c48..0e970fa70996 100644
--- a/fs/ecryptfs/events.c
+++ b/fs/ecryptfs/events.c
@@ -73,6 +73,7 @@ int ecryptfs_register_to_events(struct ecryptfs_events *ops)
events_ptr->is_cipher_supported_cb =
ops->is_cipher_supported_cb;
events_ptr->is_hw_crypt_cb = ops->is_hw_crypt_cb;
+ events_ptr->get_salt_key_size_cb = ops->get_salt_key_size_cb;
get_random_bytes(&handle, sizeof(handle));
ret_value = handle;
@@ -168,6 +169,29 @@ size_t ecryptfs_get_key_size(void *data)
/**
* Given ecryptfs data, the function
+ * returns appropriate salt size.
+ *
+ * !!! crypt_stat cipher name and mode must be initialized
+ */
+size_t ecryptfs_get_salt_size(void *data)
+{
+ struct ecryptfs_crypt_stat *stat = NULL;
+
+ if (!data) {
+ ecryptfs_printk(KERN_ERR,
+ "ecryptfs_get_salt_size: invalid data parameter\n");
+ return 0;
+ }
+
+ stat = (struct ecryptfs_crypt_stat *)data;
+ return ecryptfs_get_salt_size_for_cipher(
+ ecryptfs_get_full_cipher(stat->cipher,
+ stat->cipher_mode));
+
+}
+
+/**
+ * Given ecryptfs data, the function
* returns appropriate cipher.
*/
const unsigned char *ecryptfs_get_cipher(void *data)
@@ -203,6 +227,23 @@ const unsigned char *ecryptfs_get_key(void *data)
}
/**
+ * Given ecryptfs data, the function
+ * returns file encryption salt.
+ */
+const unsigned char *ecryptfs_get_salt(void *data)
+{
+ struct ecryptfs_crypt_stat *stat = NULL;
+
+ if (!data) {
+ ecryptfs_printk(KERN_ERR,
+ "ecryptfs_get_salt: invalid data parameter\n");
+ return NULL;
+ }
+ stat = (struct ecryptfs_crypt_stat *)data;
+ return stat->key + ecryptfs_get_salt_size(data);
+}
+
+/**
* Returns ecryptfs events pointer
*/
inline struct ecryptfs_events *get_events(void)
@@ -210,3 +251,108 @@ inline struct ecryptfs_events *get_events(void)
return events_ptr;
}
+/**
+ * If external crypto module requires salt in addition to key,
+ * we store it as part of key array (if there is enough space)
+ * Checks whether a salt key can fit into array allocated for
+ * regular key
+ */
+bool ecryptfs_check_space_for_salt(const size_t key_size,
+ const size_t salt_size)
+{
+ if ((salt_size + key_size) > ECRYPTFS_MAX_KEY_BYTES)
+ return false;
+
+ return true;
+}
+
+/*
+ * If there is salt that is used by external crypto module, it is stored
+ * in the same array where regular key is. Salt is going to be used by
+ * external crypto module only, so for all internal crypto operations salt
+ * should be ignored.
+ *
+ * Get key size in cases where it is going to be used for data encryption
+ * or for all other general purposes
+ */
+size_t ecryptfs_get_key_size_to_enc_data(
+ struct ecryptfs_crypt_stat *crypt_stat)
+{
+ if (!crypt_stat)
+ return 0;
+
+ return crypt_stat->key_size;
+}
+
+/*
+ * If there is salt that is used by external crypto module, it is stored
+ * in the same array where regular key is. Salt is going to be used by
+ * external crypto module only, but we still need to save and restore it
+ * (in encrypted form) as part of ecryptfs header along with the regular
+ * key.
+ *
+ * Get key size in cases where it is going to be stored persistently
+ *
+ * !!! crypt_stat cipher name and mode must be initialized
+ */
+size_t ecryptfs_get_key_size_to_store_key(
+ struct ecryptfs_crypt_stat *crypt_stat)
+{
+ size_t salt_size = 0;
+
+ if (!crypt_stat)
+ return 0;
+
+ salt_size = ecryptfs_get_salt_size(crypt_stat);
+
+ if (!ecryptfs_check_space_for_salt(crypt_stat->key_size, salt_size)) {
+ ecryptfs_printk(KERN_WARNING,
+ "ecryptfs_get_key_size_to_store_key: not enough space for salt\n");
+ return crypt_stat->key_size;
+ }
+
+ return crypt_stat->key_size + salt_size;
+}
+
+/*
+ * If there is salt that is used by external crypto module, it is stored
+ * in the same array where regular key is. Salt is going to be used by
+ * external crypto module only, but we still need to save and restore it
+ * (in encrypted form) as part of ecryptfs header along with the regular
+ * key.
+ *
+ * Get key size in cases where it is going to be restored from storage
+ *
+ * !!! crypt_stat cipher name and mode must be initialized
+ */
+size_t ecryptfs_get_key_size_to_restore_key(size_t stored_key_size,
+ const char *cipher)
+{
+ size_t salt_size = 0;
+
+ if (!cipher)
+ return 0;
+
+ salt_size = ecryptfs_get_salt_size_for_cipher(cipher);
+
+ if (salt_size >= stored_key_size) {
+ ecryptfs_printk(KERN_WARNING,
+ "ecryptfs_get_key_size_to_restore_key: salt %zu >= stred size %zu\n",
+ salt_size, stored_key_size);
+
+ return stored_key_size;
+ }
+
+ return stored_key_size - salt_size;
+}
+
+/**
+ * Given cipher, the function returns appropriate salt size.
+ */
+size_t ecryptfs_get_salt_size_for_cipher(const char *cipher)
+{
+ if (!get_events() || !(get_events()->get_salt_key_size_cb))
+ return 0;
+
+ return get_events()->get_salt_key_size_cb(cipher);
+}
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index 2b61b5719754..70708270c905 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -315,7 +315,8 @@ write_tag_66_packet(char *signature, u8 cipher_code,
* | File Encryption Key Size | 1 or 2 bytes |
* | File Encryption Key | arbitrary |
*/
- data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size);
+ data_len = (5 + ECRYPTFS_SIG_SIZE_HEX +
+ ecryptfs_get_key_size_to_store_key(crypt_stat));
*packet = kmalloc(data_len, GFP_KERNEL);
message = *packet;
if (!message) {
@@ -335,8 +336,9 @@ write_tag_66_packet(char *signature, u8 cipher_code,
memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
i += ECRYPTFS_SIG_SIZE_HEX;
/* The encrypted key includes 1 byte cipher code and 2 byte checksum */
- rc = ecryptfs_write_packet_length(&message[i], crypt_stat->key_size + 3,
- &packet_size_len);
+ rc = ecryptfs_write_packet_length(&message[i],
+ ecryptfs_get_key_size_to_store_key(crypt_stat) + 3,
+ &packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
"header; cannot generate packet length\n");
@@ -344,9 +346,10 @@ write_tag_66_packet(char *signature, u8 cipher_code,
}
i += packet_size_len;
message[i++] = cipher_code;
- memcpy(&message[i], crypt_stat->key, crypt_stat->key_size);
- i += crypt_stat->key_size;
- for (j = 0; j < crypt_stat->key_size; j++)
+ memcpy(&message[i], crypt_stat->key,
+ ecryptfs_get_key_size_to_store_key(crypt_stat));
+ i += ecryptfs_get_key_size_to_store_key(crypt_stat);
+ for (j = 0; j < ecryptfs_get_key_size_to_store_key(crypt_stat); j++)
checksum += crypt_stat->key[j];
message[i++] = (checksum / 256) % 256;
message[i++] = (checksum % 256);
@@ -1187,16 +1190,20 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
rc);
goto out;
}
- auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
- memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
- auth_tok->session_key.decrypted_key_size);
- crypt_stat->key_size = auth_tok->session_key.decrypted_key_size;
+
rc = ecryptfs_cipher_code_to_string(full_cipher, cipher_code);
if (rc) {
ecryptfs_printk(KERN_ERR, "Cipher code [%d] is invalid\n",
cipher_code)
- goto out;
+ goto out;
}
+
+ auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
+ memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
+ auth_tok->session_key.decrypted_key_size);
+ crypt_stat->key_size = ecryptfs_get_key_size_to_restore_key(
+ auth_tok->session_key.decrypted_key_size, full_cipher);
+
ecryptfs_parse_full_cipher(full_cipher,
crypt_stat->cipher, crypt_stat->cipher_mode);
@@ -1205,6 +1212,9 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n");
ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size);
+
+ ecryptfs_dump_salt_hex(crypt_stat->key, crypt_stat->key_size,
+ full_cipher);
}
out:
kfree(msg);
@@ -1475,7 +1485,10 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
break;
default:
crypt_stat->key_size =
- (*new_auth_tok)->session_key.encrypted_key_size;
+ ecryptfs_get_key_size_to_restore_key(
+ (*new_auth_tok)->session_key.encrypted_key_size,
+ full_cipher);
+
}
rc = ecryptfs_init_crypt_ctx(crypt_stat);
if (rc)
@@ -1723,7 +1736,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
mutex_lock(tfm_mutex);
rc = crypto_blkcipher_setkey(
desc.tfm, auth_tok->token.password.session_key_encryption_key,
- crypt_stat->key_size);
+ auth_tok->token.password.session_key_encryption_key_bytes);
if (unlikely(rc < 0)) {
mutex_unlock(tfm_mutex);
printk(KERN_ERR "Error setting key for crypto context\n");
@@ -1746,6 +1759,9 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
crypt_stat->key_size);
ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size);
+ ecryptfs_dump_salt_hex(crypt_stat->key, crypt_stat->key_size,
+ ecryptfs_get_full_cipher(crypt_stat->cipher,
+ crypt_stat->cipher_mode));
}
out:
return rc;
@@ -1984,12 +2000,13 @@ pki_encrypt_session_key(struct key *auth_tok_key,
int rc;
rc = write_tag_66_packet(auth_tok->token.private_key.signature,
- ecryptfs_code_for_cipher_string(
+ ecryptfs_code_for_cipher_string(
ecryptfs_get_full_cipher(
crypt_stat->cipher,
crypt_stat->cipher_mode),
- crypt_stat->key_size),
- crypt_stat, &payload, &payload_len);
+ ecryptfs_get_key_size_to_enc_data(
+ crypt_stat)),
+ crypt_stat, &payload, &payload_len);
up_write(&(auth_tok_key->sem));
key_put(auth_tok_key);
if (rc) {
@@ -2047,7 +2064,7 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes,
ecryptfs_from_hex(key_rec->sig, auth_tok->token.private_key.signature,
ECRYPTFS_SIG_SIZE);
encrypted_session_key_valid = 0;
- for (i = 0; i < crypt_stat->key_size; i++)
+ for (i = 0; i < ecryptfs_get_key_size_to_store_key(crypt_stat); i++)
encrypted_session_key_valid |=
auth_tok->session_key.encrypted_key[i];
if (encrypted_session_key_valid) {
@@ -2233,13 +2250,14 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
mount_crypt_stat->global_default_cipher_key_size;
if (auth_tok->session_key.encrypted_key_size == 0)
auth_tok->session_key.encrypted_key_size =
- crypt_stat->key_size;
+ ecryptfs_get_key_size_to_store_key(crypt_stat);
if (crypt_stat->key_size == 24
&& strcmp("aes", crypt_stat->cipher) == 0) {
memset((crypt_stat->key + 24), 0, 8);
auth_tok->session_key.encrypted_key_size = 32;
} else
- auth_tok->session_key.encrypted_key_size = crypt_stat->key_size;
+ auth_tok->session_key.encrypted_key_size =
+ ecryptfs_get_key_size_to_store_key(crypt_stat);
key_rec->enc_key_size =
auth_tok->session_key.encrypted_key_size;
encrypted_session_key_valid = 0;
@@ -2263,8 +2281,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
auth_tok->token.password.
session_key_encryption_key_bytes);
memcpy(session_key_encryption_key,
- auth_tok->token.password.session_key_encryption_key,
- crypt_stat->key_size);
+ auth_tok->token.password.session_key_encryption_key,
+ auth_tok->token.password.session_key_encryption_key_bytes);
ecryptfs_printk(KERN_DEBUG,
"Cached session key encryption key:\n");
if (ecryptfs_verbosity > 0)
@@ -2297,7 +2315,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
}
mutex_lock(tfm_mutex);
rc = crypto_blkcipher_setkey(desc.tfm, session_key_encryption_key,
- crypt_stat->key_size);
+ auth_tok->token.password.session_key_encryption_key_bytes);
if (rc < 0) {
mutex_unlock(tfm_mutex);
ecryptfs_printk(KERN_ERR, "Error setting key for crypto "
@@ -2306,7 +2324,11 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
}
rc = 0;
ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the key\n",
- crypt_stat->key_size);
+ crypt_stat->key_size);
+ ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the salt key\n",
+ ecryptfs_get_salt_size_for_cipher(
+ ecryptfs_get_full_cipher(crypt_stat->cipher,
+ crypt_stat->cipher_mode)));
rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg,
(*key_rec).enc_key_size);
mutex_unlock(tfm_mutex);
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 7dbccb4b38db..a3bd96a80ade 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -266,6 +266,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
int cipher_key_bytes_set = 0;
int fn_cipher_key_bytes;
int fn_cipher_key_bytes_set = 0;
+ size_t salt_size = 0;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
&sbi->mount_crypt_stat;
substring_t args[MAX_OPT_ARGS];
@@ -418,8 +419,24 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
&& !fn_cipher_name_set)
strcpy(mount_crypt_stat->global_default_fn_cipher_name,
mount_crypt_stat->global_default_cipher_name);
- if (!cipher_key_bytes_set)
+
+ if (cipher_key_bytes_set) {
+
+ salt_size = ecryptfs_get_salt_size_for_cipher(
+ ecryptfs_get_full_cipher(
+ mount_crypt_stat->global_default_cipher_name,
+ mount_crypt_stat->global_default_cipher_mode));
+
+ if (!ecryptfs_check_space_for_salt(
+ mount_crypt_stat->global_default_cipher_key_size,
+ salt_size)) {
+ ecryptfs_printk(
+ KERN_WARNING,
+ "eCryptfs internal error: no space for salt");
+ }
+ } else
mount_crypt_stat->global_default_cipher_key_size = 0;
+
if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)
&& !fn_cipher_key_bytes_set)
mount_crypt_stat->global_default_fn_cipher_key_bytes =
diff --git a/include/linux/ecryptfs.h b/include/linux/ecryptfs.h
index 4f3006ae2a42..55433c6c603d 100644
--- a/include/linux/ecryptfs.h
+++ b/include/linux/ecryptfs.h
@@ -119,7 +119,7 @@ struct ecryptfs_auth_tok {
* such as ecryptfs_get_key_size(), ecryptfs_get_cipher() etc.
*/
struct ecryptfs_events {
- bool (*is_cipher_supported_cb)(char *cipher);
+ bool (*is_cipher_supported_cb)(const char *cipher);
void (*open_cb)(struct inode *inode, void *ecrytpfs_data);
void (*release_cb)(struct inode *inode);
int (*encrypt_cb)(struct page *in_page, struct page *out_page,
@@ -127,6 +127,7 @@ struct ecryptfs_events {
int (*decrypt_cb)(struct page *in_page, struct page *out_page,
struct inode *inode, unsigned long extent_offset);
bool (*is_hw_crypt_cb)(void);
+ size_t (*get_salt_key_size_cb)(const char *cipher);
};
@@ -138,6 +139,10 @@ const unsigned char *ecryptfs_get_key(void *ecrytpfs_data);
size_t ecryptfs_get_key_size(void *ecrytpfs_data);
+const unsigned char *ecryptfs_get_salt(void *ecrytpfs_data);
+
+size_t ecryptfs_get_salt_size(void *ecrytpfs_data);
+
const unsigned char *ecryptfs_get_cipher(void *ecrytpfs_data);
bool ecryptfs_is_page_in_metadata(void *ecrytpfs_data, pgoff_t offset);
diff --git a/security/pfe/pfk.c b/security/pfe/pfk.c
index e8d7cb678aed..3c8e2f8fad41 100644
--- a/security/pfe/pfk.c
+++ b/security/pfe/pfk.c
@@ -65,6 +65,7 @@ static int g_events_handle;
/* might be replaced by a table when more than one cipher is supported */
#define PFK_SUPPORTED_CIPHER "aes_xts"
#define PFK_SUPPORTED_KEY_SIZE 32
+#define PFK_SUPPORTED_SALT_SIZE 32
static int pfk_inode_alloc_security(struct inode *inode)
{
@@ -326,12 +327,14 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
struct inode *inode = NULL;
int ret = 0;
const unsigned char *key = NULL;
+ const unsigned char *salt = NULL;
const unsigned char *cipher = NULL;
void *ecryptfs_data = NULL;
u32 key_index = 0;
enum ice_cryto_algo_mode algo_mode = 0;
enum ice_crpto_key_size key_size_type = 0;
size_t key_size = 0;
+ size_t salt_size = 0;
pgoff_t offset;
bool is_metadata = false;
@@ -386,6 +389,20 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
goto end;
}
+ salt = ecryptfs_get_salt(ecryptfs_data);
+ if (!salt) {
+ pr_err("could not parse salt from ecryptfs\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
+ salt_size = ecryptfs_get_salt_size(ecryptfs_data);
+ if (!salt_size) {
+ pr_err("could not parse salt size from ecryptfs\n");
+ ret = -EINVAL;
+ goto end;
+ }
+
cipher = ecryptfs_get_cipher(ecryptfs_data);
if (!key) {
pr_err("could not parse key from ecryptfs\n");
@@ -401,7 +418,7 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
if (ret != 0)
return ret;
- ret = pfk_kc_load_key(key, key_size, &key_index);
+ ret = pfk_kc_load_key(key, key_size, salt, salt_size, &key_index);
if (ret != 0) {
pr_err("could not load key into pfk key cache, error %d\n",
ret);
@@ -503,7 +520,6 @@ bool pfk_allow_merge_bio(struct bio *bio1, struct bio *bio2)
goto end;
}
-
/*
* at this point both bio's are in the same file which is probably
* encrypted, last thing to check is header vs data
@@ -587,7 +603,9 @@ static void pfk_open_cb(struct inode *inode, void *ecryptfs_data)
static void pfk_release_cb(struct inode *inode)
{
const unsigned char *key = NULL;
- size_t key_size;
+ const unsigned char *salt = NULL;
+ size_t key_size = 0;
+ size_t salt_size = 0;
void *data = NULL;
if (!pfk_is_ready())
@@ -616,14 +634,26 @@ static void pfk_release_cb(struct inode *inode)
return;
}
- pfk_kc_remove_key(key, key_size);
+ salt = ecryptfs_get_salt(data);
+ if (!salt) {
+ pr_err("could not parse salt from ecryptfs\n");
+ return;
+ }
+
+ salt_size = ecryptfs_get_salt_size(data);
+ if (!salt_size) {
+ pr_err("could not parse salt size from ecryptfs\n");
+ return;
+ }
+
+ pfk_kc_remove_key_with_salt(key, key_size, salt, salt_size);
mutex_lock(&pfk_lock);
pfk_set_ecryptfs_data(inode, NULL);
mutex_unlock(&pfk_lock);
}
-static bool pfk_is_cipher_supported_cb(char *cipher)
+static bool pfk_is_cipher_supported_cb(const char *cipher)
{
if (!pfk_is_ready())
return false;
@@ -642,6 +672,17 @@ static bool pfk_is_hw_crypt_cb(void)
return true;
}
+static size_t pfk_get_salt_key_size_cb(const char *cipher)
+{
+ if (!pfk_is_ready())
+ return 0;
+
+ if (!pfk_is_cipher_supported_cb(cipher))
+ return 0;
+
+ return PFK_SUPPORTED_SALT_SIZE;
+}
+
static void __exit pfk_exit(void)
{
@@ -660,6 +701,7 @@ static int __init pfk_init(void)
events.release_cb = pfk_release_cb;
events.is_cipher_supported_cb = pfk_is_cipher_supported_cb;
events.is_hw_crypt_cb = pfk_is_hw_crypt_cb;
+ events.get_salt_key_size_cb = pfk_get_salt_key_size_cb;
g_events_handle = ecryptfs_register_to_events(&events);
if (0 == g_events_handle) {
diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c
index d26dee245cc5..1cb350296159 100644
--- a/security/pfe/pfk_ice.c
+++ b/security/pfe/pfk_ice.c
@@ -48,46 +48,60 @@
#define TZ_ES_SET_ICE_KEY_PARAM_ID \
- TZ_SYSCALL_CREATE_PARAM_ID_3( \
- TZ_SYSCALL_PARAM_TYPE_VAL, \
- TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
+ TZ_SYSCALL_CREATE_PARAM_ID_5( \
+ TZ_SYSCALL_PARAM_TYPE_VAL, \
+ TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \
+ TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
#define TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID \
TZ_SYSCALL_CREATE_PARAM_ID_1( \
TZ_SYSCALL_PARAM_TYPE_VAL)
#define ICE_KEY_SIZE 32
-
+#define ICE_SALT_SIZE 32
uint8_t ice_key[ICE_KEY_SIZE];
+uint8_t ice_salt[ICE_KEY_SIZE];
-int qti_pfk_ice_set_key(uint32_t index, uint8_t *key)
+int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt)
{
struct scm_desc desc = {0};
int ret;
- char *tzbuf = (char *)ice_key;
+ char *tzbuf_key = (char *)ice_key;
+ char *tzbuf_salt = (char *)ice_salt;
uint32_t smc_id = 0;
- u32 tzbuflen = sizeof(ice_key);
+ u32 tzbuflen_key = sizeof(ice_key);
+ u32 tzbuflen_salt = sizeof(ice_salt);
if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX)
return -EINVAL;
- if (!tzbuf)
+ if (!key || !salt)
+ return -EINVAL;
+
+ if (!tzbuf_key || !tzbuf_salt)
return -ENOMEM;
- memset(tzbuf, 0, tzbuflen);
- memcpy(ice_key, key, ICE_KEY_SIZE);
+ memset(tzbuf_key, 0, tzbuflen_key);
+ memset(tzbuf_salt, 0, tzbuflen_salt);
- dmac_flush_range(tzbuf, tzbuf + tzbuflen);
+ memcpy(ice_key, key, tzbuflen_key);
+ memcpy(ice_salt, salt, tzbuflen_salt);
+
+ dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key);
+ dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt);
smc_id = TZ_ES_SET_ICE_KEY_ID;
pr_debug(" %s , smc_id = 0x%x\n", __func__, smc_id);
desc.arginfo = TZ_ES_SET_ICE_KEY_PARAM_ID;
desc.args[0] = index;
- desc.args[1] = virt_to_phys(tzbuf);
- desc.args[2] = tzbuflen;
+ desc.args[1] = virt_to_phys(tzbuf_key);
+ desc.args[2] = tzbuflen_key;
+ desc.args[3] = virt_to_phys(tzbuf_salt);
+ desc.args[4] = tzbuflen_salt;
+
ret = scm_call2_atomic(smc_id, &desc);
pr_debug(" %s , ret = %d\n", __func__, ret);
diff --git a/security/pfe/pfk_ice.h b/security/pfe/pfk_ice.h
index b1a5c4c807a3..1d6339a575be 100644
--- a/security/pfe/pfk_ice.h
+++ b/security/pfe/pfk_ice.h
@@ -26,7 +26,7 @@
int pfk_ice_init(void);
int pfk_ice_deinit(void);
-int qti_pfk_ice_set_key(uint32_t index, uint8_t *key);
+int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt);
int qti_pfk_ice_invalidate_key(uint32_t index);
diff --git a/security/pfe/pfk_kc.c b/security/pfe/pfk_kc.c
index 687663f5a7ac..eff49d0315b5 100644
--- a/security/pfe/pfk_kc.c
+++ b/security/pfe/pfk_kc.c
@@ -41,15 +41,17 @@
/** the first available index in ice engine */
#define PFK_KC_STARTING_INDEX 2
-/** currently the only supported key size */
+/** currently the only supported key and salt sizes */
#define PFK_KC_KEY_SIZE 32
+#define PFK_KC_SALT_SIZE 32
/** Table size */
/* TODO replace by some constant from ice.h */
#define PFK_KC_TABLE_SIZE ((32) - (PFK_KC_STARTING_INDEX))
-/** The maximum key size */
+/** The maximum key and salt size */
#define PFK_MAX_KEY_SIZE PFK_KC_KEY_SIZE
+#define PFK_MAX_SALT_SIZE PFK_KC_SALT_SIZE
static DEFINE_SPINLOCK(kc_lock);
static bool kc_ready;
@@ -57,11 +59,15 @@ static bool kc_ready;
struct kc_entry {
unsigned char key[PFK_MAX_KEY_SIZE];
size_t key_size;
+
+ unsigned char salt[PFK_MAX_SALT_SIZE];
+ size_t salt_size;
+
u64 time_stamp;
u32 key_index;
};
-static struct kc_entry kc_table[PFK_KC_TABLE_SIZE] = {{{0} , 0, 0, 0} };
+static struct kc_entry kc_table[PFK_KC_TABLE_SIZE] = {{{0}, 0, {0}, 0, 0, 0} };
/**
* pfk_min_time_entry() - update min time and update min entry
@@ -96,31 +102,66 @@ static inline bool kc_is_ready(void)
}
/**
- * kc_find_key() - find kc entry
+ * kc_find_key_at_index() - find kc entry starting at specific index
* @key: key to look for
* @key_size: the key size
+ * @salt: salt to look for
+ * @salt_size: the salt size
+ * @sarting_index: index to start search with, if entry found, updated with
+ * index of that entry
*
* Return entry or NULL in case of error
* Should be invoked under lock
*/
-static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size)
+static struct kc_entry *kc_find_key_at_index(const unsigned char *key,
+ size_t key_size, const unsigned char *salt, size_t salt_size,
+ int *starting_index)
{
struct kc_entry *entry = NULL;
int i = 0;
- for (i = 0; i < PFK_KC_TABLE_SIZE; i++) {
+ for (i = *starting_index; i < PFK_KC_TABLE_SIZE; i++) {
entry = &(kc_table[i]);
+
+ if (NULL != salt) {
+ if (entry->salt_size != salt_size)
+ continue;
+
+ if (0 != memcmp(entry->salt, salt, salt_size))
+ continue;
+ }
+
if (entry->key_size != key_size)
continue;
- if (0 == memcmp(entry->key, key, key_size))
+ if (0 == memcmp(entry->key, key, key_size)) {
+ *starting_index = i;
return entry;
+ }
}
return NULL;
}
/**
+ * kc_find_key() - find kc entry
+ * @key: key to look for
+ * @key_size: the key size
+ * @salt: salt to look for
+ * @salt_size: the salt size
+ *
+ * Return entry or NULL in case of error
+ * Should be invoked under lock
+ */
+static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size,
+ const unsigned char *salt, size_t salt_size)
+{
+ int index = 0;
+
+ return kc_find_key_at_index(key, key_size, salt, salt_size, &index);
+}
+
+/**
* kc_find_oldest_entry() - finds the entry with minimal timestamp
*
* Returns entry with minimal timestamp. Empty entries have timestamp
@@ -183,6 +224,7 @@ static void kc_clear_entry(struct kc_entry *entry, bool clear_qscee)
qti_pfk_ice_invalidate_key(entry->key_index);
memset(entry->key, 0, entry->key_size);
+ memset(entry->salt, 0, entry->salt_size);
entry->time_stamp = 0;
}
@@ -194,13 +236,15 @@ static void kc_clear_entry(struct kc_entry *entry, bool clear_qscee)
* @entry: entry to replace key in
* @key: key
* @key_size: key_size
+ * @salt: salt
+ * @salt_size: salt_size
*
* The previous key is securely released and wiped, the new one is loaded
* to ICE.
* Should be invoked under lock
*/
static int kc_replace_entry(struct kc_entry *entry, const unsigned char *key,
- size_t key_size)
+ size_t key_size, const unsigned char *salt, size_t salt_size)
{
int ret = 0;
@@ -209,7 +253,11 @@ static int kc_replace_entry(struct kc_entry *entry, const unsigned char *key,
memcpy(entry->key, key, key_size);
entry->key_size = key_size;
- ret = qti_pfk_ice_set_key(entry->key_index, (uint8_t *) key);
+ memcpy(entry->salt, salt, salt_size);
+ entry->salt_size = salt_size;
+
+ ret = qti_pfk_ice_set_key(entry->key_index, (uint8_t *) key,
+ (uint8_t *) salt);
if (ret != 0) {
ret = -EINVAL;
goto err;
@@ -265,7 +313,9 @@ int pfk_kc_deinit(void)
* pfk_kc_load_key() - retrieve the key from cache or add it if it's not there
* return the ICE hw key index
* @key: pointer to the key
- * @key_size: the size of the key, assumed to be not bigger than
+ * @key_size: the size of the key
+ * @salt: pointer to the salt
+ * @salt_size: the size of the salt
* @key_index: the pointer to key_index where the output will be stored
*
* If key is present in cache, than the key_index will be retrieved from cache.
@@ -275,7 +325,8 @@ int pfk_kc_deinit(void)
*
* Return 0 in case of success, error otherwise
*/
-int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
+int pfk_kc_load_key(const unsigned char *key, size_t key_size,
+ const unsigned char *salt, size_t salt_size, u32 *key_index)
{
int ret = 0;
struct kc_entry *entry = NULL;
@@ -283,14 +334,17 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
if (!kc_is_ready())
return -ENODEV;
- if (!key || !key_index)
+ if (!key || !salt || !key_index)
return -EPERM;
if (key_size != PFK_KC_KEY_SIZE)
return -EPERM;
+ if (salt_size != PFK_KC_SALT_SIZE)
+ return -EPERM;
+
spin_lock(&kc_lock);
- entry = kc_find_key(key, key_size);
+ entry = kc_find_key(key, key_size, salt, salt_size);
if (!entry) {
entry = kc_find_oldest_entry();
if (!entry) {
@@ -302,7 +356,7 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
pr_debug("didn't found key in cache, replacing entry with index %d\n",
entry->key_index);
- ret = kc_replace_entry(entry, key, key_size);
+ ret = kc_replace_entry(entry, key, key_size, salt, salt_size);
if (ret) {
spin_unlock(&kc_lock);
return -EINVAL;
@@ -322,7 +376,54 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
/**
* pfk_kc_remove_key() - remove the key from cache and from ICE engine
* @key: pointer to the key
- * @key_size: the size of the key, assumed to be not bigger than
+ * @key_size: the size of the key
+ * @salt: pointer to the key
+ * @salt_size: the size of the key
+ *
+ * Return 0 in case of success, error otherwise (also in case of non
+ * (existing key)
+ */
+int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size,
+ const unsigned char *salt, size_t salt_size)
+{
+ struct kc_entry *entry = NULL;
+
+ if (!kc_is_ready())
+ return -ENODEV;
+
+ if (!key)
+ return -EPERM;
+
+ if (!salt)
+ return -EPERM;
+
+ if (key_size != PFK_KC_KEY_SIZE)
+ return -EPERM;
+
+ if (salt_size != PFK_KC_SALT_SIZE)
+ return -EPERM;
+
+ spin_lock(&kc_lock);
+ entry = kc_find_key(key, key_size, salt, salt_size);
+ if (!entry) {
+ pr_err("key does not exist\n");
+ spin_unlock(&kc_lock);
+ return -EINVAL;
+ }
+
+ kc_clear_entry(entry, true);
+ spin_unlock(&kc_lock);
+
+ return 0;
+}
+
+/**
+ * pfk_kc_remove_key() - remove the key from cache and from ICE engine
+ * when no salt is available. Will only search key part, if there are several,
+ * all will be removed
+ *
+ * @key: pointer to the key
+ * @key_size: the size of the key
*
* Return 0 in case of success, error otherwise (also in case of non
* (existing key)
@@ -330,6 +431,7 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
int pfk_kc_remove_key(const unsigned char *key, size_t key_size)
{
struct kc_entry *entry = NULL;
+ int index = 0;
if (!kc_is_ready())
return -ENODEV;
@@ -341,7 +443,8 @@ int pfk_kc_remove_key(const unsigned char *key, size_t key_size)
return -EPERM;
spin_lock(&kc_lock);
- entry = kc_find_key(key, key_size);
+
+ entry = kc_find_key_at_index(key, key_size, NULL, 0, &index);
if (!entry) {
pr_err("key does not exist\n");
spin_unlock(&kc_lock);
@@ -349,6 +452,16 @@ int pfk_kc_remove_key(const unsigned char *key, size_t key_size)
}
kc_clear_entry(entry, true);
+
+ /* let's clean additional entries with the same key if there are any */
+ do {
+ entry = kc_find_key_at_index(key, key_size, NULL, 0, &index);
+ if (!entry)
+ break;
+
+ kc_clear_entry(entry, true);
+ } while (true);
+
spin_unlock(&kc_lock);
return 0;
diff --git a/security/pfe/pfk_kc.h b/security/pfe/pfk_kc.h
index 86cc1b43e4f3..07b7827e8ddc 100644
--- a/security/pfe/pfk_kc.h
+++ b/security/pfe/pfk_kc.h
@@ -17,7 +17,10 @@
int pfk_kc_init(void);
int pfk_kc_deinit(void);
-int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index);
+int pfk_kc_load_key(const unsigned char *key, size_t key_size,
+ const unsigned char *salt, size_t salt_size, u32 *key_index);
+int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size,
+ const unsigned char *salt, size_t salt_size);
int pfk_kc_remove_key(const unsigned char *key, size_t key_size);
void pfk_kc_clear(void);