int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw, u64 lblk_num, struct page *src_page, struct page *dest_page, unsigned int len, unsigned int offs, gfp_t gfp_flags) { union fscrypt_iv iv; struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); struct scatterlist dst, src; struct fscrypt_info *ci = inode->i_crypt_info; struct crypto_skcipher *tfm = ci->ci_ctfm; int res = 0; BUG_ON(len == 0); fscrypt_generate_iv(&iv, lblk_num, ci); req = skcipher_request_alloc(tfm, gfp_flags); if (!req) return -ENOMEM; skcipher_request_set_callback( req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &wait); sg_init_table(&dst, 1); sg_set_page(&dst, dest_page, len, offs); sg_init_table(&src, 1); sg_set_page(&src, src_page, len, offs); skcipher_request_set_crypt(req, &src, &dst, len, &iv); if (rw == FS_DECRYPT) res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait); else res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); skcipher_request_free(req); if (res) { fscrypt_err(inode->i_sb, "%scryption failed for inode %lu, block %llu: %d", (rw == FS_DECRYPT ? "de" : "en"), inode->i_ino, lblk_num, res); return res; } return 0; }
static inline int ahash_wait(int err, struct crypto_wait *wait) { err = crypto_wait_req(err, wait); if (err) pr_crit_ratelimited("ahash calculation failed: err: %d\n", err); return err; }
/* * Encryption operation is performed with the public key. Hence it is done * in software */ static int tpm_key_encrypt(struct tpm_key *tk, struct kernel_pkey_params *params, const void *in, void *out) { char alg_name[CRYPTO_MAX_ALG_NAME]; struct crypto_akcipher *tfm; struct akcipher_request *req; struct crypto_wait cwait; struct scatterlist in_sg, out_sg; uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; uint32_t der_pub_key_len; int ret; pr_devel("==>%s()\n", __func__); ret = determine_akcipher(params->encoding, params->hash_algo, alg_name); if (ret < 0) return ret; tfm = crypto_alloc_akcipher(alg_name, 0, 0); if (IS_ERR(tfm)) return PTR_ERR(tfm); der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len, der_pub_key); ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len); if (ret < 0) goto error_free_tfm; req = akcipher_request_alloc(tfm, GFP_KERNEL); if (!req) goto error_free_tfm; sg_init_one(&in_sg, in, params->in_len); sg_init_one(&out_sg, out, params->out_len); akcipher_request_set_crypt(req, &in_sg, &out_sg, params->in_len, params->out_len); crypto_init_wait(&cwait); akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &cwait); ret = crypto_akcipher_encrypt(req); ret = crypto_wait_req(ret, &cwait); if (ret == 0) ret = req->dst_len; akcipher_request_free(req); error_free_tfm: crypto_free_akcipher(tfm); pr_devel("<==%s() = %d\n", __func__, ret); return ret; }
/** * fname_encrypt() - encrypt a filename * * The output buffer must be at least as large as the input buffer. * Any extra space is filled with NUL padding before encryption. * * Return: 0 on success, -errno on failure */ int fname_encrypt(struct inode *inode, const struct qstr *iname, u8 *out, unsigned int olen) { struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); struct fscrypt_info *ci = inode->i_crypt_info; struct crypto_skcipher *tfm = ci->ci_ctfm; union fscrypt_iv iv; struct scatterlist sg; int res; /* * Copy the filename to the output buffer for encrypting in-place and * pad it with the needed number of NUL bytes. */ if (WARN_ON(olen < iname->len)) return -ENOBUFS; memcpy(out, iname->name, iname->len); memset(out + iname->len, 0, olen - iname->len); /* Initialize the IV */ fscrypt_generate_iv(&iv, 0, ci); /* Set up the encryption request */ req = skcipher_request_alloc(tfm, GFP_NOFS); if (!req) return -ENOMEM; skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &wait); sg_init_one(&sg, out, olen); skcipher_request_set_crypt(req, &sg, &sg, olen, &iv); /* Do the encryption */ res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); skcipher_request_free(req); if (res < 0) { fscrypt_err(inode->i_sb, "Filename encryption failed for inode %lu: %d", inode->i_ino, res); return res; } return 0; }
/** * fname_decrypt() - decrypt a filename * * The caller must have allocated sufficient memory for the @oname string. * * Return: 0 on success, -errno on failure */ static int fname_decrypt(struct inode *inode, const struct fscrypt_str *iname, struct fscrypt_str *oname) { struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); struct scatterlist src_sg, dst_sg; struct fscrypt_info *ci = inode->i_crypt_info; struct crypto_skcipher *tfm = ci->ci_ctfm; union fscrypt_iv iv; int res; /* Allocate request */ req = skcipher_request_alloc(tfm, GFP_NOFS); if (!req) return -ENOMEM; skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &wait); /* Initialize IV */ fscrypt_generate_iv(&iv, 0, ci); /* Create decryption request */ sg_init_one(&src_sg, iname->name, iname->len); sg_init_one(&dst_sg, oname->name, oname->len); skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, &iv); res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait); skcipher_request_free(req); if (res < 0) { fscrypt_err(inode->i_sb, "Filename decryption failed for inode %lu: %d", inode->i_ino, res); return res; } oname->len = strnlen(oname->name, iname->len); return 0; }
/* * Verify a signature using a public key. */ static int tpm_key_verify_signature(const struct key *key, const struct public_key_signature *sig) { const struct tpm_key *tk = key->payload.data[asym_crypto]; struct crypto_wait cwait; struct crypto_akcipher *tfm; struct akcipher_request *req; struct scatterlist sig_sg, digest_sg; char alg_name[CRYPTO_MAX_ALG_NAME]; uint8_t der_pub_key[PUB_KEY_BUF_SIZE]; uint32_t der_pub_key_len; void *output; unsigned int outlen; int ret; pr_devel("==>%s()\n", __func__); BUG_ON(!tk); BUG_ON(!sig); BUG_ON(!sig->s); if (!sig->digest) return -ENOPKG; ret = determine_akcipher(sig->encoding, sig->hash_algo, alg_name); if (ret < 0) return ret; tfm = crypto_alloc_akcipher(alg_name, 0, 0); if (IS_ERR(tfm)) return PTR_ERR(tfm); der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len, der_pub_key); ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len); if (ret < 0) goto error_free_tfm; ret = -ENOMEM; req = akcipher_request_alloc(tfm, GFP_KERNEL); if (!req) goto error_free_tfm; ret = -ENOMEM; outlen = crypto_akcipher_maxsize(tfm); output = kmalloc(outlen, GFP_KERNEL); if (!output) goto error_free_req; sg_init_one(&sig_sg, sig->s, sig->s_size); sg_init_one(&digest_sg, output, outlen); akcipher_request_set_crypt(req, &sig_sg, &digest_sg, sig->s_size, outlen); crypto_init_wait(&cwait); akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &cwait); /* Perform the verification calculation. This doesn't actually do the * verification, but rather calculates the hash expected by the * signature and returns that to us. */ ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); if (ret) goto out_free_output; /* Do the actual verification step. */ if (req->dst_len != sig->digest_size || memcmp(sig->digest, output, sig->digest_size) != 0) ret = -EKEYREJECTED; out_free_output: kfree(output); error_free_req: akcipher_request_free(req); error_free_tfm: crypto_free_akcipher(tfm); pr_devel("<==%s() = %d\n", __func__, ret); if (WARN_ON_ONCE(ret > 0)) ret = -EINVAL; return ret; }