Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 87870cfb authored by Iuliana Prodan's avatar Iuliana Prodan Committed by Herbert Xu
Browse files

crypto: caam - add support for cmac(aes)



Add cmac(aes) keyed hash offloading support.

Similar to xcbc implementation, driver must make sure there are still
some bytes buffered when ahash_final() is called. This way HW is able to
decide whether padding is needed and which key to derive (L -> K1 / K2)
for the last block.

Signed-off-by: default avatarIuliana Prodan <iuliana.prodan@nxp.com>
Signed-off-by: default avatarHoria Geantă <horia.geanta@nxp.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 7e33d4d4
Loading
Loading
Loading
Loading
+111 −21
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
 * caam - Freescale FSL CAAM support for ahash functions of crypto API
 *
 * Copyright 2011 Freescale Semiconductor, Inc.
 * Copyright 2018 NXP
 * Copyright 2018-2019 NXP
 *
 * Based on caamalg.c crypto API driver.
 *
@@ -159,12 +159,11 @@ static inline int *alt_buflen(struct caam_hash_state *state)
	return state->current_buf ? &state->buflen_0 : &state->buflen_1;
}

static inline bool is_xcbc_aes(u32 algtype)
static inline bool is_cmac_aes(u32 algtype)
{
	return (algtype & (OP_ALG_ALGSEL_MASK | OP_ALG_AAI_MASK)) ==
	       (OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC);
	       (OP_ALG_ALGSEL_AES | OP_ALG_AAI_CMAC);
}

/* Common job descriptor seq in/out ptr routines */

/* Map state->caam_ctx, and append seq_out_ptr command that points to it */
@@ -311,8 +310,8 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash)

	/* shared descriptor for ahash_update */
	desc = ctx->sh_desc_update;
	cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len,
			  ctx->ctx_len, 0);
	cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_UPDATE,
			    ctx->ctx_len, ctx->ctx_len, 0);
	dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma,
				   desc_bytes(desc), ctx->dir);
	print_hex_dump_debug("axcbc update shdesc@" __stringify(__LINE__)" : ",
@@ -321,8 +320,8 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash)

	/* shared descriptor for ahash_{final,finup} */
	desc = ctx->sh_desc_fin;
	cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize,
			  ctx->ctx_len, 0);
	cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_FINALIZE,
			    digestsize, ctx->ctx_len, 0);
	dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma,
				   desc_bytes(desc), ctx->dir);
	print_hex_dump_debug("axcbc finup shdesc@" __stringify(__LINE__)" : ",
@@ -334,7 +333,7 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash)

	/* shared descriptor for first invocation of ahash_update */
	desc = ctx->sh_desc_update_first;
	cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len,
	cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len,
			    ctx->ctx_len, ctx->key_dma);
	dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma,
				   desc_bytes(desc), ctx->dir);
@@ -344,13 +343,62 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash)

	/* shared descriptor for ahash_digest */
	desc = ctx->sh_desc_digest;
	cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize,
			  ctx->ctx_len, 0);
	cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INITFINAL,
			    digestsize, ctx->ctx_len, 0);
	dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma,
				   desc_bytes(desc), ctx->dir);
	print_hex_dump_debug("axcbc digest shdesc@" __stringify(__LINE__)" : ",
			     DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
			     1);
	return 0;
}

static int acmac_set_sh_desc(struct crypto_ahash *ahash)
{
	struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);
	int digestsize = crypto_ahash_digestsize(ahash);
	struct device *jrdev = ctx->jrdev;
	u32 *desc;

	/* shared descriptor for ahash_update */
	desc = ctx->sh_desc_update;
	cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_UPDATE,
			    ctx->ctx_len, ctx->ctx_len, 0);
	dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma,
				   desc_bytes(desc), ctx->dir);
	print_hex_dump_debug("acmac update shdesc@" __stringify(__LINE__)" : ",
			     DUMP_PREFIX_ADDRESS, 16, 4, desc,
			     desc_bytes(desc), 1);

	/* shared descriptor for ahash_{final,finup} */
	desc = ctx->sh_desc_fin;
	cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_FINALIZE,
			    digestsize, ctx->ctx_len, 0);
	dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma,
				   desc_bytes(desc), ctx->dir);
	print_hex_dump_debug("acmac finup shdesc@" __stringify(__LINE__)" : ",
			     DUMP_PREFIX_ADDRESS, 16, 4, desc,
			     desc_bytes(desc), 1);

	/* shared descriptor for first invocation of ahash_update */
	desc = ctx->sh_desc_update_first;
	cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INIT, ctx->ctx_len,
			    ctx->ctx_len, 0);
	dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma,
				   desc_bytes(desc), ctx->dir);
	print_hex_dump_debug("acmac update first shdesc@" __stringify(__LINE__)" : ",
			     DUMP_PREFIX_ADDRESS, 16, 4, desc,
			     desc_bytes(desc), 1);

	/* shared descriptor for ahash_digest */
	desc = ctx->sh_desc_digest;
	cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INITFINAL,
			    digestsize, ctx->ctx_len, 0);
	dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma,
				   desc_bytes(desc), ctx->dir);
	print_hex_dump_debug("acmac digest shdesc@" __stringify(__LINE__)" : ",
			     DUMP_PREFIX_ADDRESS, 16, 4, desc,
			     desc_bytes(desc), 1);

	return 0;
}
@@ -502,6 +550,22 @@ static int axcbc_setkey(struct crypto_ahash *ahash, const u8 *key,

	return axcbc_set_sh_desc(ahash);
}

