xref: /linux/security/keys/encrypted-keys/encrypted.c (revision b64cc5fb85f38ae7ca3c67a8fea9ad8c0d068bfa)
17e70cb49SMimi Zohar /*
27e70cb49SMimi Zohar  * Copyright (C) 2010 IBM Corporation
34e561d38SRoberto Sassu  * Copyright (C) 2010 Politecnico di Torino, Italy
44e561d38SRoberto Sassu  *                    TORSEC group -- http://security.polito.it
57e70cb49SMimi Zohar  *
64e561d38SRoberto Sassu  * Authors:
77e70cb49SMimi Zohar  * Mimi Zohar <zohar@us.ibm.com>
84e561d38SRoberto Sassu  * Roberto Sassu <roberto.sassu@polito.it>
97e70cb49SMimi Zohar  *
107e70cb49SMimi Zohar  * This program is free software; you can redistribute it and/or modify
117e70cb49SMimi Zohar  * it under the terms of the GNU General Public License as published by
127e70cb49SMimi Zohar  * the Free Software Foundation, version 2 of the License.
137e70cb49SMimi Zohar  *
14d410fa4eSRandy Dunlap  * See Documentation/security/keys-trusted-encrypted.txt
157e70cb49SMimi Zohar  */
167e70cb49SMimi Zohar 
177e70cb49SMimi Zohar #include <linux/uaccess.h>
187e70cb49SMimi Zohar #include <linux/module.h>
197e70cb49SMimi Zohar #include <linux/init.h>
207e70cb49SMimi Zohar #include <linux/slab.h>
217e70cb49SMimi Zohar #include <linux/parser.h>
227e70cb49SMimi Zohar #include <linux/string.h>
2393ae86e7SMimi Zohar #include <linux/err.h>
247e70cb49SMimi Zohar #include <keys/user-type.h>
257e70cb49SMimi Zohar #include <keys/trusted-type.h>
267e70cb49SMimi Zohar #include <keys/encrypted-type.h>
277e70cb49SMimi Zohar #include <linux/key-type.h>
287e70cb49SMimi Zohar #include <linux/random.h>
297e70cb49SMimi Zohar #include <linux/rcupdate.h>
307e70cb49SMimi Zohar #include <linux/scatterlist.h>
317e70cb49SMimi Zohar #include <linux/crypto.h>
3279a73d18SRoberto Sassu #include <linux/ctype.h>
337e70cb49SMimi Zohar #include <crypto/hash.h>
347e70cb49SMimi Zohar #include <crypto/sha.h>
357e70cb49SMimi Zohar #include <crypto/aes.h>
367e70cb49SMimi Zohar 
37b9703449SMimi Zohar #include "encrypted.h"
3879a73d18SRoberto Sassu #include "ecryptfs_format.h"
397e70cb49SMimi Zohar 
403b1826ceSMimi Zohar static const char KEY_TRUSTED_PREFIX[] = "trusted:";
413b1826ceSMimi Zohar static const char KEY_USER_PREFIX[] = "user:";
427e70cb49SMimi Zohar static const char hash_alg[] = "sha256";
437e70cb49SMimi Zohar static const char hmac_alg[] = "hmac(sha256)";
447e70cb49SMimi Zohar static const char blkcipher_alg[] = "cbc(aes)";
454e561d38SRoberto Sassu static const char key_format_default[] = "default";
4679a73d18SRoberto Sassu static const char key_format_ecryptfs[] = "ecryptfs";
477e70cb49SMimi Zohar static unsigned int ivsize;
487e70cb49SMimi Zohar static int blksize;
497e70cb49SMimi Zohar 
503b1826ceSMimi Zohar #define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
513b1826ceSMimi Zohar #define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
5279a73d18SRoberto Sassu #define KEY_ECRYPTFS_DESC_LEN 16
533b1826ceSMimi Zohar #define HASH_SIZE SHA256_DIGEST_SIZE
543b1826ceSMimi Zohar #define MAX_DATA_SIZE 4096
553b1826ceSMimi Zohar #define MIN_DATA_SIZE  20
563b1826ceSMimi Zohar 
577e70cb49SMimi Zohar struct sdesc {
587e70cb49SMimi Zohar 	struct shash_desc shash;
597e70cb49SMimi Zohar 	char ctx[];
607e70cb49SMimi Zohar };
617e70cb49SMimi Zohar 
627e70cb49SMimi Zohar static struct crypto_shash *hashalg;
637e70cb49SMimi Zohar static struct crypto_shash *hmacalg;
647e70cb49SMimi Zohar 
657e70cb49SMimi Zohar enum {
667e70cb49SMimi Zohar 	Opt_err = -1, Opt_new, Opt_load, Opt_update
677e70cb49SMimi Zohar };
687e70cb49SMimi Zohar 
694e561d38SRoberto Sassu enum {
7079a73d18SRoberto Sassu 	Opt_error = -1, Opt_default, Opt_ecryptfs
714e561d38SRoberto Sassu };
724e561d38SRoberto Sassu 
734e561d38SRoberto Sassu static const match_table_t key_format_tokens = {
744e561d38SRoberto Sassu 	{Opt_default, "default"},
7579a73d18SRoberto Sassu 	{Opt_ecryptfs, "ecryptfs"},
764e561d38SRoberto Sassu 	{Opt_error, NULL}
774e561d38SRoberto Sassu };
784e561d38SRoberto Sassu 
797e70cb49SMimi Zohar static const match_table_t key_tokens = {
807e70cb49SMimi Zohar 	{Opt_new, "new"},
817e70cb49SMimi Zohar 	{Opt_load, "load"},
827e70cb49SMimi Zohar 	{Opt_update, "update"},
837e70cb49SMimi Zohar 	{Opt_err, NULL}
847e70cb49SMimi Zohar };
857e70cb49SMimi Zohar 
867e70cb49SMimi Zohar static int aes_get_sizes(void)
877e70cb49SMimi Zohar {
887e70cb49SMimi Zohar 	struct crypto_blkcipher *tfm;
897e70cb49SMimi Zohar 
907e70cb49SMimi Zohar 	tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
917e70cb49SMimi Zohar 	if (IS_ERR(tfm)) {
927e70cb49SMimi Zohar 		pr_err("encrypted_key: failed to alloc_cipher (%ld)\n",
937e70cb49SMimi Zohar 		       PTR_ERR(tfm));
947e70cb49SMimi Zohar 		return PTR_ERR(tfm);
957e70cb49SMimi Zohar 	}
967e70cb49SMimi Zohar 	ivsize = crypto_blkcipher_ivsize(tfm);
977e70cb49SMimi Zohar 	blksize = crypto_blkcipher_blocksize(tfm);
987e70cb49SMimi Zohar 	crypto_free_blkcipher(tfm);
997e70cb49SMimi Zohar 	return 0;
1007e70cb49SMimi Zohar }
1017e70cb49SMimi Zohar 
1027e70cb49SMimi Zohar /*
10379a73d18SRoberto Sassu  * valid_ecryptfs_desc - verify the description of a new/loaded encrypted key
10479a73d18SRoberto Sassu  *
10579a73d18SRoberto Sassu  * The description of a encrypted key with format 'ecryptfs' must contain
10679a73d18SRoberto Sassu  * exactly 16 hexadecimal characters.
10779a73d18SRoberto Sassu  *
10879a73d18SRoberto Sassu  */
10979a73d18SRoberto Sassu static int valid_ecryptfs_desc(const char *ecryptfs_desc)
11079a73d18SRoberto Sassu {
11179a73d18SRoberto Sassu 	int i;
11279a73d18SRoberto Sassu 
11379a73d18SRoberto Sassu 	if (strlen(ecryptfs_desc) != KEY_ECRYPTFS_DESC_LEN) {
11479a73d18SRoberto Sassu 		pr_err("encrypted_key: key description must be %d hexadecimal "
11579a73d18SRoberto Sassu 		       "characters long\n", KEY_ECRYPTFS_DESC_LEN);
11679a73d18SRoberto Sassu 		return -EINVAL;
11779a73d18SRoberto Sassu 	}
11879a73d18SRoberto Sassu 
11979a73d18SRoberto Sassu 	for (i = 0; i < KEY_ECRYPTFS_DESC_LEN; i++) {
12079a73d18SRoberto Sassu 		if (!isxdigit(ecryptfs_desc[i])) {
12179a73d18SRoberto Sassu 			pr_err("encrypted_key: key description must contain "
12279a73d18SRoberto Sassu 			       "only hexadecimal characters\n");
12379a73d18SRoberto Sassu 			return -EINVAL;
12479a73d18SRoberto Sassu 		}
12579a73d18SRoberto Sassu 	}
12679a73d18SRoberto Sassu 
12779a73d18SRoberto Sassu 	return 0;
12879a73d18SRoberto Sassu }
12979a73d18SRoberto Sassu 
13079a73d18SRoberto Sassu /*
1317e70cb49SMimi Zohar  * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key
1327e70cb49SMimi Zohar  *
13308fa2aa5SRoberto Sassu  * key-type:= "trusted:" | "user:"
1347e70cb49SMimi Zohar  * desc:= master-key description
1357e70cb49SMimi Zohar  *
1367e70cb49SMimi Zohar  * Verify that 'key-type' is valid and that 'desc' exists. On key update,
1377e70cb49SMimi Zohar  * only the master key description is permitted to change, not the key-type.
1387e70cb49SMimi Zohar  * The key-type remains constant.
1397e70cb49SMimi Zohar  *
1407e70cb49SMimi Zohar  * On success returns 0, otherwise -EINVAL.
1417e70cb49SMimi Zohar  */
1427e70cb49SMimi Zohar static int valid_master_desc(const char *new_desc, const char *orig_desc)
1437e70cb49SMimi Zohar {
1447e70cb49SMimi Zohar 	if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) {
1457e70cb49SMimi Zohar 		if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN)
1467e70cb49SMimi Zohar 			goto out;
1477e70cb49SMimi Zohar 		if (orig_desc)
1487e70cb49SMimi Zohar 			if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN))
1497e70cb49SMimi Zohar 				goto out;
1507e70cb49SMimi Zohar 	} else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) {
1517e70cb49SMimi Zohar 		if (strlen(new_desc) == KEY_USER_PREFIX_LEN)
1527e70cb49SMimi Zohar 			goto out;
1537e70cb49SMimi Zohar 		if (orig_desc)
1547e70cb49SMimi Zohar 			if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN))
1557e70cb49SMimi Zohar 				goto out;
1567e70cb49SMimi Zohar 	} else
1577e70cb49SMimi Zohar 		goto out;
1587e70cb49SMimi Zohar 	return 0;
1597e70cb49SMimi Zohar out:
1607e70cb49SMimi Zohar 	return -EINVAL;
1617e70cb49SMimi Zohar }
1627e70cb49SMimi Zohar 
1637e70cb49SMimi Zohar /*
1647e70cb49SMimi Zohar  * datablob_parse - parse the keyctl data
1657e70cb49SMimi Zohar  *
1667e70cb49SMimi Zohar  * datablob format:
1674e561d38SRoberto Sassu  * new [<format>] <master-key name> <decrypted data length>
1684e561d38SRoberto Sassu  * load [<format>] <master-key name> <decrypted data length>
1694e561d38SRoberto Sassu  *     <encrypted iv + data>
1707e70cb49SMimi Zohar  * update <new-master-key name>
1717e70cb49SMimi Zohar  *
1727e70cb49SMimi Zohar  * Tokenizes a copy of the keyctl data, returning a pointer to each token,
1737e70cb49SMimi Zohar  * which is null terminated.
1747e70cb49SMimi Zohar  *
1757e70cb49SMimi Zohar  * On success returns 0, otherwise -EINVAL.
1767e70cb49SMimi Zohar  */
1774e561d38SRoberto Sassu static int datablob_parse(char *datablob, const char **format,
1784e561d38SRoberto Sassu 			  char **master_desc, char **decrypted_datalen,
1794e561d38SRoberto Sassu 			  char **hex_encoded_iv)
1807e70cb49SMimi Zohar {
1817e70cb49SMimi Zohar 	substring_t args[MAX_OPT_ARGS];
1827e70cb49SMimi Zohar 	int ret = -EINVAL;
1837e70cb49SMimi Zohar 	int key_cmd;
1844e561d38SRoberto Sassu 	int key_format;
1854e561d38SRoberto Sassu 	char *p, *keyword;
1867e70cb49SMimi Zohar 
1877103dff0SRoberto Sassu 	keyword = strsep(&datablob, " \t");
1887103dff0SRoberto Sassu 	if (!keyword) {
1897103dff0SRoberto Sassu 		pr_info("encrypted_key: insufficient parameters specified\n");
1907e70cb49SMimi Zohar 		return ret;
1917103dff0SRoberto Sassu 	}
1927103dff0SRoberto Sassu 	key_cmd = match_token(keyword, key_tokens, args);
1937e70cb49SMimi Zohar 
19479a73d18SRoberto Sassu 	/* Get optional format: default | ecryptfs */
1954e561d38SRoberto Sassu 	p = strsep(&datablob, " \t");
1964e561d38SRoberto Sassu 	if (!p) {
1974e561d38SRoberto Sassu 		pr_err("encrypted_key: insufficient parameters specified\n");
1984e561d38SRoberto Sassu 		return ret;
1994e561d38SRoberto Sassu 	}
2004e561d38SRoberto Sassu 
2014e561d38SRoberto Sassu 	key_format = match_token(p, key_format_tokens, args);
2024e561d38SRoberto Sassu 	switch (key_format) {
20379a73d18SRoberto Sassu 	case Opt_ecryptfs:
2044e561d38SRoberto Sassu 	case Opt_default:
2054e561d38SRoberto Sassu 		*format = p;
2067e70cb49SMimi Zohar 		*master_desc = strsep(&datablob, " \t");
2074e561d38SRoberto Sassu 		break;
2084e561d38SRoberto Sassu 	case Opt_error:
2094e561d38SRoberto Sassu 		*master_desc = p;
2104e561d38SRoberto Sassu 		break;
2114e561d38SRoberto Sassu 	}
2124e561d38SRoberto Sassu 
2137103dff0SRoberto Sassu 	if (!*master_desc) {
2147103dff0SRoberto Sassu 		pr_info("encrypted_key: master key parameter is missing\n");
2157e70cb49SMimi Zohar 		goto out;
2167103dff0SRoberto Sassu 	}
2177e70cb49SMimi Zohar 
2187103dff0SRoberto Sassu 	if (valid_master_desc(*master_desc, NULL) < 0) {
2197103dff0SRoberto Sassu 		pr_info("encrypted_key: master key parameter \'%s\' "
2207103dff0SRoberto Sassu 			"is invalid\n", *master_desc);
2217e70cb49SMimi Zohar 		goto out;
2227103dff0SRoberto Sassu 	}
2237e70cb49SMimi Zohar 
2247e70cb49SMimi Zohar 	if (decrypted_datalen) {
2257e70cb49SMimi Zohar 		*decrypted_datalen = strsep(&datablob, " \t");
2267103dff0SRoberto Sassu 		if (!*decrypted_datalen) {
2277103dff0SRoberto Sassu 			pr_info("encrypted_key: keylen parameter is missing\n");
2287e70cb49SMimi Zohar 			goto out;
2297e70cb49SMimi Zohar 		}
2307103dff0SRoberto Sassu 	}
2317e70cb49SMimi Zohar 
2327e70cb49SMimi Zohar 	switch (key_cmd) {
2337e70cb49SMimi Zohar 	case Opt_new:
2347103dff0SRoberto Sassu 		if (!decrypted_datalen) {
2357103dff0SRoberto Sassu 			pr_info("encrypted_key: keyword \'%s\' not allowed "
2367103dff0SRoberto Sassu 				"when called from .update method\n", keyword);
2377e70cb49SMimi Zohar 			break;
2387103dff0SRoberto Sassu 		}
2397e70cb49SMimi Zohar 		ret = 0;
2407e70cb49SMimi Zohar 		break;
2417e70cb49SMimi Zohar 	case Opt_load:
2427103dff0SRoberto Sassu 		if (!decrypted_datalen) {
2437103dff0SRoberto Sassu 			pr_info("encrypted_key: keyword \'%s\' not allowed "
2447103dff0SRoberto Sassu 				"when called from .update method\n", keyword);
2457e70cb49SMimi Zohar 			break;
2467103dff0SRoberto Sassu 		}
2477e70cb49SMimi Zohar 		*hex_encoded_iv = strsep(&datablob, " \t");
2487103dff0SRoberto Sassu 		if (!*hex_encoded_iv) {
2497103dff0SRoberto Sassu 			pr_info("encrypted_key: hex blob is missing\n");
2507e70cb49SMimi Zohar 			break;
2517103dff0SRoberto Sassu 		}
2527e70cb49SMimi Zohar 		ret = 0;
2537e70cb49SMimi Zohar 		break;
2547e70cb49SMimi Zohar 	case Opt_update:
2557103dff0SRoberto Sassu 		if (decrypted_datalen) {
2567103dff0SRoberto Sassu 			pr_info("encrypted_key: keyword \'%s\' not allowed "
2577103dff0SRoberto Sassu 				"when called from .instantiate method\n",
2587103dff0SRoberto Sassu 				keyword);
2597e70cb49SMimi Zohar 			break;
2607103dff0SRoberto Sassu 		}
2617e70cb49SMimi Zohar 		ret = 0;
2627e70cb49SMimi Zohar 		break;
2637e70cb49SMimi Zohar 	case Opt_err:
2647103dff0SRoberto Sassu 		pr_info("encrypted_key: keyword \'%s\' not recognized\n",
2657103dff0SRoberto Sassu 			keyword);
2667e70cb49SMimi Zohar 		break;
2677e70cb49SMimi Zohar 	}
2687e70cb49SMimi Zohar out:
2697e70cb49SMimi Zohar 	return ret;
2707e70cb49SMimi Zohar }
2717e70cb49SMimi Zohar 
2727e70cb49SMimi Zohar /*
2737e70cb49SMimi Zohar  * datablob_format - format as an ascii string, before copying to userspace
2747e70cb49SMimi Zohar  */
2757e70cb49SMimi Zohar static char *datablob_format(struct encrypted_key_payload *epayload,
2767e70cb49SMimi Zohar 			     size_t asciiblob_len)
2777e70cb49SMimi Zohar {
2787e70cb49SMimi Zohar 	char *ascii_buf, *bufp;
2797e70cb49SMimi Zohar 	u8 *iv = epayload->iv;
2807e70cb49SMimi Zohar 	int len;
2817e70cb49SMimi Zohar 	int i;
2827e70cb49SMimi Zohar 
2837e70cb49SMimi Zohar 	ascii_buf = kmalloc(asciiblob_len + 1, GFP_KERNEL);
2847e70cb49SMimi Zohar 	if (!ascii_buf)
2857e70cb49SMimi Zohar 		goto out;
2867e70cb49SMimi Zohar 
2877e70cb49SMimi Zohar 	ascii_buf[asciiblob_len] = '\0';
2887e70cb49SMimi Zohar 
2897e70cb49SMimi Zohar 	/* copy datablob master_desc and datalen strings */
2904e561d38SRoberto Sassu 	len = sprintf(ascii_buf, "%s %s %s ", epayload->format,
2914e561d38SRoberto Sassu 		      epayload->master_desc, epayload->datalen);
2927e70cb49SMimi Zohar 
2937e70cb49SMimi Zohar 	/* convert the hex encoded iv, encrypted-data and HMAC to ascii */
2947e70cb49SMimi Zohar 	bufp = &ascii_buf[len];
2957e70cb49SMimi Zohar 	for (i = 0; i < (asciiblob_len - len) / 2; i++)
29602473119SAndy Shevchenko 		bufp = hex_byte_pack(bufp, iv[i]);
2977e70cb49SMimi Zohar out:
2987e70cb49SMimi Zohar 	return ascii_buf;
2997e70cb49SMimi Zohar }
3007e70cb49SMimi Zohar 
3017e70cb49SMimi Zohar /*
3027e70cb49SMimi Zohar  * request_user_key - request the user key
3037e70cb49SMimi Zohar  *
3047e70cb49SMimi Zohar  * Use a user provided key to encrypt/decrypt an encrypted-key.
3057e70cb49SMimi Zohar  */
3067e70cb49SMimi Zohar static struct key *request_user_key(const char *master_desc, u8 **master_key,
3073b1826ceSMimi Zohar 				    size_t *master_keylen)
3087e70cb49SMimi Zohar {
3097e70cb49SMimi Zohar 	struct user_key_payload *upayload;
3107e70cb49SMimi Zohar 	struct key *ukey;
3117e70cb49SMimi Zohar 
3127e70cb49SMimi Zohar 	ukey = request_key(&key_type_user, master_desc, NULL);
3137e70cb49SMimi Zohar 	if (IS_ERR(ukey))
3147e70cb49SMimi Zohar 		goto error;
3157e70cb49SMimi Zohar 
3167e70cb49SMimi Zohar 	down_read(&ukey->sem);
3176ac6172aSMimi Zohar 	upayload = ukey->payload.data;
3187e70cb49SMimi Zohar 	*master_key = upayload->data;
3197e70cb49SMimi Zohar 	*master_keylen = upayload->datalen;
3207e70cb49SMimi Zohar error:
3217e70cb49SMimi Zohar 	return ukey;
3227e70cb49SMimi Zohar }
3237e70cb49SMimi Zohar 
3243b1826ceSMimi Zohar static struct sdesc *alloc_sdesc(struct crypto_shash *alg)
3257e70cb49SMimi Zohar {
3267e70cb49SMimi Zohar 	struct sdesc *sdesc;
3277e70cb49SMimi Zohar 	int size;
3287e70cb49SMimi Zohar 
3297e70cb49SMimi Zohar 	size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
3307e70cb49SMimi Zohar 	sdesc = kmalloc(size, GFP_KERNEL);
3317e70cb49SMimi Zohar 	if (!sdesc)
3327e70cb49SMimi Zohar 		return ERR_PTR(-ENOMEM);
3337e70cb49SMimi Zohar 	sdesc->shash.tfm = alg;
3347e70cb49SMimi Zohar 	sdesc->shash.flags = 0x0;
3357e70cb49SMimi Zohar 	return sdesc;
3367e70cb49SMimi Zohar }
3377e70cb49SMimi Zohar 
3383b1826ceSMimi Zohar static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen,
3393b1826ceSMimi Zohar 		     const u8 *buf, unsigned int buflen)
3407e70cb49SMimi Zohar {
3417e70cb49SMimi Zohar 	struct sdesc *sdesc;
3427e70cb49SMimi Zohar 	int ret;
3437e70cb49SMimi Zohar 
3443b1826ceSMimi Zohar 	sdesc = alloc_sdesc(hmacalg);
3457e70cb49SMimi Zohar 	if (IS_ERR(sdesc)) {
3467e70cb49SMimi Zohar 		pr_info("encrypted_key: can't alloc %s\n", hmac_alg);
3477e70cb49SMimi Zohar 		return PTR_ERR(sdesc);
3487e70cb49SMimi Zohar 	}
3497e70cb49SMimi Zohar 
3507e70cb49SMimi Zohar 	ret = crypto_shash_setkey(hmacalg, key, keylen);
3517e70cb49SMimi Zohar 	if (!ret)
3527e70cb49SMimi Zohar 		ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
3537e70cb49SMimi Zohar 	kfree(sdesc);
3547e70cb49SMimi Zohar 	return ret;
3557e70cb49SMimi Zohar }
3567e70cb49SMimi Zohar 
3573b1826ceSMimi Zohar static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen)
3587e70cb49SMimi Zohar {
3597e70cb49SMimi Zohar 	struct sdesc *sdesc;
3607e70cb49SMimi Zohar 	int ret;
3617e70cb49SMimi Zohar 
3623b1826ceSMimi Zohar 	sdesc = alloc_sdesc(hashalg);
3637e70cb49SMimi Zohar 	if (IS_ERR(sdesc)) {
3647e70cb49SMimi Zohar 		pr_info("encrypted_key: can't alloc %s\n", hash_alg);
3657e70cb49SMimi Zohar 		return PTR_ERR(sdesc);
3667e70cb49SMimi Zohar 	}
3677e70cb49SMimi Zohar 
3687e70cb49SMimi Zohar 	ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest);
3697e70cb49SMimi Zohar 	kfree(sdesc);
3707e70cb49SMimi Zohar 	return ret;
3717e70cb49SMimi Zohar }
3727e70cb49SMimi Zohar 
3737e70cb49SMimi Zohar enum derived_key_type { ENC_KEY, AUTH_KEY };
3747e70cb49SMimi Zohar 
3757e70cb49SMimi Zohar /* Derive authentication/encryption key from trusted key */
3767e70cb49SMimi Zohar static int get_derived_key(u8 *derived_key, enum derived_key_type key_type,
3773b1826ceSMimi Zohar 			   const u8 *master_key, size_t master_keylen)
3787e70cb49SMimi Zohar {
3797e70cb49SMimi Zohar 	u8 *derived_buf;
3807e70cb49SMimi Zohar 	unsigned int derived_buf_len;
3817e70cb49SMimi Zohar 	int ret;
3827e70cb49SMimi Zohar 
3837e70cb49SMimi Zohar 	derived_buf_len = strlen("AUTH_KEY") + 1 + master_keylen;
3847e70cb49SMimi Zohar 	if (derived_buf_len < HASH_SIZE)
3857e70cb49SMimi Zohar 		derived_buf_len = HASH_SIZE;
3867e70cb49SMimi Zohar 
3877e70cb49SMimi Zohar 	derived_buf = kzalloc(derived_buf_len, GFP_KERNEL);
3887e70cb49SMimi Zohar 	if (!derived_buf) {
3897e70cb49SMimi Zohar 		pr_err("encrypted_key: out of memory\n");
3907e70cb49SMimi Zohar 		return -ENOMEM;
3917e70cb49SMimi Zohar 	}
3927e70cb49SMimi Zohar 	if (key_type)
3937e70cb49SMimi Zohar 		strcpy(derived_buf, "AUTH_KEY");
3947e70cb49SMimi Zohar 	else
3957e70cb49SMimi Zohar 		strcpy(derived_buf, "ENC_KEY");
3967e70cb49SMimi Zohar 
3977e70cb49SMimi Zohar 	memcpy(derived_buf + strlen(derived_buf) + 1, master_key,
3987e70cb49SMimi Zohar 	       master_keylen);
3997e70cb49SMimi Zohar 	ret = calc_hash(derived_key, derived_buf, derived_buf_len);
4007e70cb49SMimi Zohar 	kfree(derived_buf);
4017e70cb49SMimi Zohar 	return ret;
4027e70cb49SMimi Zohar }
4037e70cb49SMimi Zohar 
4047e70cb49SMimi Zohar static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key,
4053b1826ceSMimi Zohar 			       unsigned int key_len, const u8 *iv,
4063b1826ceSMimi Zohar 			       unsigned int ivsize)
4077e70cb49SMimi Zohar {
4087e70cb49SMimi Zohar 	int ret;
4097e70cb49SMimi Zohar 
4107e70cb49SMimi Zohar 	desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC);
4117e70cb49SMimi Zohar 	if (IS_ERR(desc->tfm)) {
4127e70cb49SMimi Zohar 		pr_err("encrypted_key: failed to load %s transform (%ld)\n",
4137e70cb49SMimi Zohar 		       blkcipher_alg, PTR_ERR(desc->tfm));
4147e70cb49SMimi Zohar 		return PTR_ERR(desc->tfm);
4157e70cb49SMimi Zohar 	}
4167e70cb49SMimi Zohar 	desc->flags = 0;
4177e70cb49SMimi Zohar 
4187e70cb49SMimi Zohar 	ret = crypto_blkcipher_setkey(desc->tfm, key, key_len);
4197e70cb49SMimi Zohar 	if (ret < 0) {
4207e70cb49SMimi Zohar 		pr_err("encrypted_key: failed to setkey (%d)\n", ret);
4217e70cb49SMimi Zohar 		crypto_free_blkcipher(desc->tfm);
4227e70cb49SMimi Zohar 		return ret;
4237e70cb49SMimi Zohar 	}
4247e70cb49SMimi Zohar 	crypto_blkcipher_set_iv(desc->tfm, iv, ivsize);
4257e70cb49SMimi Zohar 	return 0;
4267e70cb49SMimi Zohar }
4277e70cb49SMimi Zohar 
4287e70cb49SMimi Zohar static struct key *request_master_key(struct encrypted_key_payload *epayload,
4293b1826ceSMimi Zohar 				      u8 **master_key, size_t *master_keylen)
4307e70cb49SMimi Zohar {
4317e70cb49SMimi Zohar 	struct key *mkey = NULL;
4327e70cb49SMimi Zohar 
4337e70cb49SMimi Zohar 	if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX,
4347e70cb49SMimi Zohar 		     KEY_TRUSTED_PREFIX_LEN)) {
4357e70cb49SMimi Zohar 		mkey = request_trusted_key(epayload->master_desc +
4367e70cb49SMimi Zohar 					   KEY_TRUSTED_PREFIX_LEN,
4377e70cb49SMimi Zohar 					   master_key, master_keylen);
4387e70cb49SMimi Zohar 	} else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX,
4397e70cb49SMimi Zohar 			    KEY_USER_PREFIX_LEN)) {
4407e70cb49SMimi Zohar 		mkey = request_user_key(epayload->master_desc +
4417e70cb49SMimi Zohar 					KEY_USER_PREFIX_LEN,
4427e70cb49SMimi Zohar 					master_key, master_keylen);
4437e70cb49SMimi Zohar 	} else
4447e70cb49SMimi Zohar 		goto out;
4457e70cb49SMimi Zohar 
446f91c2c5cSRoberto Sassu 	if (IS_ERR(mkey)) {
447f4a0d5abSMimi Zohar 		int ret = PTR_ERR(mkey);
448982e617aSMimi Zohar 
449982e617aSMimi Zohar 		if (ret == -ENOTSUPP)
450982e617aSMimi Zohar 			pr_info("encrypted_key: key %s not supported",
451982e617aSMimi Zohar 				epayload->master_desc);
452982e617aSMimi Zohar 		else
4537e70cb49SMimi Zohar 			pr_info("encrypted_key: key %s not found",
4547e70cb49SMimi Zohar 				epayload->master_desc);
455f91c2c5cSRoberto Sassu 		goto out;
456f91c2c5cSRoberto Sassu 	}
457f91c2c5cSRoberto Sassu 
4587e70cb49SMimi Zohar 	dump_master_key(*master_key, *master_keylen);
4597e70cb49SMimi Zohar out:
4607e70cb49SMimi Zohar 	return mkey;
4617e70cb49SMimi Zohar }
4627e70cb49SMimi Zohar 
4637e70cb49SMimi Zohar /* Before returning data to userspace, encrypt decrypted data. */
4647e70cb49SMimi Zohar static int derived_key_encrypt(struct encrypted_key_payload *epayload,
4657e70cb49SMimi Zohar 			       const u8 *derived_key,
4663b1826ceSMimi Zohar 			       unsigned int derived_keylen)
4677e70cb49SMimi Zohar {
4687e70cb49SMimi Zohar 	struct scatterlist sg_in[2];
4697e70cb49SMimi Zohar 	struct scatterlist sg_out[1];
4707e70cb49SMimi Zohar 	struct blkcipher_desc desc;
4717e70cb49SMimi Zohar 	unsigned int encrypted_datalen;
4727e70cb49SMimi Zohar 	unsigned int padlen;
4737e70cb49SMimi Zohar 	char pad[16];
4747e70cb49SMimi Zohar 	int ret;
4757e70cb49SMimi Zohar 
4767e70cb49SMimi Zohar 	encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
4777e70cb49SMimi Zohar 	padlen = encrypted_datalen - epayload->decrypted_datalen;
4787e70cb49SMimi Zohar 
4797e70cb49SMimi Zohar 	ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
4807e70cb49SMimi Zohar 				  epayload->iv, ivsize);
4817e70cb49SMimi Zohar 	if (ret < 0)
4827e70cb49SMimi Zohar 		goto out;
4837e70cb49SMimi Zohar 	dump_decrypted_data(epayload);
4847e70cb49SMimi Zohar 
4857e70cb49SMimi Zohar 	memset(pad, 0, sizeof pad);
4867e70cb49SMimi Zohar 	sg_init_table(sg_in, 2);
4877e70cb49SMimi Zohar 	sg_set_buf(&sg_in[0], epayload->decrypted_data,
4887e70cb49SMimi Zohar 		   epayload->decrypted_datalen);
4897e70cb49SMimi Zohar 	sg_set_buf(&sg_in[1], pad, padlen);
4907e70cb49SMimi Zohar 
4917e70cb49SMimi Zohar 	sg_init_table(sg_out, 1);
4927e70cb49SMimi Zohar 	sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen);
4937e70cb49SMimi Zohar 
4947e70cb49SMimi Zohar 	ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen);
4957e70cb49SMimi Zohar 	crypto_free_blkcipher(desc.tfm);
4967e70cb49SMimi Zohar 	if (ret < 0)
4977e70cb49SMimi Zohar 		pr_err("encrypted_key: failed to encrypt (%d)\n", ret);
4987e70cb49SMimi Zohar 	else
4997e70cb49SMimi Zohar 		dump_encrypted_data(epayload, encrypted_datalen);
5007e70cb49SMimi Zohar out:
5017e70cb49SMimi Zohar 	return ret;
5027e70cb49SMimi Zohar }
5037e70cb49SMimi Zohar 
5047e70cb49SMimi Zohar static int datablob_hmac_append(struct encrypted_key_payload *epayload,
5053b1826ceSMimi Zohar 				const u8 *master_key, size_t master_keylen)
5067e70cb49SMimi Zohar {
5077e70cb49SMimi Zohar 	u8 derived_key[HASH_SIZE];
5087e70cb49SMimi Zohar 	u8 *digest;
5097e70cb49SMimi Zohar 	int ret;
5107e70cb49SMimi Zohar 
5117e70cb49SMimi Zohar 	ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
5127e70cb49SMimi Zohar 	if (ret < 0)
5137e70cb49SMimi Zohar 		goto out;
5147e70cb49SMimi Zohar 
5154e561d38SRoberto Sassu 	digest = epayload->format + epayload->datablob_len;
5167e70cb49SMimi Zohar 	ret = calc_hmac(digest, derived_key, sizeof derived_key,
5174e561d38SRoberto Sassu 			epayload->format, epayload->datablob_len);
5187e70cb49SMimi Zohar 	if (!ret)
5197e70cb49SMimi Zohar 		dump_hmac(NULL, digest, HASH_SIZE);
5207e70cb49SMimi Zohar out:
5217e70cb49SMimi Zohar 	return ret;
5227e70cb49SMimi Zohar }
5237e70cb49SMimi Zohar 
5247e70cb49SMimi Zohar /* verify HMAC before decrypting encrypted key */
5257e70cb49SMimi Zohar static int datablob_hmac_verify(struct encrypted_key_payload *epayload,
5264e561d38SRoberto Sassu 				const u8 *format, const u8 *master_key,
5274e561d38SRoberto Sassu 				size_t master_keylen)
5287e70cb49SMimi Zohar {
5297e70cb49SMimi Zohar 	u8 derived_key[HASH_SIZE];
5307e70cb49SMimi Zohar 	u8 digest[HASH_SIZE];
5317e70cb49SMimi Zohar 	int ret;
5324e561d38SRoberto Sassu 	char *p;
5334e561d38SRoberto Sassu 	unsigned short len;
5347e70cb49SMimi Zohar 
5357e70cb49SMimi Zohar 	ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen);
5367e70cb49SMimi Zohar 	if (ret < 0)
5377e70cb49SMimi Zohar 		goto out;
5387e70cb49SMimi Zohar 
5394e561d38SRoberto Sassu 	len = epayload->datablob_len;
5404e561d38SRoberto Sassu 	if (!format) {
5414e561d38SRoberto Sassu 		p = epayload->master_desc;
5424e561d38SRoberto Sassu 		len -= strlen(epayload->format) + 1;
5434e561d38SRoberto Sassu 	} else
5444e561d38SRoberto Sassu 		p = epayload->format;
5454e561d38SRoberto Sassu 
5464e561d38SRoberto Sassu 	ret = calc_hmac(digest, derived_key, sizeof derived_key, p, len);
5477e70cb49SMimi Zohar 	if (ret < 0)
5487e70cb49SMimi Zohar 		goto out;
5494e561d38SRoberto Sassu 	ret = memcmp(digest, epayload->format + epayload->datablob_len,
5507e70cb49SMimi Zohar 		     sizeof digest);
5517e70cb49SMimi Zohar 	if (ret) {
5527e70cb49SMimi Zohar 		ret = -EINVAL;
5537e70cb49SMimi Zohar 		dump_hmac("datablob",
5544e561d38SRoberto Sassu 			  epayload->format + epayload->datablob_len,
5557e70cb49SMimi Zohar 			  HASH_SIZE);
5567e70cb49SMimi Zohar 		dump_hmac("calc", digest, HASH_SIZE);
5577e70cb49SMimi Zohar 	}
5587e70cb49SMimi Zohar out:
5597e70cb49SMimi Zohar 	return ret;
5607e70cb49SMimi Zohar }
5617e70cb49SMimi Zohar 
5627e70cb49SMimi Zohar static int derived_key_decrypt(struct encrypted_key_payload *epayload,
5637e70cb49SMimi Zohar 			       const u8 *derived_key,
5643b1826ceSMimi Zohar 			       unsigned int derived_keylen)
5657e70cb49SMimi Zohar {
5667e70cb49SMimi Zohar 	struct scatterlist sg_in[1];
5677e70cb49SMimi Zohar 	struct scatterlist sg_out[2];
5687e70cb49SMimi Zohar 	struct blkcipher_desc desc;
5697e70cb49SMimi Zohar 	unsigned int encrypted_datalen;
5707e70cb49SMimi Zohar 	char pad[16];
5717e70cb49SMimi Zohar 	int ret;
5727e70cb49SMimi Zohar 
5737e70cb49SMimi Zohar 	encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
5747e70cb49SMimi Zohar 	ret = init_blkcipher_desc(&desc, derived_key, derived_keylen,
5757e70cb49SMimi Zohar 				  epayload->iv, ivsize);
5767e70cb49SMimi Zohar 	if (ret < 0)
5777e70cb49SMimi Zohar 		goto out;
5787e70cb49SMimi Zohar 	dump_encrypted_data(epayload, encrypted_datalen);
5797e70cb49SMimi Zohar 
5807e70cb49SMimi Zohar 	memset(pad, 0, sizeof pad);
5817e70cb49SMimi Zohar 	sg_init_table(sg_in, 1);
5827e70cb49SMimi Zohar 	sg_init_table(sg_out, 2);
5837e70cb49SMimi Zohar 	sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen);
5847e70cb49SMimi Zohar 	sg_set_buf(&sg_out[0], epayload->decrypted_data,
5853b1826ceSMimi Zohar 		   epayload->decrypted_datalen);
5867e70cb49SMimi Zohar 	sg_set_buf(&sg_out[1], pad, sizeof pad);
5877e70cb49SMimi Zohar 
5887e70cb49SMimi Zohar 	ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, encrypted_datalen);
5897e70cb49SMimi Zohar 	crypto_free_blkcipher(desc.tfm);
5907e70cb49SMimi Zohar 	if (ret < 0)
5917e70cb49SMimi Zohar 		goto out;
5927e70cb49SMimi Zohar 	dump_decrypted_data(epayload);
5937e70cb49SMimi Zohar out:
5947e70cb49SMimi Zohar 	return ret;
5957e70cb49SMimi Zohar }
5967e70cb49SMimi Zohar 
5977e70cb49SMimi Zohar /* Allocate memory for decrypted key and datablob. */
5987e70cb49SMimi Zohar static struct encrypted_key_payload *encrypted_key_alloc(struct key *key,
5994e561d38SRoberto Sassu 							 const char *format,
6007e70cb49SMimi Zohar 							 const char *master_desc,
6017e70cb49SMimi Zohar 							 const char *datalen)
6027e70cb49SMimi Zohar {
6037e70cb49SMimi Zohar 	struct encrypted_key_payload *epayload = NULL;
6047e70cb49SMimi Zohar 	unsigned short datablob_len;
6057e70cb49SMimi Zohar 	unsigned short decrypted_datalen;
6064e561d38SRoberto Sassu 	unsigned short payload_datalen;
6077e70cb49SMimi Zohar 	unsigned int encrypted_datalen;
6084e561d38SRoberto Sassu 	unsigned int format_len;
6097e70cb49SMimi Zohar 	long dlen;
6107e70cb49SMimi Zohar 	int ret;
6117e70cb49SMimi Zohar 
61229707b20SJingoo Han 	ret = kstrtol(datalen, 10, &dlen);
6137e70cb49SMimi Zohar 	if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE)
6147e70cb49SMimi Zohar 		return ERR_PTR(-EINVAL);
6157e70cb49SMimi Zohar 
6164e561d38SRoberto Sassu 	format_len = (!format) ? strlen(key_format_default) : strlen(format);
6177e70cb49SMimi Zohar 	decrypted_datalen = dlen;
6184e561d38SRoberto Sassu 	payload_datalen = decrypted_datalen;
61979a73d18SRoberto Sassu 	if (format && !strcmp(format, key_format_ecryptfs)) {
62079a73d18SRoberto Sassu 		if (dlen != ECRYPTFS_MAX_KEY_BYTES) {
62179a73d18SRoberto Sassu 			pr_err("encrypted_key: keylen for the ecryptfs format "
62279a73d18SRoberto Sassu 			       "must be equal to %d bytes\n",
62379a73d18SRoberto Sassu 			       ECRYPTFS_MAX_KEY_BYTES);
62479a73d18SRoberto Sassu 			return ERR_PTR(-EINVAL);
62579a73d18SRoberto Sassu 		}
62679a73d18SRoberto Sassu 		decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES;
62779a73d18SRoberto Sassu 		payload_datalen = sizeof(struct ecryptfs_auth_tok);
62879a73d18SRoberto Sassu 	}
62979a73d18SRoberto Sassu 
6307e70cb49SMimi Zohar 	encrypted_datalen = roundup(decrypted_datalen, blksize);
6317e70cb49SMimi Zohar 
6324e561d38SRoberto Sassu 	datablob_len = format_len + 1 + strlen(master_desc) + 1
6334e561d38SRoberto Sassu 	    + strlen(datalen) + 1 + ivsize + 1 + encrypted_datalen;
6347e70cb49SMimi Zohar 
6354e561d38SRoberto Sassu 	ret = key_payload_reserve(key, payload_datalen + datablob_len
6367e70cb49SMimi Zohar 				  + HASH_SIZE + 1);
6377e70cb49SMimi Zohar 	if (ret < 0)
6387e70cb49SMimi Zohar 		return ERR_PTR(ret);
6397e70cb49SMimi Zohar 
6404e561d38SRoberto Sassu 	epayload = kzalloc(sizeof(*epayload) + payload_datalen +
6417e70cb49SMimi Zohar 			   datablob_len + HASH_SIZE + 1, GFP_KERNEL);
6427e70cb49SMimi Zohar 	if (!epayload)
6437e70cb49SMimi Zohar 		return ERR_PTR(-ENOMEM);
6447e70cb49SMimi Zohar 
6454e561d38SRoberto Sassu 	epayload->payload_datalen = payload_datalen;
6467e70cb49SMimi Zohar 	epayload->decrypted_datalen = decrypted_datalen;
6477e70cb49SMimi Zohar 	epayload->datablob_len = datablob_len;
6487e70cb49SMimi Zohar 	return epayload;
6497e70cb49SMimi Zohar }
6507e70cb49SMimi Zohar 
6517e70cb49SMimi Zohar static int encrypted_key_decrypt(struct encrypted_key_payload *epayload,
6524e561d38SRoberto Sassu 				 const char *format, const char *hex_encoded_iv)
6537e70cb49SMimi Zohar {
6547e70cb49SMimi Zohar 	struct key *mkey;
6557e70cb49SMimi Zohar 	u8 derived_key[HASH_SIZE];
6567e70cb49SMimi Zohar 	u8 *master_key;
6577e70cb49SMimi Zohar 	u8 *hmac;
6581f35065aSMimi Zohar 	const char *hex_encoded_data;
6597e70cb49SMimi Zohar 	unsigned int encrypted_datalen;
6603b1826ceSMimi Zohar 	size_t master_keylen;
6611f35065aSMimi Zohar 	size_t asciilen;
6627e70cb49SMimi Zohar 	int ret;
6637e70cb49SMimi Zohar 
6647e70cb49SMimi Zohar 	encrypted_datalen = roundup(epayload->decrypted_datalen, blksize);
6651f35065aSMimi Zohar 	asciilen = (ivsize + 1 + encrypted_datalen + HASH_SIZE) * 2;
6661f35065aSMimi Zohar 	if (strlen(hex_encoded_iv) != asciilen)
6671f35065aSMimi Zohar 		return -EINVAL;
6681f35065aSMimi Zohar 
6691f35065aSMimi Zohar 	hex_encoded_data = hex_encoded_iv + (2 * ivsize) + 2;
6702b3ff631SMimi Zohar 	ret = hex2bin(epayload->iv, hex_encoded_iv, ivsize);
6712b3ff631SMimi Zohar 	if (ret < 0)
6722b3ff631SMimi Zohar 		return -EINVAL;
6732b3ff631SMimi Zohar 	ret = hex2bin(epayload->encrypted_data, hex_encoded_data,
6742b3ff631SMimi Zohar 		      encrypted_datalen);
6752b3ff631SMimi Zohar 	if (ret < 0)
6762b3ff631SMimi Zohar 		return -EINVAL;
6777e70cb49SMimi Zohar 
6784e561d38SRoberto Sassu 	hmac = epayload->format + epayload->datablob_len;
6792b3ff631SMimi Zohar 	ret = hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2),
6802b3ff631SMimi Zohar 		      HASH_SIZE);
6812b3ff631SMimi Zohar 	if (ret < 0)
6822b3ff631SMimi Zohar 		return -EINVAL;
6837e70cb49SMimi Zohar 
6847e70cb49SMimi Zohar 	mkey = request_master_key(epayload, &master_key, &master_keylen);
6857e70cb49SMimi Zohar 	if (IS_ERR(mkey))
6867e70cb49SMimi Zohar 		return PTR_ERR(mkey);
6877e70cb49SMimi Zohar 
6884e561d38SRoberto Sassu 	ret = datablob_hmac_verify(epayload, format, master_key, master_keylen);
6897e70cb49SMimi Zohar 	if (ret < 0) {
6907e70cb49SMimi Zohar 		pr_err("encrypted_key: bad hmac (%d)\n", ret);
6917e70cb49SMimi Zohar 		goto out;
6927e70cb49SMimi Zohar 	}
6937e70cb49SMimi Zohar 
6947e70cb49SMimi Zohar 	ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
6957e70cb49SMimi Zohar 	if (ret < 0)
6967e70cb49SMimi Zohar 		goto out;
6977e70cb49SMimi Zohar 
6987e70cb49SMimi Zohar 	ret = derived_key_decrypt(epayload, derived_key, sizeof derived_key);
6997e70cb49SMimi Zohar 	if (ret < 0)
7007e70cb49SMimi Zohar 		pr_err("encrypted_key: failed to decrypt key (%d)\n", ret);
7017e70cb49SMimi Zohar out:
7027e70cb49SMimi Zohar 	up_read(&mkey->sem);
7037e70cb49SMimi Zohar 	key_put(mkey);
7047e70cb49SMimi Zohar 	return ret;
7057e70cb49SMimi Zohar }
7067e70cb49SMimi Zohar 
7077e70cb49SMimi Zohar static void __ekey_init(struct encrypted_key_payload *epayload,
7084e561d38SRoberto Sassu 			const char *format, const char *master_desc,
7094e561d38SRoberto Sassu 			const char *datalen)
7107e70cb49SMimi Zohar {
7114e561d38SRoberto Sassu 	unsigned int format_len;
7124e561d38SRoberto Sassu 
7134e561d38SRoberto Sassu 	format_len = (!format) ? strlen(key_format_default) : strlen(format);
7144e561d38SRoberto Sassu 	epayload->format = epayload->payload_data + epayload->payload_datalen;
7154e561d38SRoberto Sassu 	epayload->master_desc = epayload->format + format_len + 1;
7167e70cb49SMimi Zohar 	epayload->datalen = epayload->master_desc + strlen(master_desc) + 1;
7177e70cb49SMimi Zohar 	epayload->iv = epayload->datalen + strlen(datalen) + 1;
7187e70cb49SMimi Zohar 	epayload->encrypted_data = epayload->iv + ivsize + 1;
7194e561d38SRoberto Sassu 	epayload->decrypted_data = epayload->payload_data;
7207e70cb49SMimi Zohar 
7214e561d38SRoberto Sassu 	if (!format)
7224e561d38SRoberto Sassu 		memcpy(epayload->format, key_format_default, format_len);
72379a73d18SRoberto Sassu 	else {
72479a73d18SRoberto Sassu 		if (!strcmp(format, key_format_ecryptfs))
72579a73d18SRoberto Sassu 			epayload->decrypted_data =
72679a73d18SRoberto Sassu 				ecryptfs_get_auth_tok_key((struct ecryptfs_auth_tok *)epayload->payload_data);
72779a73d18SRoberto Sassu 
7284e561d38SRoberto Sassu 		memcpy(epayload->format, format, format_len);
72979a73d18SRoberto Sassu 	}
73079a73d18SRoberto Sassu 
7317e70cb49SMimi Zohar 	memcpy(epayload->master_desc, master_desc, strlen(master_desc));
7327e70cb49SMimi Zohar 	memcpy(epayload->datalen, datalen, strlen(datalen));
7337e70cb49SMimi Zohar }
7347e70cb49SMimi Zohar 
7357e70cb49SMimi Zohar /*
7367e70cb49SMimi Zohar  * encrypted_init - initialize an encrypted key
7377e70cb49SMimi Zohar  *
7387e70cb49SMimi Zohar  * For a new key, use a random number for both the iv and data
7397e70cb49SMimi Zohar  * itself.  For an old key, decrypt the hex encoded data.
7407e70cb49SMimi Zohar  */
7417e70cb49SMimi Zohar static int encrypted_init(struct encrypted_key_payload *epayload,
74279a73d18SRoberto Sassu 			  const char *key_desc, const char *format,
74379a73d18SRoberto Sassu 			  const char *master_desc, const char *datalen,
74479a73d18SRoberto Sassu 			  const char *hex_encoded_iv)
7457e70cb49SMimi Zohar {
7467e70cb49SMimi Zohar 	int ret = 0;
7477e70cb49SMimi Zohar 
74879a73d18SRoberto Sassu 	if (format && !strcmp(format, key_format_ecryptfs)) {
74979a73d18SRoberto Sassu 		ret = valid_ecryptfs_desc(key_desc);
75079a73d18SRoberto Sassu 		if (ret < 0)
75179a73d18SRoberto Sassu 			return ret;
75279a73d18SRoberto Sassu 
75379a73d18SRoberto Sassu 		ecryptfs_fill_auth_tok((struct ecryptfs_auth_tok *)epayload->payload_data,
75479a73d18SRoberto Sassu 				       key_desc);
75579a73d18SRoberto Sassu 	}
75679a73d18SRoberto Sassu 
7574e561d38SRoberto Sassu 	__ekey_init(epayload, format, master_desc, datalen);
7581f35065aSMimi Zohar 	if (!hex_encoded_iv) {
7597e70cb49SMimi Zohar 		get_random_bytes(epayload->iv, ivsize);
7607e70cb49SMimi Zohar 
7617e70cb49SMimi Zohar 		get_random_bytes(epayload->decrypted_data,
7627e70cb49SMimi Zohar 				 epayload->decrypted_datalen);
7637e70cb49SMimi Zohar 	} else
7644e561d38SRoberto Sassu 		ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv);
7657e70cb49SMimi Zohar 	return ret;
7667e70cb49SMimi Zohar }
7677e70cb49SMimi Zohar 
7687e70cb49SMimi Zohar /*
7697e70cb49SMimi Zohar  * encrypted_instantiate - instantiate an encrypted key
7707e70cb49SMimi Zohar  *
7717e70cb49SMimi Zohar  * Decrypt an existing encrypted datablob or create a new encrypted key
7727e70cb49SMimi Zohar  * based on a kernel random number.
7737e70cb49SMimi Zohar  *
7747e70cb49SMimi Zohar  * On success, return 0. Otherwise return errno.
7757e70cb49SMimi Zohar  */
776cf7f601cSDavid Howells static int encrypted_instantiate(struct key *key,
777cf7f601cSDavid Howells 				 struct key_preparsed_payload *prep)
7787e70cb49SMimi Zohar {
7797e70cb49SMimi Zohar 	struct encrypted_key_payload *epayload = NULL;
7807e70cb49SMimi Zohar 	char *datablob = NULL;
7814e561d38SRoberto Sassu 	const char *format = NULL;
7827e70cb49SMimi Zohar 	char *master_desc = NULL;
7837e70cb49SMimi Zohar 	char *decrypted_datalen = NULL;
7847e70cb49SMimi Zohar 	char *hex_encoded_iv = NULL;
785cf7f601cSDavid Howells 	size_t datalen = prep->datalen;
7867e70cb49SMimi Zohar 	int ret;
7877e70cb49SMimi Zohar 
788cf7f601cSDavid Howells 	if (datalen <= 0 || datalen > 32767 || !prep->data)
7897e70cb49SMimi Zohar 		return -EINVAL;
7907e70cb49SMimi Zohar 
7917e70cb49SMimi Zohar 	datablob = kmalloc(datalen + 1, GFP_KERNEL);
7927e70cb49SMimi Zohar 	if (!datablob)
7937e70cb49SMimi Zohar 		return -ENOMEM;
7947e70cb49SMimi Zohar 	datablob[datalen] = 0;
795cf7f601cSDavid Howells 	memcpy(datablob, prep->data, datalen);
7964e561d38SRoberto Sassu 	ret = datablob_parse(datablob, &format, &master_desc,
7974e561d38SRoberto Sassu 			     &decrypted_datalen, &hex_encoded_iv);
7987e70cb49SMimi Zohar 	if (ret < 0)
7997e70cb49SMimi Zohar 		goto out;
8007e70cb49SMimi Zohar 
8014e561d38SRoberto Sassu 	epayload = encrypted_key_alloc(key, format, master_desc,
8024e561d38SRoberto Sassu 				       decrypted_datalen);
8037e70cb49SMimi Zohar 	if (IS_ERR(epayload)) {
8047e70cb49SMimi Zohar 		ret = PTR_ERR(epayload);
8057e70cb49SMimi Zohar 		goto out;
8067e70cb49SMimi Zohar 	}
80779a73d18SRoberto Sassu 	ret = encrypted_init(epayload, key->description, format, master_desc,
80879a73d18SRoberto Sassu 			     decrypted_datalen, hex_encoded_iv);
8097e70cb49SMimi Zohar 	if (ret < 0) {
8107e70cb49SMimi Zohar 		kfree(epayload);
8117e70cb49SMimi Zohar 		goto out;
8127e70cb49SMimi Zohar 	}
8137e70cb49SMimi Zohar 
814*b64cc5fbSMimi Zohar 	rcu_assign_keypointer(key, epayload);
8157e70cb49SMimi Zohar out:
8167e70cb49SMimi Zohar 	kfree(datablob);
8177e70cb49SMimi Zohar 	return ret;
8187e70cb49SMimi Zohar }
8197e70cb49SMimi Zohar 
8207e70cb49SMimi Zohar static void encrypted_rcu_free(struct rcu_head *rcu)
8217e70cb49SMimi Zohar {
8227e70cb49SMimi Zohar 	struct encrypted_key_payload *epayload;
8237e70cb49SMimi Zohar 
8247e70cb49SMimi Zohar 	epayload = container_of(rcu, struct encrypted_key_payload, rcu);
8257e70cb49SMimi Zohar 	memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
8267e70cb49SMimi Zohar 	kfree(epayload);
8277e70cb49SMimi Zohar }
8287e70cb49SMimi Zohar 
8297e70cb49SMimi Zohar /*
8307e70cb49SMimi Zohar  * encrypted_update - update the master key description
8317e70cb49SMimi Zohar  *
8327e70cb49SMimi Zohar  * Change the master key description for an existing encrypted key.
8337e70cb49SMimi Zohar  * The next read will return an encrypted datablob using the new
8347e70cb49SMimi Zohar  * master key description.
8357e70cb49SMimi Zohar  *
8367e70cb49SMimi Zohar  * On success, return 0. Otherwise return errno.
8377e70cb49SMimi Zohar  */
838cf7f601cSDavid Howells static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
8397e70cb49SMimi Zohar {
8407e70cb49SMimi Zohar 	struct encrypted_key_payload *epayload = key->payload.data;
8417e70cb49SMimi Zohar 	struct encrypted_key_payload *new_epayload;
8427e70cb49SMimi Zohar 	char *buf;
8437e70cb49SMimi Zohar 	char *new_master_desc = NULL;
8444e561d38SRoberto Sassu 	const char *format = NULL;
845cf7f601cSDavid Howells 	size_t datalen = prep->datalen;
8467e70cb49SMimi Zohar 	int ret = 0;
8477e70cb49SMimi Zohar 
848cf7f601cSDavid Howells 	if (datalen <= 0 || datalen > 32767 || !prep->data)
8497e70cb49SMimi Zohar 		return -EINVAL;
8507e70cb49SMimi Zohar 
8517e70cb49SMimi Zohar 	buf = kmalloc(datalen + 1, GFP_KERNEL);
8527e70cb49SMimi Zohar 	if (!buf)
8537e70cb49SMimi Zohar 		return -ENOMEM;
8547e70cb49SMimi Zohar 
8557e70cb49SMimi Zohar 	buf[datalen] = 0;
856cf7f601cSDavid Howells 	memcpy(buf, prep->data, datalen);
8574e561d38SRoberto Sassu 	ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL);
8587e70cb49SMimi Zohar 	if (ret < 0)
8597e70cb49SMimi Zohar 		goto out;
8607e70cb49SMimi Zohar 
8617e70cb49SMimi Zohar 	ret = valid_master_desc(new_master_desc, epayload->master_desc);
8627e70cb49SMimi Zohar 	if (ret < 0)
8637e70cb49SMimi Zohar 		goto out;
8647e70cb49SMimi Zohar 
8654e561d38SRoberto Sassu 	new_epayload = encrypted_key_alloc(key, epayload->format,
8664e561d38SRoberto Sassu 					   new_master_desc, epayload->datalen);
8677e70cb49SMimi Zohar 	if (IS_ERR(new_epayload)) {
8687e70cb49SMimi Zohar 		ret = PTR_ERR(new_epayload);
8697e70cb49SMimi Zohar 		goto out;
8707e70cb49SMimi Zohar 	}
8717e70cb49SMimi Zohar 
8724e561d38SRoberto Sassu 	__ekey_init(new_epayload, epayload->format, new_master_desc,
8734e561d38SRoberto Sassu 		    epayload->datalen);
8747e70cb49SMimi Zohar 
8757e70cb49SMimi Zohar 	memcpy(new_epayload->iv, epayload->iv, ivsize);
8764e561d38SRoberto Sassu 	memcpy(new_epayload->payload_data, epayload->payload_data,
8774e561d38SRoberto Sassu 	       epayload->payload_datalen);
8787e70cb49SMimi Zohar 
879ee0b31a2SMimi Zohar 	rcu_assign_keypointer(key, new_epayload);
8807e70cb49SMimi Zohar 	call_rcu(&epayload->rcu, encrypted_rcu_free);
8817e70cb49SMimi Zohar out:
8827e70cb49SMimi Zohar 	kfree(buf);
8837e70cb49SMimi Zohar 	return ret;
8847e70cb49SMimi Zohar }
8857e70cb49SMimi Zohar 
8867e70cb49SMimi Zohar /*
8877e70cb49SMimi Zohar  * encrypted_read - format and copy the encrypted data to userspace
8887e70cb49SMimi Zohar  *
8897e70cb49SMimi Zohar  * The resulting datablob format is:
8907e70cb49SMimi Zohar  * <master-key name> <decrypted data length> <encrypted iv> <encrypted data>
8917e70cb49SMimi Zohar  *
8927e70cb49SMimi Zohar  * On success, return to userspace the encrypted key datablob size.
8937e70cb49SMimi Zohar  */
8947e70cb49SMimi Zohar static long encrypted_read(const struct key *key, char __user *buffer,
8957e70cb49SMimi Zohar 			   size_t buflen)
8967e70cb49SMimi Zohar {
8977e70cb49SMimi Zohar 	struct encrypted_key_payload *epayload;
8987e70cb49SMimi Zohar 	struct key *mkey;
8997e70cb49SMimi Zohar 	u8 *master_key;
9003b1826ceSMimi Zohar 	size_t master_keylen;
9017e70cb49SMimi Zohar 	char derived_key[HASH_SIZE];
9027e70cb49SMimi Zohar 	char *ascii_buf;
9037e70cb49SMimi Zohar 	size_t asciiblob_len;
9047e70cb49SMimi Zohar 	int ret;
9057e70cb49SMimi Zohar 
906633e804eSDavid Howells 	epayload = rcu_dereference_key(key);
9077e70cb49SMimi Zohar 
9087e70cb49SMimi Zohar 	/* returns the hex encoded iv, encrypted-data, and hmac as ascii */
9097e70cb49SMimi Zohar 	asciiblob_len = epayload->datablob_len + ivsize + 1
9107e70cb49SMimi Zohar 	    + roundup(epayload->decrypted_datalen, blksize)
9117e70cb49SMimi Zohar 	    + (HASH_SIZE * 2);
9127e70cb49SMimi Zohar 
9137e70cb49SMimi Zohar 	if (!buffer || buflen < asciiblob_len)
9147e70cb49SMimi Zohar 		return asciiblob_len;
9157e70cb49SMimi Zohar 
9167e70cb49SMimi Zohar 	mkey = request_master_key(epayload, &master_key, &master_keylen);
9177e70cb49SMimi Zohar 	if (IS_ERR(mkey))
9187e70cb49SMimi Zohar 		return PTR_ERR(mkey);
9197e70cb49SMimi Zohar 
9207e70cb49SMimi Zohar 	ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen);
9217e70cb49SMimi Zohar 	if (ret < 0)
9227e70cb49SMimi Zohar 		goto out;
9237e70cb49SMimi Zohar 
9247e70cb49SMimi Zohar 	ret = derived_key_encrypt(epayload, derived_key, sizeof derived_key);
9257e70cb49SMimi Zohar 	if (ret < 0)
9267e70cb49SMimi Zohar 		goto out;
9277e70cb49SMimi Zohar 
9287e70cb49SMimi Zohar 	ret = datablob_hmac_append(epayload, master_key, master_keylen);
9297e70cb49SMimi Zohar 	if (ret < 0)
9307e70cb49SMimi Zohar 		goto out;
9317e70cb49SMimi Zohar 
9327e70cb49SMimi Zohar 	ascii_buf = datablob_format(epayload, asciiblob_len);
9337e70cb49SMimi Zohar 	if (!ascii_buf) {
9347e70cb49SMimi Zohar 		ret = -ENOMEM;
9357e70cb49SMimi Zohar 		goto out;
9367e70cb49SMimi Zohar 	}
9377e70cb49SMimi Zohar 
9387e70cb49SMimi Zohar 	up_read(&mkey->sem);
9397e70cb49SMimi Zohar 	key_put(mkey);
9407e70cb49SMimi Zohar 
9417e70cb49SMimi Zohar 	if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0)
9427e70cb49SMimi Zohar 		ret = -EFAULT;
9437e70cb49SMimi Zohar 	kfree(ascii_buf);
9447e70cb49SMimi Zohar 
9457e70cb49SMimi Zohar 	return asciiblob_len;
9467e70cb49SMimi Zohar out:
9477e70cb49SMimi Zohar 	up_read(&mkey->sem);
9487e70cb49SMimi Zohar 	key_put(mkey);
9497e70cb49SMimi Zohar 	return ret;
9507e70cb49SMimi Zohar }
9517e70cb49SMimi Zohar 
9527e70cb49SMimi Zohar /*
9537e70cb49SMimi Zohar  * encrypted_destroy - before freeing the key, clear the decrypted data
9547e70cb49SMimi Zohar  *
9557e70cb49SMimi Zohar  * Before freeing the key, clear the memory containing the decrypted
9567e70cb49SMimi Zohar  * key data.
9577e70cb49SMimi Zohar  */
9587e70cb49SMimi Zohar static void encrypted_destroy(struct key *key)
9597e70cb49SMimi Zohar {
9607e70cb49SMimi Zohar 	struct encrypted_key_payload *epayload = key->payload.data;
9617e70cb49SMimi Zohar 
9627e70cb49SMimi Zohar 	if (!epayload)
9637e70cb49SMimi Zohar 		return;
9647e70cb49SMimi Zohar 
9657e70cb49SMimi Zohar 	memset(epayload->decrypted_data, 0, epayload->decrypted_datalen);
9667e70cb49SMimi Zohar 	kfree(key->payload.data);
9677e70cb49SMimi Zohar }
9687e70cb49SMimi Zohar 
9697e70cb49SMimi Zohar struct key_type key_type_encrypted = {
9707e70cb49SMimi Zohar 	.name = "encrypted",
9717e70cb49SMimi Zohar 	.instantiate = encrypted_instantiate,
9727e70cb49SMimi Zohar 	.update = encrypted_update,
9737e70cb49SMimi Zohar 	.match = user_match,
9747e70cb49SMimi Zohar 	.destroy = encrypted_destroy,
9757e70cb49SMimi Zohar 	.describe = user_describe,
9767e70cb49SMimi Zohar 	.read = encrypted_read,
9777e70cb49SMimi Zohar };
9787e70cb49SMimi Zohar EXPORT_SYMBOL_GPL(key_type_encrypted);
9797e70cb49SMimi Zohar 
9807e70cb49SMimi Zohar static void encrypted_shash_release(void)
9817e70cb49SMimi Zohar {
9827e70cb49SMimi Zohar 	if (hashalg)
9837e70cb49SMimi Zohar 		crypto_free_shash(hashalg);
9847e70cb49SMimi Zohar 	if (hmacalg)
9857e70cb49SMimi Zohar 		crypto_free_shash(hmacalg);
9867e70cb49SMimi Zohar }
9877e70cb49SMimi Zohar 
9887e70cb49SMimi Zohar static int __init encrypted_shash_alloc(void)
9897e70cb49SMimi Zohar {
9907e70cb49SMimi Zohar 	int ret;
9917e70cb49SMimi Zohar 
9927e70cb49SMimi Zohar 	hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
9937e70cb49SMimi Zohar 	if (IS_ERR(hmacalg)) {
9947e70cb49SMimi Zohar 		pr_info("encrypted_key: could not allocate crypto %s\n",
9957e70cb49SMimi Zohar 			hmac_alg);
9967e70cb49SMimi Zohar 		return PTR_ERR(hmacalg);
9977e70cb49SMimi Zohar 	}
9987e70cb49SMimi Zohar 
9997e70cb49SMimi Zohar 	hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
10007e70cb49SMimi Zohar 	if (IS_ERR(hashalg)) {
10017e70cb49SMimi Zohar 		pr_info("encrypted_key: could not allocate crypto %s\n",
10027e70cb49SMimi Zohar 			hash_alg);
10037e70cb49SMimi Zohar 		ret = PTR_ERR(hashalg);
10047e70cb49SMimi Zohar 		goto hashalg_fail;
10057e70cb49SMimi Zohar 	}
10067e70cb49SMimi Zohar 
10077e70cb49SMimi Zohar 	return 0;
10087e70cb49SMimi Zohar 
10097e70cb49SMimi Zohar hashalg_fail:
10107e70cb49SMimi Zohar 	crypto_free_shash(hmacalg);
10117e70cb49SMimi Zohar 	return ret;
10127e70cb49SMimi Zohar }
10137e70cb49SMimi Zohar 
10147e70cb49SMimi Zohar static int __init init_encrypted(void)
10157e70cb49SMimi Zohar {
10167e70cb49SMimi Zohar 	int ret;
10177e70cb49SMimi Zohar 
10187e70cb49SMimi Zohar 	ret = encrypted_shash_alloc();
10197e70cb49SMimi Zohar 	if (ret < 0)
10207e70cb49SMimi Zohar 		return ret;
10217e70cb49SMimi Zohar 	ret = register_key_type(&key_type_encrypted);
10227e70cb49SMimi Zohar 	if (ret < 0)
10237e70cb49SMimi Zohar 		goto out;
10247e70cb49SMimi Zohar 	return aes_get_sizes();
10257e70cb49SMimi Zohar out:
10267e70cb49SMimi Zohar 	encrypted_shash_release();
10277e70cb49SMimi Zohar 	return ret;
1028b9703449SMimi Zohar 
10297e70cb49SMimi Zohar }
10307e70cb49SMimi Zohar 
10317e70cb49SMimi Zohar static void __exit cleanup_encrypted(void)
10327e70cb49SMimi Zohar {
10337e70cb49SMimi Zohar 	encrypted_shash_release();
10347e70cb49SMimi Zohar 	unregister_key_type(&key_type_encrypted);
10357e70cb49SMimi Zohar }
10367e70cb49SMimi Zohar 
10377e70cb49SMimi Zohar late_initcall(init_encrypted);
10387e70cb49SMimi Zohar module_exit(cleanup_encrypted);
10397e70cb49SMimi Zohar 
10407e70cb49SMimi Zohar MODULE_LICENSE("GPL");
1041