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-xcbc.c (9507B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * AES XCBC routines supporting the Power 7+ Nest Accelerators driver
      4 *
      5 * Copyright (C) 2011-2012 International Business Machines Inc.
      6 *
      7 * Author: Kent Yoder <yoder1@us.ibm.com>
      8 */
      9
     10#include <crypto/internal/hash.h>
     11#include <crypto/aes.h>
     12#include <crypto/algapi.h>
     13#include <linux/module.h>
     14#include <linux/types.h>
     15#include <linux/crypto.h>
     16#include <asm/vio.h>
     17
     18#include "nx_csbcpb.h"
     19#include "nx.h"
     20
     21
     22struct xcbc_state {
     23	u8 state[AES_BLOCK_SIZE];
     24	unsigned int count;
     25	u8 buffer[AES_BLOCK_SIZE];
     26};
     27
     28static int nx_xcbc_set_key(struct crypto_shash *desc,
     29			   const u8            *in_key,
     30			   unsigned int         key_len)
     31{
     32	struct nx_crypto_ctx *nx_ctx = crypto_shash_ctx(desc);
     33	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
     34
     35	switch (key_len) {
     36	case AES_KEYSIZE_128:
     37		nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
     38		break;
     39	default:
     40		return -EINVAL;
     41	}
     42
     43	memcpy(csbcpb->cpb.aes_xcbc.key, in_key, key_len);
     44
     45	return 0;
     46}
     47
     48/*
     49 * Based on RFC 3566, for a zero-length message:
     50 *
     51 * n = 1
     52 * K1 = E(K, 0x01010101010101010101010101010101)
     53 * K3 = E(K, 0x03030303030303030303030303030303)
     54 * E[0] = 0x00000000000000000000000000000000
     55 * M[1] = 0x80000000000000000000000000000000 (0 length message with padding)
     56 * E[1] = (K1, M[1] ^ E[0] ^ K3)
     57 * Tag = M[1]
     58 */
     59static int nx_xcbc_empty(struct shash_desc *desc, u8 *out)
     60{
     61	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
     62	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
     63	struct nx_sg *in_sg, *out_sg;
     64	u8 keys[2][AES_BLOCK_SIZE];
     65	u8 key[32];
     66	int rc = 0;
     67	int len;
     68
     69	/* Change to ECB mode */
     70	csbcpb->cpb.hdr.mode = NX_MODE_AES_ECB;
     71	memcpy(key, csbcpb->cpb.aes_xcbc.key, AES_BLOCK_SIZE);
     72	memcpy(csbcpb->cpb.aes_ecb.key, key, AES_BLOCK_SIZE);
     73	NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
     74
     75	/* K1 and K3 base patterns */
     76	memset(keys[0], 0x01, sizeof(keys[0]));
     77	memset(keys[1], 0x03, sizeof(keys[1]));
     78
     79	len = sizeof(keys);
     80	/* Generate K1 and K3 encrypting the patterns */
     81	in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *) keys, &len,
     82				 nx_ctx->ap->sglen);
     83
     84	if (len != sizeof(keys))
     85		return -EINVAL;
     86
     87	out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *) keys, &len,
     88				  nx_ctx->ap->sglen);
     89
     90	if (len != sizeof(keys))
     91		return -EINVAL;
     92
     93	nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
     94	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
     95
     96	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op, 0);
     97	if (rc)
     98		goto out;
     99	atomic_inc(&(nx_ctx->stats->aes_ops));
    100
    101	/* XOr K3 with the padding for a 0 length message */
    102	keys[1][0] ^= 0x80;
    103
    104	len = sizeof(keys[1]);
    105
    106	/* Encrypt the final result */
    107	memcpy(csbcpb->cpb.aes_ecb.key, keys[0], AES_BLOCK_SIZE);
    108	in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *) keys[1], &len,
    109				 nx_ctx->ap->sglen);
    110
    111	if (len != sizeof(keys[1]))
    112		return -EINVAL;
    113
    114	len = AES_BLOCK_SIZE;
    115	out_sg = nx_build_sg_list(nx_ctx->out_sg, out, &len,
    116				  nx_ctx->ap->sglen);
    117
    118	if (len != AES_BLOCK_SIZE)
    119		return -EINVAL;
    120
    121	nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
    122	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
    123
    124	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op, 0);
    125	if (rc)
    126		goto out;
    127	atomic_inc(&(nx_ctx->stats->aes_ops));
    128
    129out:
    130	/* Restore XCBC mode */
    131	csbcpb->cpb.hdr.mode = NX_MODE_AES_XCBC_MAC;
    132	memcpy(csbcpb->cpb.aes_xcbc.key, key, AES_BLOCK_SIZE);
    133	NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
    134
    135	return rc;
    136}
    137
    138static int nx_crypto_ctx_aes_xcbc_init2(struct crypto_tfm *tfm)
    139{
    140	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
    141	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
    142	int err;
    143
    144	err = nx_crypto_ctx_aes_xcbc_init(tfm);
    145	if (err)
    146		return err;
    147
    148	nx_ctx_init(nx_ctx, HCOP_FC_AES);
    149
    150	NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
    151	csbcpb->cpb.hdr.mode = NX_MODE_AES_XCBC_MAC;
    152
    153	return 0;
    154}
    155
    156static int nx_xcbc_init(struct shash_desc *desc)
    157{
    158	struct xcbc_state *sctx = shash_desc_ctx(desc);
    159
    160	memset(sctx, 0, sizeof *sctx);
    161
    162	return 0;
    163}
    164
    165static int nx_xcbc_update(struct shash_desc *desc,
    166			  const u8          *data,
    167			  unsigned int       len)
    168{
    169	struct xcbc_state *sctx = shash_desc_ctx(desc);
    170	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
    171	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
    172	struct nx_sg *in_sg;
    173	struct nx_sg *out_sg;
    174	u32 to_process = 0, leftover, total;
    175	unsigned int max_sg_len;
    176	unsigned long irq_flags;
    177	int rc = 0;
    178	int data_len;
    179
    180	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
    181
    182
    183	total = sctx->count + len;
    184
    185	/* 2 cases for total data len:
    186	 *  1: <= AES_BLOCK_SIZE: copy into state, return 0
    187	 *  2: > AES_BLOCK_SIZE: process X blocks, copy in leftover
    188	 */
    189	if (total <= AES_BLOCK_SIZE) {
    190		memcpy(sctx->buffer + sctx->count, data, len);
    191		sctx->count += len;
    192		goto out;
    193	}
    194
    195	in_sg = nx_ctx->in_sg;
    196	max_sg_len = min_t(u64, nx_driver.of.max_sg_len/sizeof(struct nx_sg),
    197				nx_ctx->ap->sglen);
    198	max_sg_len = min_t(u64, max_sg_len,
    199				nx_ctx->ap->databytelen/NX_PAGE_SIZE);
    200
    201	data_len = AES_BLOCK_SIZE;
    202	out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
    203				  &len, nx_ctx->ap->sglen);
    204
    205	if (data_len != AES_BLOCK_SIZE) {
    206		rc = -EINVAL;
    207		goto out;
    208	}
    209
    210	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
    211
    212	do {
    213		to_process = total - to_process;
    214		to_process = to_process & ~(AES_BLOCK_SIZE - 1);
    215
    216		leftover = total - to_process;
    217
    218		/* the hardware will not accept a 0 byte operation for this
    219		 * algorithm and the operation MUST be finalized to be correct.
    220		 * So if we happen to get an update that falls on a block sized
    221		 * boundary, we must save off the last block to finalize with
    222		 * later. */
    223		if (!leftover) {
    224			to_process -= AES_BLOCK_SIZE;
    225			leftover = AES_BLOCK_SIZE;
    226		}
    227
    228		if (sctx->count) {
    229			data_len = sctx->count;
    230			in_sg = nx_build_sg_list(nx_ctx->in_sg,
    231						(u8 *) sctx->buffer,
    232						&data_len,
    233						max_sg_len);
    234			if (data_len != sctx->count) {
    235				rc = -EINVAL;
    236				goto out;
    237			}
    238		}
    239
    240		data_len = to_process - sctx->count;
    241		in_sg = nx_build_sg_list(in_sg,
    242					(u8 *) data,
    243					&data_len,
    244					max_sg_len);
    245
    246		if (data_len != to_process - sctx->count) {
    247			rc = -EINVAL;
    248			goto out;
    249		}
    250
    251		nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
    252					sizeof(struct nx_sg);
    253
    254		/* we've hit the nx chip previously and we're updating again,
    255		 * so copy over the partial digest */
    256		if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
    257			memcpy(csbcpb->cpb.aes_xcbc.cv,
    258				csbcpb->cpb.aes_xcbc.out_cv_mac,
    259				AES_BLOCK_SIZE);
    260		}
    261
    262		NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
    263		if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
    264			rc = -EINVAL;
    265			goto out;
    266		}
    267
    268		rc = nx_hcall_sync(nx_ctx, &nx_ctx->op, 0);
    269		if (rc)
    270			goto out;
    271
    272		atomic_inc(&(nx_ctx->stats->aes_ops));
    273
    274		/* everything after the first update is continuation */
    275		NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
    276
    277		total -= to_process;
    278		data += to_process - sctx->count;
    279		sctx->count = 0;
    280		in_sg = nx_ctx->in_sg;
    281	} while (leftover > AES_BLOCK_SIZE);
    282
    283	/* copy the leftover back into the state struct */
    284	memcpy(sctx->buffer, data, leftover);
    285	sctx->count = leftover;
    286
    287out:
    288	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
    289	return rc;
    290}
    291
    292static int nx_xcbc_final(struct shash_desc *desc, u8 *out)
    293{
    294	struct xcbc_state *sctx = shash_desc_ctx(desc);
    295	struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
    296	struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
    297	struct nx_sg *in_sg, *out_sg;
    298	unsigned long irq_flags;
    299	int rc = 0;
    300	int len;
    301
    302	spin_lock_irqsave(&nx_ctx->lock, irq_flags);
    303
    304	if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
    305		/* we've hit the nx chip previously, now we're finalizing,
    306		 * so copy over the partial digest */
    307		memcpy(csbcpb->cpb.aes_xcbc.cv,
    308		       csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
    309	} else if (sctx->count == 0) {
    310		/*
    311		 * we've never seen an update, so this is a 0 byte op. The
    312		 * hardware cannot handle a 0 byte op, so just ECB to
    313		 * generate the hash.
    314		 */
    315		rc = nx_xcbc_empty(desc, out);
    316		goto out;
    317	}
    318
    319	/* final is represented by continuing the operation and indicating that
    320	 * this is not an intermediate operation */
    321	NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
    322
    323	len = sctx->count;
    324	in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buffer,
    325				 &len, nx_ctx->ap->sglen);
    326
    327	if (len != sctx->count) {
    328		rc = -EINVAL;
    329		goto out;
    330	}
    331
    332	len = AES_BLOCK_SIZE;
    333	out_sg = nx_build_sg_list(nx_ctx->out_sg, out, &len,
    334				  nx_ctx->ap->sglen);
    335
    336	if (len != AES_BLOCK_SIZE) {
    337		rc = -EINVAL;
    338		goto out;
    339	}
    340
    341	nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
    342	nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
    343
    344	if (!nx_ctx->op.outlen) {
    345		rc = -EINVAL;
    346		goto out;
    347	}
    348
    349	rc = nx_hcall_sync(nx_ctx, &nx_ctx->op, 0);
    350	if (rc)
    351		goto out;
    352
    353	atomic_inc(&(nx_ctx->stats->aes_ops));
    354
    355	memcpy(out, csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
    356out:
    357	spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
    358	return rc;
    359}
    360
    361struct shash_alg nx_shash_aes_xcbc_alg = {
    362	.digestsize = AES_BLOCK_SIZE,
    363	.init       = nx_xcbc_init,
    364	.update     = nx_xcbc_update,
    365	.final      = nx_xcbc_final,
    366	.setkey     = nx_xcbc_set_key,
    367	.descsize   = sizeof(struct xcbc_state),
    368	.statesize  = sizeof(struct xcbc_state),
    369	.base       = {
    370		.cra_name        = "xcbc(aes)",
    371		.cra_driver_name = "xcbc-aes-nx",
    372		.cra_priority    = 300,
    373		.cra_blocksize   = AES_BLOCK_SIZE,
    374		.cra_module      = THIS_MODULE,
    375		.cra_ctxsize     = sizeof(struct nx_crypto_ctx),
    376		.cra_init        = nx_crypto_ctx_aes_xcbc_init2,
    377		.cra_exit        = nx_crypto_ctx_exit,
    378	}
    379};