static int acmac_setkey(struct crypto_ahash *ahash, const u8 *key,
			unsigned int keylen)
{
	struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash);

	/* key is immediate data for all cmac shared descriptors */
	ctx->adata.key_virt = key;
	ctx->adata.keylen = keylen;

	print_hex_dump_debug("acmac ctx.key@" __stringify(__LINE__)" : ",
			     DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);

	return acmac_set_sh_desc(ahash);
}

/*
 * ahash_edesc - s/w-extended ahash descriptor
 * @dst_dma: physical mapped address of req->result
@@ -779,10 +843,11 @@ static int ahash_update_ctx(struct ahash_request *req)
	to_hash = in_len - *next_buflen;

	/*
	 * For XCBC, if to_hash is multiple of block size,
	 * For XCBC and CMAC, if to_hash is multiple of block size,
	 * keep last block in internal buffer
	 */
	if (is_xcbc_aes(ctx->adata.algtype) && to_hash >= blocksize &&
	if ((is_xcbc_aes(ctx->adata.algtype) ||
	     is_cmac_aes(ctx->adata.algtype)) && to_hash >= blocksize &&
	     (*next_buflen == 0)) {
		*next_buflen = blocksize;
		to_hash -= blocksize;
@@ -1224,10 +1289,11 @@ static int ahash_update_no_ctx(struct ahash_request *req)
	to_hash = in_len - *next_buflen;

	/*
	 * For XCBC, if to_hash is multiple of block size,
	 * For XCBC and CMAC, if to_hash is multiple of block size,
	 * keep last block in internal buffer
	 */
	if (is_xcbc_aes(ctx->adata.algtype) && to_hash >= blocksize &&
	if ((is_xcbc_aes(ctx->adata.algtype) ||
	     is_cmac_aes(ctx->adata.algtype)) && to_hash >= blocksize &&
	     (*next_buflen == 0)) {
		*next_buflen = blocksize;
		to_hash -= blocksize;
@@ -1448,10 +1514,11 @@ static int ahash_update_first(struct ahash_request *req)
	to_hash = req->nbytes - *next_buflen;

	/*
	 * For XCBC, if to_hash is multiple of block size,
	 * For XCBC and CMAC, if to_hash is multiple of block size,
	 * keep last block in internal buffer
	 */
	if (is_xcbc_aes(ctx->adata.algtype) && to_hash >= blocksize &&
	if ((is_xcbc_aes(ctx->adata.algtype) ||
	     is_cmac_aes(ctx->adata.algtype)) && to_hash >= blocksize &&
	     (*next_buflen == 0)) {
		*next_buflen = blocksize;
		to_hash -= blocksize;
@@ -1783,6 +1850,25 @@ static struct caam_hash_template driver_hash[] = {
			},
		 },
		.alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC,
	}, {
		.hmac_name = "cmac(aes)",
		.hmac_driver_name = "cmac-aes-caam",
		.blocksize = AES_BLOCK_SIZE,
		.template_ahash = {
			.init = ahash_init,
			.update = ahash_update,
			.final = ahash_final,
			.finup = ahash_finup,
			.digest = ahash_digest,
			.export = ahash_export,
			.import = ahash_import,
			.setkey = acmac_setkey,
			.halg = {
				.digestsize = AES_BLOCK_SIZE,
				.statesize = sizeof(struct caam_export_state),
			},
		 },
		.alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CMAC,
	},
};

@@ -1839,6 +1925,10 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
			caam_jr_free(ctx->jrdev);
			return -ENOMEM;
		}
	} else if (is_cmac_aes(caam_hash->alg_type)) {
		ctx->dir = DMA_TO_DEVICE;
		ctx->adata.algtype = OP_TYPE_CLASS1_ALG | caam_hash->alg_type;
		ctx->ctx_len = 32;
	} else {
		ctx->dir = priv->era >= 6 ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
		ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type;
+20 −10
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
/*
 * Shared descriptors for ahash algorithms
 *
 * Copyright 2017-2018 NXP
 * Copyright 2017-2019 NXP
 */

#include "compat.h"
@@ -76,7 +76,8 @@ void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
EXPORT_SYMBOL(cnstr_shdsc_ahash);

/**
 * cnstr_shdsc_axcbc - axcbc shared descriptor
 * cnstr_shdsc_sk_hash - shared descriptor for symmetric key cipher-based
 *                       hash algorithms
 * @desc: pointer to buffer used for descriptor construction
 * @adata: pointer to authentication transform definitions.
 * @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE}
@@ -84,7 +85,7 @@ EXPORT_SYMBOL(cnstr_shdsc_ahash);
 * @ctx_len: size of Context Register
 * @key_dma: I/O Virtual Address of the key
 */
void cnstr_shdsc_axcbc(u32 * const desc, struct alginfo *adata, u32 state,
void cnstr_shdsc_sk_hash(u32 * const desc, struct alginfo *adata, u32 state,
			 int digestsize, int ctx_len, dma_addr_t key_dma)
{
	u32 *skip_key_load;
@@ -98,9 +99,14 @@ void cnstr_shdsc_axcbc(u32 * const desc, struct alginfo *adata, u32 state,
		append_key_as_imm(desc, adata->key_virt, adata->keylen,
				  adata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
	} else { /* UPDATE, FINALIZE */
		if (is_xcbc_aes(adata->algtype))
			/* Load K1 */
			append_key(desc, adata->key_dma, adata->keylen,
				   CLASS_1 | KEY_DEST_CLASS_REG | KEY_ENC);
		else /* CMAC */
			append_key_as_imm(desc, adata->key_virt, adata->keylen,
					  adata->keylen, CLASS_1 |
					  KEY_DEST_CLASS_REG);
		/* Restore context */
		append_seq_load(desc, ctx_len, LDST_CLASS_1_CCB |
				LDST_SRCDST_BYTE_CONTEXT);
@@ -121,15 +127,19 @@ void cnstr_shdsc_axcbc(u32 * const desc, struct alginfo *adata, u32 state,
	append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_LAST1 |
			     FIFOLD_TYPE_MSG | FIFOLDST_VLF);

	/* Save context (partial hash, K2, K3) */
	/*
	 * Save context:
	 * - xcbc: partial hash, keys K2 and K3
	 * - cmac: partial hash, constant L = E(K,0)
	 */
	append_seq_store(desc, digestsize, LDST_CLASS_1_CCB |
			 LDST_SRCDST_BYTE_CONTEXT);
	if (state == OP_ALG_AS_INIT)
	if (is_xcbc_aes(adata->algtype) && state == OP_ALG_AS_INIT)
		/* Save K1 */
		append_fifo_store(desc, key_dma, adata->keylen,
				  LDST_CLASS_1_CCB | FIFOST_TYPE_KEY_KEK);
}
EXPORT_SYMBOL(cnstr_shdsc_axcbc);
EXPORT_SYMBOL(cnstr_shdsc_sk_hash);

MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("FSL CAAM ahash descriptors support");
+8 −2
Original line number Diff line number Diff line
@@ -15,9 +15,15 @@
#define DESC_AHASH_FINAL_LEN		(DESC_AHASH_BASE + 5 * CAAM_CMD_SZ)
#define DESC_AHASH_DIGEST_LEN		(DESC_AHASH_BASE + 4 * CAAM_CMD_SZ)

static inline bool is_xcbc_aes(u32 algtype)
{
	return (algtype & (OP_ALG_ALGSEL_MASK | OP_ALG_AAI_MASK)) ==
	       (OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC);
}

void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
		       int digestsize, int ctx_len, bool import_ctx, int era);

void cnstr_shdsc_axcbc(u32 * const desc, struct alginfo *adata, u32 state,
void cnstr_shdsc_sk_hash(u32 * const desc, struct alginfo *adata, u32 state,
			 int digestsize, int ctx_len, dma_addr_t key_dma);
#endif /* _CAAMHASH_DESC_H_ */