cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

omap-aes-gcm.c (9607B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Cryptographic API.
      4 *
      5 * Support for OMAP AES GCM HW acceleration.
      6 *
      7 * Copyright (c) 2016 Texas Instruments Incorporated
      8 */
      9
     10#include <linux/errno.h>
     11#include <linux/scatterlist.h>
     12#include <linux/dma-mapping.h>
     13#include <linux/dmaengine.h>
     14#include <linux/omap-dma.h>
     15#include <linux/interrupt.h>
     16#include <linux/pm_runtime.h>
     17#include <crypto/aes.h>
     18#include <crypto/gcm.h>
     19#include <crypto/scatterwalk.h>
     20#include <crypto/skcipher.h>
     21#include <crypto/internal/aead.h>
     22
     23#include "omap-crypto.h"
     24#include "omap-aes.h"
     25
     26static int omap_aes_gcm_handle_queue(struct omap_aes_dev *dd,
     27				     struct aead_request *req);
     28
     29static void omap_aes_gcm_finish_req(struct omap_aes_dev *dd, int ret)
     30{
     31	struct aead_request *req = dd->aead_req;
     32
     33	dd->in_sg = NULL;
     34	dd->out_sg = NULL;
     35
     36	crypto_finalize_aead_request(dd->engine, req, ret);
     37
     38	pm_runtime_mark_last_busy(dd->dev);
     39	pm_runtime_put_autosuspend(dd->dev);
     40}
     41
     42static void omap_aes_gcm_done_task(struct omap_aes_dev *dd)
     43{
     44	u8 *tag;
     45	int alen, clen, i, ret = 0, nsg;
     46	struct omap_aes_reqctx *rctx;
     47
     48	alen = ALIGN(dd->assoc_len, AES_BLOCK_SIZE);
     49	clen = ALIGN(dd->total, AES_BLOCK_SIZE);
     50	rctx = aead_request_ctx(dd->aead_req);
     51
     52	nsg = !!(dd->assoc_len && dd->total);
     53
     54	dma_sync_sg_for_device(dd->dev, dd->out_sg, dd->out_sg_len,
     55			       DMA_FROM_DEVICE);
     56	dma_unmap_sg(dd->dev, dd->in_sg, dd->in_sg_len, DMA_TO_DEVICE);
     57	dma_unmap_sg(dd->dev, dd->out_sg, dd->out_sg_len, DMA_FROM_DEVICE);
     58	omap_aes_crypt_dma_stop(dd);
     59
     60	omap_crypto_cleanup(dd->out_sg, dd->orig_out,
     61			    dd->aead_req->assoclen, dd->total,
     62			    FLAGS_OUT_DATA_ST_SHIFT, dd->flags);
     63
     64	if (dd->flags & FLAGS_ENCRYPT)
     65		scatterwalk_map_and_copy(rctx->auth_tag,
     66					 dd->aead_req->dst,
     67					 dd->total + dd->aead_req->assoclen,
     68					 dd->authsize, 1);
     69
     70	omap_crypto_cleanup(&dd->in_sgl[0], NULL, 0, alen,
     71			    FLAGS_ASSOC_DATA_ST_SHIFT, dd->flags);
     72
     73	omap_crypto_cleanup(&dd->in_sgl[nsg], NULL, 0, clen,
     74			    FLAGS_IN_DATA_ST_SHIFT, dd->flags);
     75
     76	if (!(dd->flags & FLAGS_ENCRYPT)) {
     77		tag = (u8 *)rctx->auth_tag;
     78		for (i = 0; i < dd->authsize; i++) {
     79			if (tag[i]) {
     80				ret = -EBADMSG;
     81			}
     82		}
     83	}
     84
     85	omap_aes_gcm_finish_req(dd, ret);
     86}
     87
     88static int omap_aes_gcm_copy_buffers(struct omap_aes_dev *dd,
     89				     struct aead_request *req)
     90{
     91	int alen, clen, cryptlen, assoclen, ret;
     92	struct crypto_aead *aead = crypto_aead_reqtfm(req);
     93	unsigned int authlen = crypto_aead_authsize(aead);
     94	struct scatterlist *tmp, sg_arr[2];
     95	int nsg;
     96	u16 flags;
     97
     98	assoclen = req->assoclen;
     99	cryptlen = req->cryptlen;
    100
    101	if (dd->flags & FLAGS_RFC4106_GCM)
    102		assoclen -= 8;
    103
    104	if (!(dd->flags & FLAGS_ENCRYPT))
    105		cryptlen -= authlen;
    106
    107	alen = ALIGN(assoclen, AES_BLOCK_SIZE);
    108	clen = ALIGN(cryptlen, AES_BLOCK_SIZE);
    109
    110	nsg = !!(assoclen && cryptlen);
    111
    112	omap_aes_clear_copy_flags(dd);
    113
    114	sg_init_table(dd->in_sgl, nsg + 1);
    115	if (assoclen) {
    116		tmp = req->src;
    117		ret = omap_crypto_align_sg(&tmp, assoclen,
    118					   AES_BLOCK_SIZE, dd->in_sgl,
    119					   OMAP_CRYPTO_COPY_DATA |
    120					   OMAP_CRYPTO_ZERO_BUF |
    121					   OMAP_CRYPTO_FORCE_SINGLE_ENTRY,
    122					   FLAGS_ASSOC_DATA_ST_SHIFT,
    123					   &dd->flags);
    124		if (ret)
    125			return ret;
    126	}
    127
    128	if (cryptlen) {
    129		tmp = scatterwalk_ffwd(sg_arr, req->src, req->assoclen);
    130
    131		if (nsg)
    132			sg_unmark_end(dd->in_sgl);
    133
    134		ret = omap_crypto_align_sg(&tmp, cryptlen,
    135					   AES_BLOCK_SIZE, &dd->in_sgl[nsg],
    136					   OMAP_CRYPTO_COPY_DATA |
    137					   OMAP_CRYPTO_ZERO_BUF |
    138					   OMAP_CRYPTO_FORCE_SINGLE_ENTRY,
    139					   FLAGS_IN_DATA_ST_SHIFT,
    140					   &dd->flags);
    141		if (ret)
    142			return ret;
    143	}
    144
    145	dd->in_sg = dd->in_sgl;
    146	dd->total = cryptlen;
    147	dd->assoc_len = assoclen;
    148	dd->authsize = authlen;
    149
    150	dd->out_sg = req->dst;
    151	dd->orig_out = req->dst;
    152
    153	dd->out_sg = scatterwalk_ffwd(sg_arr, req->dst, req->assoclen);
    154
    155	flags = 0;
    156	if (req->src == req->dst || dd->out_sg == sg_arr)
    157		flags |= OMAP_CRYPTO_FORCE_COPY;
    158
    159	if (cryptlen) {
    160		ret = omap_crypto_align_sg(&dd->out_sg, cryptlen,
    161					   AES_BLOCK_SIZE, &dd->out_sgl,
    162					   flags,
    163					   FLAGS_OUT_DATA_ST_SHIFT, &dd->flags);
    164		if (ret)
    165			return ret;
    166	}
    167
    168	dd->in_sg_len = sg_nents_for_len(dd->in_sg, alen + clen);
    169	dd->out_sg_len = sg_nents_for_len(dd->out_sg, clen);
    170
    171	return 0;
    172}
    173
    174static int do_encrypt_iv(struct aead_request *req, u32 *tag, u32 *iv)
    175{
    176	struct omap_aes_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
    177
    178	aes_encrypt(&ctx->actx, (u8 *)tag, (u8 *)iv);
    179	return 0;
    180}
    181
    182void omap_aes_gcm_dma_out_callback(void *data)
    183{
    184	struct omap_aes_dev *dd = data;
    185	struct omap_aes_reqctx *rctx;
    186	int i, val;
    187	u32 *auth_tag, tag[4];
    188
    189	if (!(dd->flags & FLAGS_ENCRYPT))
    190		scatterwalk_map_and_copy(tag, dd->aead_req->src,
    191					 dd->total + dd->aead_req->assoclen,
    192					 dd->authsize, 0);
    193
    194	rctx = aead_request_ctx(dd->aead_req);
    195	auth_tag = (u32 *)rctx->auth_tag;
    196	for (i = 0; i < 4; i++) {
    197		val = omap_aes_read(dd, AES_REG_TAG_N(dd, i));
    198		auth_tag[i] = val ^ auth_tag[i];
    199		if (!(dd->flags & FLAGS_ENCRYPT))
    200			auth_tag[i] = auth_tag[i] ^ tag[i];
    201	}
    202
    203	omap_aes_gcm_done_task(dd);
    204}
    205
    206static int omap_aes_gcm_handle_queue(struct omap_aes_dev *dd,
    207				     struct aead_request *req)
    208{
    209	if (req)
    210		return crypto_transfer_aead_request_to_engine(dd->engine, req);
    211
    212	return 0;
    213}
    214
    215static int omap_aes_gcm_prepare_req(struct crypto_engine *engine, void *areq)
    216{
    217	struct aead_request *req = container_of(areq, struct aead_request,
    218						base);
    219	struct omap_aes_reqctx *rctx = aead_request_ctx(req);
    220	struct omap_aes_dev *dd = rctx->dd;
    221	struct omap_aes_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
    222	int err;
    223
    224	dd->aead_req = req;
    225
    226	rctx->mode &= FLAGS_MODE_MASK;
    227	dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode;
    228
    229	err = omap_aes_gcm_copy_buffers(dd, req);
    230	if (err)
    231		return err;
    232
    233	dd->ctx = &ctx->octx;
    234
    235	return omap_aes_write_ctrl(dd);
    236}
    237
    238static int omap_aes_gcm_crypt(struct aead_request *req, unsigned long mode)
    239{
    240	struct omap_aes_reqctx *rctx = aead_request_ctx(req);
    241	struct crypto_aead *aead = crypto_aead_reqtfm(req);
    242	unsigned int authlen = crypto_aead_authsize(aead);
    243	struct omap_aes_dev *dd;
    244	__be32 counter = cpu_to_be32(1);
    245	int err, assoclen;
    246
    247	memset(rctx->auth_tag, 0, sizeof(rctx->auth_tag));
    248	memcpy(rctx->iv + GCM_AES_IV_SIZE, &counter, 4);
    249
    250	err = do_encrypt_iv(req, (u32 *)rctx->auth_tag, (u32 *)rctx->iv);
    251	if (err)
    252		return err;
    253
    254	if (mode & FLAGS_RFC4106_GCM)
    255		assoclen = req->assoclen - 8;
    256	else
    257		assoclen = req->assoclen;
    258	if (assoclen + req->cryptlen == 0) {
    259		scatterwalk_map_and_copy(rctx->auth_tag, req->dst, 0, authlen,
    260					 1);
    261		return 0;
    262	}
    263
    264	dd = omap_aes_find_dev(rctx);
    265	if (!dd)
    266		return -ENODEV;
    267	rctx->mode = mode;
    268
    269	return omap_aes_gcm_handle_queue(dd, req);
    270}
    271
    272int omap_aes_gcm_encrypt(struct aead_request *req)
    273{
    274	struct omap_aes_reqctx *rctx = aead_request_ctx(req);
    275
    276	memcpy(rctx->iv, req->iv, GCM_AES_IV_SIZE);
    277	return omap_aes_gcm_crypt(req, FLAGS_ENCRYPT | FLAGS_GCM);
    278}
    279
    280int omap_aes_gcm_decrypt(struct aead_request *req)
    281{
    282	struct omap_aes_reqctx *rctx = aead_request_ctx(req);
    283
    284	memcpy(rctx->iv, req->iv, GCM_AES_IV_SIZE);
    285	return omap_aes_gcm_crypt(req, FLAGS_GCM);
    286}
    287
    288int omap_aes_4106gcm_encrypt(struct aead_request *req)
    289{
    290	struct omap_aes_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
    291	struct omap_aes_reqctx *rctx = aead_request_ctx(req);
    292
    293	memcpy(rctx->iv, ctx->octx.nonce, 4);
    294	memcpy(rctx->iv + 4, req->iv, 8);
    295	return crypto_ipsec_check_assoclen(req->assoclen) ?:
    296	       omap_aes_gcm_crypt(req, FLAGS_ENCRYPT | FLAGS_GCM |
    297				  FLAGS_RFC4106_GCM);
    298}
    299
    300int omap_aes_4106gcm_decrypt(struct aead_request *req)
    301{
    302	struct omap_aes_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
    303	struct omap_aes_reqctx *rctx = aead_request_ctx(req);
    304
    305	memcpy(rctx->iv, ctx->octx.nonce, 4);
    306	memcpy(rctx->iv + 4, req->iv, 8);
    307	return crypto_ipsec_check_assoclen(req->assoclen) ?:
    308	       omap_aes_gcm_crypt(req, FLAGS_GCM | FLAGS_RFC4106_GCM);
    309}
    310
    311int omap_aes_gcm_setkey(struct crypto_aead *tfm, const u8 *key,
    312			unsigned int keylen)
    313{
    314	struct omap_aes_gcm_ctx *ctx = crypto_aead_ctx(tfm);
    315	int ret;
    316
    317	ret = aes_expandkey(&ctx->actx, key, keylen);
    318	if (ret)
    319		return ret;
    320
    321	memcpy(ctx->octx.key, key, keylen);
    322	ctx->octx.keylen = keylen;
    323
    324	return 0;
    325}
    326
    327int omap_aes_4106gcm_setkey(struct crypto_aead *tfm, const u8 *key,
    328			    unsigned int keylen)
    329{
    330	struct omap_aes_gcm_ctx *ctx = crypto_aead_ctx(tfm);
    331	int ret;
    332
    333	if (keylen < 4)
    334		return -EINVAL;
    335	keylen -= 4;
    336
    337	ret = aes_expandkey(&ctx->actx, key, keylen);
    338	if (ret)
    339		return ret;
    340
    341	memcpy(ctx->octx.key, key, keylen);
    342	memcpy(ctx->octx.nonce, key + keylen, 4);
    343	ctx->octx.keylen = keylen;
    344
    345	return 0;
    346}
    347
    348int omap_aes_gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize)
    349{
    350	return crypto_gcm_check_authsize(authsize);
    351}
    352
    353int omap_aes_4106gcm_setauthsize(struct crypto_aead *parent,
    354				 unsigned int authsize)
    355{
    356	return crypto_rfc4106_check_authsize(authsize);
    357}
    358
    359static int omap_aes_gcm_crypt_req(struct crypto_engine *engine, void *areq)
    360{
    361	struct aead_request *req = container_of(areq, struct aead_request,
    362						base);
    363	struct omap_aes_reqctx *rctx = aead_request_ctx(req);
    364	struct omap_aes_dev *dd = rctx->dd;
    365	int ret = 0;
    366
    367	if (!dd)
    368		return -ENODEV;
    369
    370	if (dd->in_sg_len)
    371		ret = omap_aes_crypt_dma_start(dd);
    372	else
    373		omap_aes_gcm_dma_out_callback(dd);
    374
    375	return ret;
    376}
    377
    378int omap_aes_gcm_cra_init(struct crypto_aead *tfm)
    379{
    380	struct omap_aes_ctx *ctx = crypto_aead_ctx(tfm);
    381
    382	ctx->enginectx.op.prepare_request = omap_aes_gcm_prepare_req;
    383	ctx->enginectx.op.unprepare_request = NULL;
    384	ctx->enginectx.op.do_one_request = omap_aes_gcm_crypt_req;
    385
    386	crypto_aead_set_reqsize(tfm, sizeof(struct omap_aes_reqctx));
    387
    388	return 0;
    389}