|
20 | 20 | * managed alongside the master keys in the filesystem-level keyring) |
21 | 21 | */ |
22 | 22 |
|
23 | | -#include <crypto/skcipher.h> |
| 23 | +#include <crypto/aes.h> |
24 | 24 | #include <crypto/utils.h> |
25 | 25 | #include <keys/user-type.h> |
26 | 26 | #include <linux/hashtable.h> |
27 | | -#include <linux/scatterlist.h> |
28 | 27 |
|
29 | 28 | #include "fscrypt_private.h" |
30 | 29 |
|
31 | 30 | /* Table of keys referenced by DIRECT_KEY policies */ |
32 | 31 | static DEFINE_HASHTABLE(fscrypt_direct_keys, 6); /* 6 bits = 64 buckets */ |
33 | 32 | static DEFINE_SPINLOCK(fscrypt_direct_keys_lock); |
34 | 33 |
|
35 | | -/* |
36 | | - * v1 key derivation function. This generates the derived key by encrypting the |
37 | | - * master key with AES-128-ECB using the nonce as the AES key. This provides a |
38 | | - * unique derived key with sufficient entropy for each inode. However, it's |
39 | | - * nonstandard, non-extensible, doesn't evenly distribute the entropy from the |
40 | | - * master key, and is trivially reversible: an attacker who compromises a |
41 | | - * derived key can "decrypt" it to get back to the master key, then derive any |
42 | | - * other key. For all new code, use HKDF instead. |
43 | | - * |
44 | | - * The master key must be at least as long as the derived key. If the master |
45 | | - * key is longer, then only the first 'derived_keysize' bytes are used. |
46 | | - */ |
47 | | -static int derive_key_aes(const u8 *master_key, |
48 | | - const u8 nonce[FSCRYPT_FILE_NONCE_SIZE], |
49 | | - u8 *derived_key, unsigned int derived_keysize) |
50 | | -{ |
51 | | - struct crypto_sync_skcipher *tfm; |
52 | | - int err; |
53 | | - |
54 | | - tfm = crypto_alloc_sync_skcipher("ecb(aes)", 0, FSCRYPT_CRYPTOAPI_MASK); |
55 | | - if (IS_ERR(tfm)) |
56 | | - return PTR_ERR(tfm); |
57 | | - |
58 | | - err = crypto_sync_skcipher_setkey(tfm, nonce, FSCRYPT_FILE_NONCE_SIZE); |
59 | | - if (err == 0) { |
60 | | - SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); |
61 | | - struct scatterlist src_sg, dst_sg; |
62 | | - |
63 | | - skcipher_request_set_callback(req, |
64 | | - CRYPTO_TFM_REQ_MAY_BACKLOG | |
65 | | - CRYPTO_TFM_REQ_MAY_SLEEP, |
66 | | - NULL, NULL); |
67 | | - sg_init_one(&src_sg, master_key, derived_keysize); |
68 | | - sg_init_one(&dst_sg, derived_key, derived_keysize); |
69 | | - skcipher_request_set_crypt(req, &src_sg, &dst_sg, |
70 | | - derived_keysize, NULL); |
71 | | - err = crypto_skcipher_encrypt(req); |
72 | | - } |
73 | | - crypto_free_sync_skcipher(tfm); |
74 | | - return err; |
75 | | -} |
76 | | - |
77 | 34 | /* |
78 | 35 | * Search the current task's subscribed keyrings for a "logon" key with |
79 | 36 | * description prefix:descriptor, and if found acquire a read lock on it and |
@@ -255,29 +212,41 @@ static int setup_v1_file_key_direct(struct fscrypt_inode_info *ci, |
255 | 212 | return 0; |
256 | 213 | } |
257 | 214 |
|
258 | | -/* v1 policy, !DIRECT_KEY: derive the file's encryption key */ |
| 215 | +/* |
| 216 | + * v1 policy, !DIRECT_KEY: derive the file's encryption key. |
| 217 | + * |
| 218 | + * The v1 key derivation function generates the derived key by encrypting the |
| 219 | + * master key with AES-128-ECB using the file's nonce as the AES key. This |
| 220 | + * provides a unique derived key with sufficient entropy for each inode. |
| 221 | + * However, it's nonstandard, non-extensible, doesn't evenly distribute the |
| 222 | + * entropy from the master key, and is trivially reversible: an attacker who |
| 223 | + * compromises a derived key can "decrypt" it to get back to the master key, |
| 224 | + * then derive any other key. For all new code, use HKDF instead. |
| 225 | + * |
| 226 | + * The master key must be at least as long as the derived key. If the master |
| 227 | + * key is longer, then only the first ci->ci_mode->keysize bytes are used. |
| 228 | + */ |
259 | 229 | static int setup_v1_file_key_derived(struct fscrypt_inode_info *ci, |
260 | 230 | const u8 *raw_master_key) |
261 | 231 | { |
262 | | - u8 *derived_key; |
| 232 | + const unsigned int derived_keysize = ci->ci_mode->keysize; |
| 233 | + u8 derived_key[FSCRYPT_MAX_RAW_KEY_SIZE]; |
| 234 | + struct aes_enckey aes; |
263 | 235 | int err; |
264 | 236 |
|
265 | | - /* |
266 | | - * This cannot be a stack buffer because it will be passed to the |
267 | | - * scatterlist crypto API during derive_key_aes(). |
268 | | - */ |
269 | | - derived_key = kmalloc(ci->ci_mode->keysize, GFP_KERNEL); |
270 | | - if (!derived_key) |
271 | | - return -ENOMEM; |
| 237 | + if (WARN_ON_ONCE(derived_keysize > FSCRYPT_MAX_RAW_KEY_SIZE || |
| 238 | + derived_keysize % AES_BLOCK_SIZE != 0)) |
| 239 | + return -EINVAL; |
272 | 240 |
|
273 | | - err = derive_key_aes(raw_master_key, ci->ci_nonce, |
274 | | - derived_key, ci->ci_mode->keysize); |
275 | | - if (err) |
276 | | - goto out; |
| 241 | + static_assert(FSCRYPT_FILE_NONCE_SIZE == AES_KEYSIZE_128); |
| 242 | + aes_prepareenckey(&aes, ci->ci_nonce, FSCRYPT_FILE_NONCE_SIZE); |
| 243 | + for (unsigned int i = 0; i < derived_keysize; i += AES_BLOCK_SIZE) |
| 244 | + aes_encrypt(&aes, &derived_key[i], &raw_master_key[i]); |
277 | 245 |
|
278 | 246 | err = fscrypt_set_per_file_enc_key(ci, derived_key); |
279 | | -out: |
280 | | - kfree_sensitive(derived_key); |
| 247 | + |
| 248 | + memzero_explicit(derived_key, derived_keysize); |
| 249 | + /* No need to zeroize 'aes', as its key is not secret. */ |
281 | 250 | return err; |
282 | 251 | } |
283 | 252 |
|
|
0 commit comments