// SPDX-License-Identifier: GPL-2.0 /* * Key setup for v1 encryption policies * * Copyright 2015, 2019 Google LLC
*/
/* * This file implements compatibility functions for the original encryption * policy version ("v1"), including: * * - Deriving per-file encryption keys using the AES-128-ECB based KDF * (rather than the new method of using HKDF-SHA512) * * - Retrieving fscrypt master keys from process-subscribed keyrings * (rather than the new method of using a filesystem-level keyring) * * - Handling policies with the DIRECT_KEY flag set using a master key table * (rather than the new method of implementing DIRECT_KEY with per-mode keys * managed alongside the master keys in the filesystem-level keyring)
*/
/* * v1 key derivation function. This generates the derived key by encrypting the * master key with AES-128-ECB using the nonce as the AES key. This provides a * unique derived key with sufficient entropy for each inode. However, it's * nonstandard, non-extensible, doesn't evenly distribute the entropy from the * master key, and is trivially reversible: an attacker who compromises a * derived key can "decrypt" it to get back to the master key, then derive any * other key. For all new code, use HKDF instead. * * The master key must be at least as long as the derived key. If the master * key is longer, then only the first 'derived_keysize' bytes are used.
*/ staticint derive_key_aes(const u8 *master_key, const u8 nonce[FSCRYPT_FILE_NONCE_SIZE],
u8 *derived_key, unsignedint derived_keysize)
{ struct crypto_sync_skcipher *tfm; int err;
tfm = crypto_alloc_sync_skcipher("ecb(aes)", 0, FSCRYPT_CRYPTOAPI_MASK); if (IS_ERR(tfm)) return PTR_ERR(tfm);
/* * Search the current task's subscribed keyrings for a "logon" key with * description prefix:descriptor, and if found acquire a read lock on it and * return a pointer to its validated payload in *payload_ret.
*/ staticstruct key *
find_and_lock_process_key(constchar *prefix, const u8 descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE], unsignedint min_keysize, conststruct fscrypt_key **payload_ret)
{ char *description; struct key *key; conststruct user_key_payload *ukp; conststruct fscrypt_key *payload;
if (!ukp) /* was the key revoked before we acquired its semaphore? */ goto invalid;
payload = (conststruct fscrypt_key *)ukp->data;
if (ukp->datalen != sizeof(struct fscrypt_key) ||
payload->size < 1 || payload->size > sizeof(payload->raw)) {
fscrypt_warn(NULL, "key with description '%s' has invalid payload",
key->description); goto invalid;
}
if (payload->size < min_keysize) {
fscrypt_warn(NULL, "key with description '%s' is too short (got %u bytes, need %u+ bytes)",
key->description, payload->size, min_keysize); goto invalid;
}
/* * Find/insert the given key into the fscrypt_direct_keys table. If found, it * is returned with elevated refcount, and 'to_insert' is freed if non-NULL. If * not found, 'to_insert' is inserted and returned if it's non-NULL; otherwise * NULL is returned.
*/ staticstruct fscrypt_direct_key *
find_or_insert_direct_key(struct fscrypt_direct_key *to_insert, const u8 *raw_key, conststruct fscrypt_inode_info *ci)
{ unsignedlong hash_key; struct fscrypt_direct_key *dk;
/* * Careful: to avoid potentially leaking secret key bytes via timing * information, we must key the hash table by descriptor rather than by * raw key, and use crypto_memneq() when comparing raw keys.
*/
spin_lock(&fscrypt_direct_keys_lock);
hash_for_each_possible(fscrypt_direct_keys, dk, dk_node, hash_key) { if (memcmp(ci->ci_policy.v1.master_key_descriptor,
dk->dk_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE) != 0) continue; if (ci->ci_mode != dk->dk_mode) continue; if (!fscrypt_is_key_prepared(&dk->dk_key, ci)) continue; if (crypto_memneq(raw_key, dk->dk_raw, ci->ci_mode->keysize)) continue; /* using existing tfm with same (descriptor, mode, raw_key) */
refcount_inc(&dk->dk_refcount);
spin_unlock(&fscrypt_direct_keys_lock);
free_direct_key(to_insert); return dk;
} if (to_insert)
hash_add(fscrypt_direct_keys, &to_insert->dk_node, hash_key);
spin_unlock(&fscrypt_direct_keys_lock); return to_insert;
}
/* Prepare to encrypt directly using the master key in the given mode */ staticstruct fscrypt_direct_key *
fscrypt_get_direct_key(conststruct fscrypt_inode_info *ci, const u8 *raw_key)
{ struct fscrypt_direct_key *dk; int err;
/* Is there already a tfm for this key? */
dk = find_or_insert_direct_key(NULL, raw_key, ci); if (dk) return dk;
/* * This cannot be a stack buffer because it will be passed to the * scatterlist crypto API during derive_key_aes().
*/
derived_key = kmalloc(ci->ci_mode->keysize, GFP_KERNEL); if (!derived_key) return -ENOMEM;
err = derive_key_aes(raw_master_key, ci->ci_nonce,
derived_key, ci->ci_mode->keysize); if (err) goto out;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.