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

nx-aes-ccm.c (14496B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * AES CCM routines supporting the Power 7+ Nest Accelerators driver
      4 *
      5 * Copyright (C) 2012 International Business Machines Inc.
      6 *
      7 * Author: Kent Yoder <yoder1@us.ibm.com>
      8 */
      9
     10#include <crypto/internal/aead.h>
     11#include <crypto/aes.h>
     12#include <crypto/algapi.h>
     13#include <crypto/scatterwalk.h>
     14#include <linux/module.h>
     15#include <linux/types.h>
     16#include <linux/crypto.h>
     17#include <asm/vio.h>
     18
     19#include "nx_csbcpb.h"
     20#include "nx.h"
     21
     22
     23static int ccm_aes_nx_set_key(struct crypto_aead *tfm,
     24			      const u8           *in_key,
     25			      unsigned int        key_len)
     26{
     27	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
     28	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
     29	struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
     30
     31	nx_ctx_init(nx_ctx, HCOP_FC_AES);
     32
     33	switch (key_len) {
     34	case AES_KEYSIZE_128:
     35		NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
     36		NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
     37		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
     38		break;
     39	default:
     40		return -EINVAL;
     41	}
     42
     43	csbcpb->cpb.hdr.mode = NX_MODE_AES_CCM;
     44	memcpy(csbcpb->cpb.aes_ccm.key, in_key, key_len);
     45
     46	csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_CCA;
     47	memcpy(csbcpb_aead->cpb.aes_cca.key, in_key, key_len);
     48
     49	return 0;
     50
     51}
     52
     53static int ccm4309_aes_nx_set_key(struct crypto_aead *tfm,
     54				  const u8           *in_key,
     55				  unsigned int        key_len)
     56{
     57	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
     58
     59	if (key_len < 3)
     60		return -EINVAL;
     61
     62	key_len -= 3;
     63
     64	memcpy(nx_ctx->priv.ccm.nonce, in_key + key_len, 3);
     65
     66	return ccm_aes_nx_set_key(tfm, in_key, key_len);
     67}
     68
     69static int ccm_aes_nx_setauthsize(struct crypto_aead *tfm,
     70				  unsigned int authsize)
     71{
     72	switch (authsize) {
     73	case 4:
     74	case 6:
     75	case 8:
     76	case 10:
     77	case 12:
     78	case 14:
     79	case 16:
     80		break;
     81	default:
     82		return -EINVAL;
     83	}
     84
     85	return 0;
     86}
     87
     88static int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm,
     89				      unsigned int authsize)
     90{
     91	switch (authsize) {
     92	case 8:
     93	case 12:
     94	case 16:
     95		break;
     96	default:
     97		return -EINVAL;
     98	}
     99
    100	return 0;
    101}
    102
    103/* taken from crypto/ccm.c */
    104static int set_msg_len(u8 *block, unsigned int msglen, int csize)
    105{
    106	__be32 data;
    107
    108	memset(block, 0, csize);
    109	block += csize;
    110
    111	if (csize >= 4)
    112		csize = 4;
    113	else if (msglen > (unsigned int)(1 << (8 * csize)))
    114		return -EOVERFLOW;
    115
    116	data = cpu_to_be32(msglen);
    117	memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
    118
    119	return 0;
    120}
    121
    122/* taken from crypto/ccm.c */
    123static inline int crypto_ccm_check_iv(const u8 *iv)
    124{
    125	/* 2 <= L <= 8, so 1 <= L' <= 7. */
    126	if (1 > iv[0] || iv[0] > 7)
    127		return -EINVAL;
    128
    129	return 0;
    130}
    131
    132/* based on code from crypto/ccm.c */
    133static int generate_b0(u8 *iv, unsigned int assoclen, unsigned int authsize,
    134		       unsigned int cryptlen, u8 *b0)
    135{
    136	unsigned int l, lp, m = authsize;
    137	int rc;
    138
    139	memcpy(b0, iv, 16);
    140
    141	lp = b0[0];
    142	l = lp + 1;
    143
    144	/* set m, bits 3-5 */
    145	*b0 |= (8 * ((m - 2) / 2));
    146
    147	/* set adata, bit 6, if associated data is used */
    148	if (assoclen)
    149		*b0 |= 64;
    150
    151	rc = set_msg_len(b0 + 16 - l, cryptlen, l);
    152
    153	return rc;
    154}
    155
    156static int generate_pat(u8                   *iv,
    157			struct aead_request  *req,
    158			struct nx_crypto_ctx *nx_ctx,
    159			unsigned int          authsize,
    160			unsigned int          nbytes,
    161			unsigned int	      assoclen,
    162			u8                   *out)
    163{
    164	struct nx_sg *nx_insg = nx_ctx->in_sg;
    165	struct nx_sg *nx_outsg = nx_ctx->out_sg;
    166	unsigned int iauth_len = 0;
    167	u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL;
    168	int rc;
    169	unsigned int max_sg_len;
    170
    171	/* zero the ctr value */
    172	memset(iv + 15 - iv[0], 0, iv[0] + 1);
    173
    174	/* page 78 of nx_wb.pdf has,
    175	 * Note: RFC3610 allows the AAD data to be up to 2^64 -1 bytes
    176	 * in length. If a full message is used, the AES CCA implementation
    177	 * restricts the maximum AAD length to 2^32 -1 bytes.
    178	 * If partial messages are used, the implementation supports
    179	 * 2^64 -1 bytes maximum AAD length.
    180	 *
    181	 * However, in the cryptoapi's aead_request structure,
    182	 * assoclen is an unsigned int, thus it cannot hold a length
    183	 * value greater than 2^32 - 1.
    184	 * Thus the AAD is further constrained by this and is never
    185	 * greater than 2^32.
    186	 */
    187
    188	if (!assoclen) {
    189		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
    190	} else if (assoclen <= 14) {
    191		/* if associated data is 14 bytes or less, we do 1 GCM
    192		 * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1,
    193		 * which is fed in through the source buffers here */
    194		b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
    195		b1 = nx_ctx->priv.ccm.iauth_tag;
    196		iauth_len = assoclen;
    197	} else if (assoclen <= 65280) {
    198		/* if associated data is less than (2^16 - 2^8), we construct
    199		 * B1 differently and feed in the associated data to a CCA
    200		 * operation */
    201		b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
    202		b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
    203		iauth_len = 14;
    204	} else {
    205		b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
    206		b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
    207		iauth_len = 10;
    208	}
    209
    210	/* generate B0 */
    211	rc = generate_b0(iv, assoclen, authsize, nbytes, b0);
    212	if (rc)
    213		return rc;
    214
    215	/* generate B1:
    216	 * add control info for associated data
    217	 * RFC 3610 and NIST Special Publication 800-38C
    218	 */
    219	if (b1) {
    220		memset(b1, 0, 16);
    221		if (assoclen <= 65280) {
    222			*(u16 *)b1 = assoclen;
    223			scatterwalk_map_and_copy(b1 + 2, req->src, 0,
    224					 iauth_len, SCATTERWALK_FROM_SG);
    225		} else {
    226			*(u16 *)b1 = (u16)(0xfffe);
    227			*(u32 *)&b1[2] = assoclen;
    228			scatterwalk_map_and_copy(b1 + 6, req->src, 0,
    229					 iauth_len, SCATTERWALK_FROM_SG);
    230		}
    231	}
    232
    233	/* now copy any remaining AAD to scatterlist and call nx... */
    234	if (!assoclen) {
    235		return rc;
    236	} else if (assoclen <= 14) {
    237		unsigned int len = 16;
    238
    239		nx_insg = nx_build_sg_list(nx_insg, b1, &len, nx_ctx->ap->sglen);
    240
    241		if (len != 16)
    242			return -EINVAL;
    243
    244		nx_outsg = nx_build_sg_list(nx_outsg, tmp, &len,
    245					    nx_ctx->ap->sglen);
    246
    247		if (len != 16)
    248			return -EINVAL;
    249
    250		/* inlen should be negative, indicating to phyp that its a
    251		 * pointer to an sg list */
    252		nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) *
    253					sizeof(struct nx_sg);
    254		nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) *
    255					sizeof(struct nx_sg);
    256
    257		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT;
    258		NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE;
    259
    260		result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac;
    261
    262		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
    263				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
    264		if (rc)
    265			return rc;
    266
    267		atomic_inc(&(nx_ctx->stats->aes_ops));
    268		atomic64_add(assoclen, &nx_ctx->stats->aes_bytes);
    269
    270	} else {
    271		unsigned int processed = 0, to_process;
    272
    273		processed += iauth_len;
    274
    275		/* page_limit: number of sg entries that fit on one page */
    276		max_sg_len = min_t(u64, nx_ctx->ap->sglen,
    277				nx_driver.of.max_sg_len/sizeof(struct nx_sg));
    278		max_sg_len = min_t(u64, max_sg_len,
    279				nx_ctx->ap->databytelen/NX_PAGE_SIZE);
    280
    281		do {
    282			to_process = min_t(u32, assoclen - processed,
    283					   nx_ctx->ap->databytelen);
    284
    285			nx_insg = nx_walk_and_build(nx_ctx->in_sg,
    286						    nx_ctx->ap->sglen,
    287						    req->src, processed,
    288						    &to_process);
    289
    290			if ((to_process + processed) < assoclen) {
    291				NX_CPB_FDM(nx_ctx->csbcpb_aead) |=
    292					NX_FDM_INTERMEDIATE;
    293			} else {
    294				NX_CPB_FDM(nx_ctx->csbcpb_aead) &=
    295					~NX_FDM_INTERMEDIATE;
    296			}
    297
    298
    299			nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
    300						sizeof(struct nx_sg);
    301
    302			result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
    303
    304			rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
    305				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
    306			if (rc)
    307				return rc;
    308
    309			memcpy(nx_ctx->csbcpb_aead->cpb.aes_cca.b0,
    310				nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0,
    311				AES_BLOCK_SIZE);
    312
    313			NX_CPB_FDM(nx_ctx->csbcpb_aead) |= NX_FDM_CONTINUATION;
    314
    315			atomic_inc(&(nx_ctx->stats->aes_ops));
    316			atomic64_add(assoclen, &nx_ctx->stats->aes_bytes);
    317
    318			processed += to_process;
    319		} while (processed < assoclen);
    320
    321		result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
    322	}
    323
    324	memcpy(out, result, AES_BLOCK_SIZE);
    325
    326	return rc;
    327}
    328
    329static int ccm_nx_decrypt(struct aead_request   *req,
    330			  u8                    *iv,
    331			  unsigned int assoclen)
    332{
    333	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
    334	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
    335	unsigned int nbytes = req->cryptlen;
    336	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
    337	struct nx_ccm_priv *priv = &nx_ctx->priv.ccm;
    338	unsigned long irq_flags;
    339	unsigned int processed = 0, to_process;
    340	int rc = -1;
    341
    342	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
    343
    344	nbytes -= authsize;
    345
    346	/* copy out the auth tag to compare with later */
    347	scatterwalk_map_and_copy(priv->oauth_tag,
    348				 req->src, nbytes + req->assoclen, authsize,
    349				 SCATTERWALK_FROM_SG);
    350
    351	rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen,
    352			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
    353	if (rc)
    354		goto out;
    355
    356	do {
    357
    358		/* to_process: the AES_BLOCK_SIZE data chunk to process in this
    359		 * update. This value is bound by sg list limits.
    360		 */
    361		to_process = nbytes - processed;
    362
    363		if ((to_process + processed) < nbytes)
    364			NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
    365		else
    366			NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
    367
    368		NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
    369
    370		rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src,
    371				       &to_process, processed + req->assoclen,
    372				       csbcpb->cpb.aes_ccm.iv_or_ctr);
    373		if (rc)
    374			goto out;
    375
    376		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
    377			   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
    378		if (rc)
    379			goto out;
    380
    381		/* for partial completion, copy following for next
    382		 * entry into loop...
    383		 */
    384		memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
    385		memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
    386			csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
    387		memcpy(csbcpb->cpb.aes_ccm.in_s0,
    388			csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
    389
    390		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
    391
    392		/* update stats */
    393		atomic_inc(&(nx_ctx->stats->aes_ops));
    394		atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
    395			     &(nx_ctx->stats->aes_bytes));
    396
    397		processed += to_process;
    398	} while (processed < nbytes);
    399
    400	rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
    401		    authsize) ? -EBADMSG : 0;
    402out:
    403	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
    404	return rc;
    405}
    406
    407static int ccm_nx_encrypt(struct aead_request   *req,
    408			  u8                    *iv,
    409			  unsigned int assoclen)
    410{
    411	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
    412	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
    413	unsigned int nbytes = req->cryptlen;
    414	unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
    415	unsigned long irq_flags;
    416	unsigned int processed = 0, to_process;
    417	int rc = -1;
    418
    419	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
    420
    421	rc = generate_pat(iv, req, nx_ctx, authsize, nbytes, assoclen,
    422			  csbcpb->cpb.aes_ccm.in_pat_or_b0);
    423	if (rc)
    424		goto out;
    425
    426	do {
    427		/* to process: the AES_BLOCK_SIZE data chunk to process in this
    428		 * update. This value is bound by sg list limits.
    429		 */
    430		to_process = nbytes - processed;
    431
    432		if ((to_process + processed) < nbytes)
    433			NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
    434		else
    435			NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
    436
    437		NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
    438
    439		rc = nx_build_sg_lists(nx_ctx, iv, req->dst, req->src,
    440				       &to_process, processed + req->assoclen,
    441				       csbcpb->cpb.aes_ccm.iv_or_ctr);
    442		if (rc)
    443			goto out;
    444
    445		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
    446				   req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
    447		if (rc)
    448			goto out;
    449
    450		/* for partial completion, copy following for next
    451		 * entry into loop...
    452		 */
    453		memcpy(iv, csbcpb->cpb.aes_ccm.out_ctr, AES_BLOCK_SIZE);
    454		memcpy(csbcpb->cpb.aes_ccm.in_pat_or_b0,
    455			csbcpb->cpb.aes_ccm.out_pat_or_mac, AES_BLOCK_SIZE);
    456		memcpy(csbcpb->cpb.aes_ccm.in_s0,
    457			csbcpb->cpb.aes_ccm.out_s0, AES_BLOCK_SIZE);
    458
    459		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
    460
    461		/* update stats */
    462		atomic_inc(&(nx_ctx->stats->aes_ops));
    463		atomic64_add(be32_to_cpu(csbcpb->csb.processed_byte_count),
    464			     &(nx_ctx->stats->aes_bytes));
    465
    466		processed += to_process;
    467
    468	} while (processed < nbytes);
    469
    470	/* copy out the auth tag */
    471	scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac,
    472				 req->dst, nbytes + req->assoclen, authsize,
    473				 SCATTERWALK_TO_SG);
    474
    475out:
    476	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
    477	return rc;
    478}
    479
    480static int ccm4309_aes_nx_encrypt(struct aead_request *req)
    481{
    482	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
    483	struct nx_gcm_rctx *rctx = aead_request_ctx(req);
    484	u8 *iv = rctx->iv;
    485
    486	iv[0] = 3;
    487	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
    488	memcpy(iv + 4, req->iv, 8);
    489
    490	return ccm_nx_encrypt(req, iv, req->assoclen - 8);
    491}
    492
    493static int ccm_aes_nx_encrypt(struct aead_request *req)
    494{
    495	int rc;
    496
    497	rc = crypto_ccm_check_iv(req->iv);
    498	if (rc)
    499		return rc;
    500
    501	return ccm_nx_encrypt(req, req->iv, req->assoclen);
    502}
    503
    504static int ccm4309_aes_nx_decrypt(struct aead_request *req)
    505{
    506	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
    507	struct nx_gcm_rctx *rctx = aead_request_ctx(req);
    508	u8 *iv = rctx->iv;
    509
    510	iv[0] = 3;
    511	memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
    512	memcpy(iv + 4, req->iv, 8);
    513
    514	return ccm_nx_decrypt(req, iv, req->assoclen - 8);
    515}
    516
    517static int ccm_aes_nx_decrypt(struct aead_request *req)
    518{
    519	int rc;
    520
    521	rc = crypto_ccm_check_iv(req->iv);
    522	if (rc)
    523		return rc;
    524
    525	return ccm_nx_decrypt(req, req->iv, req->assoclen);
    526}
    527
    528struct aead_alg nx_ccm_aes_alg = {
    529	.base = {
    530		.cra_name        = "ccm(aes)",
    531		.cra_driver_name = "ccm-aes-nx",
    532		.cra_priority    = 300,
    533		.cra_flags       = CRYPTO_ALG_NEED_FALLBACK,
    534		.cra_blocksize   = 1,
    535		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
    536		.cra_module      = THIS_MODULE,
    537	},
    538	.init        = nx_crypto_ctx_aes_ccm_init,
    539	.exit        = nx_crypto_ctx_aead_exit,
    540	.ivsize      = AES_BLOCK_SIZE,
    541	.maxauthsize = AES_BLOCK_SIZE,
    542	.setkey      = ccm_aes_nx_set_key,
    543	.setauthsize = ccm_aes_nx_setauthsize,
    544	.encrypt     = ccm_aes_nx_encrypt,
    545	.decrypt     = ccm_aes_nx_decrypt,
    546};
    547
    548struct aead_alg nx_ccm4309_aes_alg = {
    549	.base = {
    550		.cra_name        = "rfc4309(ccm(aes))",
    551		.cra_driver_name = "rfc4309-ccm-aes-nx",
    552		.cra_priority    = 300,
    553		.cra_flags       = CRYPTO_ALG_NEED_FALLBACK,
    554		.cra_blocksize   = 1,
    555		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
    556		.cra_module      = THIS_MODULE,
    557	},
    558	.init        = nx_crypto_ctx_aes_ccm_init,
    559	.exit        = nx_crypto_ctx_aead_exit,
    560	.ivsize      = 8,
    561	.maxauthsize = AES_BLOCK_SIZE,
    562	.setkey      = ccm4309_aes_nx_set_key,
    563	.setauthsize = ccm4309_aes_nx_setauthsize,
    564	.encrypt     = ccm4309_aes_nx_encrypt,
    565	.decrypt     = ccm4309_aes_nx_decrypt,
    566};