brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · b1dbb8c Raw
259 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * AMD Cryptographic Coprocessor (CCP) AES GCM crypto API support4 *5 * Copyright (C) 2016,2017 Advanced Micro Devices, Inc.6 *7 * Author: Gary R Hook <gary.hook@amd.com>8 */9 10#include <linux/module.h>11#include <linux/sched.h>12#include <linux/delay.h>13#include <linux/scatterlist.h>14#include <linux/crypto.h>15#include <crypto/internal/aead.h>16#include <crypto/algapi.h>17#include <crypto/aes.h>18#include <crypto/ctr.h>19#include <crypto/gcm.h>20#include <crypto/scatterwalk.h>21 22#include "ccp-crypto.h"23 24static int ccp_aes_gcm_complete(struct crypto_async_request *async_req, int ret)25{26	return ret;27}28 29static int ccp_aes_gcm_setkey(struct crypto_aead *tfm, const u8 *key,30			      unsigned int key_len)31{32	struct ccp_ctx *ctx = crypto_aead_ctx_dma(tfm);33 34	switch (key_len) {35	case AES_KEYSIZE_128:36		ctx->u.aes.type = CCP_AES_TYPE_128;37		break;38	case AES_KEYSIZE_192:39		ctx->u.aes.type = CCP_AES_TYPE_192;40		break;41	case AES_KEYSIZE_256:42		ctx->u.aes.type = CCP_AES_TYPE_256;43		break;44	default:45		return -EINVAL;46	}47 48	ctx->u.aes.mode = CCP_AES_MODE_GCM;49	ctx->u.aes.key_len = key_len;50 51	memcpy(ctx->u.aes.key, key, key_len);52	sg_init_one(&ctx->u.aes.key_sg, ctx->u.aes.key, key_len);53 54	return 0;55}56 57static int ccp_aes_gcm_setauthsize(struct crypto_aead *tfm,58				   unsigned int authsize)59{60	switch (authsize) {61	case 16:62	case 15:63	case 14:64	case 13:65	case 12:66	case 8:67	case 4:68		break;69	default:70		return -EINVAL;71	}72 73	return 0;74}75 76static int ccp_aes_gcm_crypt(struct aead_request *req, bool encrypt)77{78	struct crypto_aead *tfm = crypto_aead_reqtfm(req);79	struct ccp_ctx *ctx = crypto_aead_ctx_dma(tfm);80	struct ccp_aes_req_ctx *rctx = aead_request_ctx_dma(req);81	struct scatterlist *iv_sg = NULL;82	unsigned int iv_len = 0;83	int i;84	int ret = 0;85 86	if (!ctx->u.aes.key_len)87		return -EINVAL;88 89	if (ctx->u.aes.mode != CCP_AES_MODE_GCM)90		return -EINVAL;91 92	if (!req->iv)93		return -EINVAL;94 95	/*96	 * 5 parts:97	 *   plaintext/ciphertext input98	 *   AAD99	 *   key100	 *   IV101	 *   Destination+tag buffer102	 */103 104	/* Prepare the IV: 12 bytes + an integer (counter) */105	memcpy(rctx->iv, req->iv, GCM_AES_IV_SIZE);106	for (i = 0; i < 3; i++)107		rctx->iv[i + GCM_AES_IV_SIZE] = 0;108	rctx->iv[AES_BLOCK_SIZE - 1] = 1;109 110	/* Set up a scatterlist for the IV */111	iv_sg = &rctx->iv_sg;112	iv_len = AES_BLOCK_SIZE;113	sg_init_one(iv_sg, rctx->iv, iv_len);114 115	/* The AAD + plaintext are concatenated in the src buffer */116	memset(&rctx->cmd, 0, sizeof(rctx->cmd));117	INIT_LIST_HEAD(&rctx->cmd.entry);118	rctx->cmd.engine = CCP_ENGINE_AES;119	rctx->cmd.u.aes.authsize = crypto_aead_authsize(tfm);120	rctx->cmd.u.aes.type = ctx->u.aes.type;121	rctx->cmd.u.aes.mode = ctx->u.aes.mode;122	rctx->cmd.u.aes.action = encrypt;123	rctx->cmd.u.aes.key = &ctx->u.aes.key_sg;124	rctx->cmd.u.aes.key_len = ctx->u.aes.key_len;125	rctx->cmd.u.aes.iv = iv_sg;126	rctx->cmd.u.aes.iv_len = iv_len;127	rctx->cmd.u.aes.src = req->src;128	rctx->cmd.u.aes.src_len = req->cryptlen;129	rctx->cmd.u.aes.aad_len = req->assoclen;130 131	/* The cipher text + the tag are in the dst buffer */132	rctx->cmd.u.aes.dst = req->dst;133 134	ret = ccp_crypto_enqueue_request(&req->base, &rctx->cmd);135 136	return ret;137}138 139static int ccp_aes_gcm_encrypt(struct aead_request *req)140{141	return ccp_aes_gcm_crypt(req, CCP_AES_ACTION_ENCRYPT);142}143 144static int ccp_aes_gcm_decrypt(struct aead_request *req)145{146	return ccp_aes_gcm_crypt(req, CCP_AES_ACTION_DECRYPT);147}148 149static int ccp_aes_gcm_cra_init(struct crypto_aead *tfm)150{151	struct ccp_ctx *ctx = crypto_aead_ctx_dma(tfm);152 153	ctx->complete = ccp_aes_gcm_complete;154	ctx->u.aes.key_len = 0;155 156	crypto_aead_set_reqsize_dma(tfm, sizeof(struct ccp_aes_req_ctx));157 158	return 0;159}160 161static void ccp_aes_gcm_cra_exit(struct crypto_tfm *tfm)162{163}164 165static struct aead_alg ccp_aes_gcm_defaults = {166	.setkey = ccp_aes_gcm_setkey,167	.setauthsize = ccp_aes_gcm_setauthsize,168	.encrypt = ccp_aes_gcm_encrypt,169	.decrypt = ccp_aes_gcm_decrypt,170	.init = ccp_aes_gcm_cra_init,171	.ivsize = GCM_AES_IV_SIZE,172	.maxauthsize = AES_BLOCK_SIZE,173	.base = {174		.cra_flags	= CRYPTO_ALG_ASYNC |175				  CRYPTO_ALG_ALLOCATES_MEMORY |176				  CRYPTO_ALG_KERN_DRIVER_ONLY |177				  CRYPTO_ALG_NEED_FALLBACK,178		.cra_blocksize	= AES_BLOCK_SIZE,179		.cra_ctxsize	= sizeof(struct ccp_ctx) + CRYPTO_DMA_PADDING,180		.cra_priority	= CCP_CRA_PRIORITY,181		.cra_exit	= ccp_aes_gcm_cra_exit,182		.cra_module	= THIS_MODULE,183	},184};185 186struct ccp_aes_aead_def {187	enum ccp_aes_mode mode;188	unsigned int version;189	const char *name;190	const char *driver_name;191	unsigned int blocksize;192	unsigned int ivsize;193	struct aead_alg *alg_defaults;194};195 196static struct ccp_aes_aead_def aes_aead_algs[] = {197	{198		.mode		= CCP_AES_MODE_GHASH,199		.version	= CCP_VERSION(5, 0),200		.name		= "gcm(aes)",201		.driver_name	= "gcm-aes-ccp",202		.blocksize	= 1,203		.ivsize		= AES_BLOCK_SIZE,204		.alg_defaults	= &ccp_aes_gcm_defaults,205	},206};207 208static int ccp_register_aes_aead(struct list_head *head,209				 const struct ccp_aes_aead_def *def)210{211	struct ccp_crypto_aead *ccp_aead;212	struct aead_alg *alg;213	int ret;214 215	ccp_aead = kzalloc(sizeof(*ccp_aead), GFP_KERNEL);216	if (!ccp_aead)217		return -ENOMEM;218 219	INIT_LIST_HEAD(&ccp_aead->entry);220 221	ccp_aead->mode = def->mode;222 223	/* Copy the defaults and override as necessary */224	alg = &ccp_aead->alg;225	*alg = *def->alg_defaults;226	snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name);227	snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",228		 def->driver_name);229	alg->base.cra_blocksize = def->blocksize;230 231	ret = crypto_register_aead(alg);232	if (ret) {233		pr_err("%s aead algorithm registration error (%d)\n",234		       alg->base.cra_name, ret);235		kfree(ccp_aead);236		return ret;237	}238 239	list_add(&ccp_aead->entry, head);240 241	return 0;242}243 244int ccp_register_aes_aeads(struct list_head *head)245{246	int i, ret;247	unsigned int ccpversion = ccp_version();248 249	for (i = 0; i < ARRAY_SIZE(aes_aead_algs); i++) {250		if (aes_aead_algs[i].version > ccpversion)251			continue;252		ret = ccp_register_aes_aead(head, &aes_aead_algs[i]);253		if (ret)254			return ret;255	}256 257	return 0;258}259