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

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
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* caam - Freescale FSL CAAM support for ahash functions of crypto API * caam - Freescale FSL CAAM support for ahash functions of crypto API
* *
* Copyright 2011 Freescale Semiconductor, Inc. * Copyright 2011 Freescale Semiconductor, Inc.
* Copyright 2018 NXP * Copyright 2018-2019 NXP
* *
* Based on caamalg.c crypto API driver. * Based on caamalg.c crypto API driver.
* *
...@@ -159,12 +159,11 @@ static inline int *alt_buflen(struct caam_hash_state *state) ...@@ -159,12 +159,11 @@ static inline int *alt_buflen(struct caam_hash_state *state)
return state->current_buf ? &state->buflen_0 : &state->buflen_1; 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)) == 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 */ /* Common job descriptor seq in/out ptr routines */
/* Map state->caam_ctx, and append seq_out_ptr command that points to it */ /* 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) ...@@ -311,8 +310,8 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash)
/* shared descriptor for ahash_update */ /* shared descriptor for ahash_update */
desc = ctx->sh_desc_update; desc = ctx->sh_desc_update;
cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_UPDATE, ctx->ctx_len, cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_UPDATE,
ctx->ctx_len, 0); ctx->ctx_len, ctx->ctx_len, 0);
dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma, dma_sync_single_for_device(jrdev, ctx->sh_desc_update_dma,
desc_bytes(desc), ctx->dir); desc_bytes(desc), ctx->dir);
print_hex_dump_debug("axcbc update shdesc@" __stringify(__LINE__)" : ", print_hex_dump_debug("axcbc update shdesc@" __stringify(__LINE__)" : ",
...@@ -321,8 +320,8 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash) ...@@ -321,8 +320,8 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash)
/* shared descriptor for ahash_{final,finup} */ /* shared descriptor for ahash_{final,finup} */
desc = ctx->sh_desc_fin; desc = ctx->sh_desc_fin;
cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_FINALIZE, digestsize, cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_FINALIZE,
ctx->ctx_len, 0); digestsize, ctx->ctx_len, 0);
dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma, dma_sync_single_for_device(jrdev, ctx->sh_desc_fin_dma,
desc_bytes(desc), ctx->dir); desc_bytes(desc), ctx->dir);
print_hex_dump_debug("axcbc finup shdesc@" __stringify(__LINE__)" : ", print_hex_dump_debug("axcbc finup shdesc@" __stringify(__LINE__)" : ",
...@@ -334,8 +333,8 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash) ...@@ -334,8 +333,8 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash)
/* shared descriptor for first invocation of ahash_update */ /* shared descriptor for first invocation of ahash_update */
desc = ctx->sh_desc_update_first; 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); ctx->ctx_len, ctx->key_dma);
dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma, dma_sync_single_for_device(jrdev, ctx->sh_desc_update_first_dma,
desc_bytes(desc), ctx->dir); desc_bytes(desc), ctx->dir);
print_hex_dump_debug("axcbc update first shdesc@" __stringify(__LINE__)" : ", print_hex_dump_debug("axcbc update first shdesc@" __stringify(__LINE__)" : ",
...@@ -344,13 +343,62 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash) ...@@ -344,13 +343,62 @@ static int axcbc_set_sh_desc(struct crypto_ahash *ahash)
/* shared descriptor for ahash_digest */ /* shared descriptor for ahash_digest */
desc = ctx->sh_desc_digest; desc = ctx->sh_desc_digest;
cnstr_shdsc_axcbc(desc, &ctx->adata, OP_ALG_AS_INITFINAL, digestsize, cnstr_shdsc_sk_hash(desc, &ctx->adata, OP_ALG_AS_INITFINAL,
ctx->ctx_len, 0); digestsize, ctx->ctx_len, 0);
dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma, dma_sync_single_for_device(jrdev, ctx->sh_desc_digest_dma,
desc_bytes(desc), ctx->dir); desc_bytes(desc), ctx->dir);
print_hex_dump_debug("axcbc digest shdesc@" __stringify(__LINE__)" : ", print_hex_dump_debug("axcbc digest shdesc@" __stringify(__LINE__)" : ",
DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
1); 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; return 0;
} }
...@@ -502,6 +550,22 @@ static int axcbc_setkey(struct crypto_ahash *ahash, const u8 *key, ...@@ -502,6 +550,22 @@ static int axcbc_setkey(struct crypto_ahash *ahash, const u8 *key,
return axcbc_set_sh_desc(ahash); 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 * ahash_edesc - s/w-extended ahash descriptor
* @dst_dma: physical mapped address of req->result * @dst_dma: physical mapped address of req->result
...@@ -779,11 +843,12 @@ static int ahash_update_ctx(struct ahash_request *req) ...@@ -779,11 +843,12 @@ static int ahash_update_ctx(struct ahash_request *req)
to_hash = in_len - *next_buflen; 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 * keep last block in internal buffer
*/ */
if (is_xcbc_aes(ctx->adata.algtype) && to_hash >= blocksize && if ((is_xcbc_aes(ctx->adata.algtype) ||
(*next_buflen == 0)) { is_cmac_aes(ctx->adata.algtype)) && to_hash >= blocksize &&
(*next_buflen == 0)) {
*next_buflen = blocksize; *next_buflen = blocksize;
to_hash -= blocksize; to_hash -= blocksize;
} }
...@@ -1224,11 +1289,12 @@ static int ahash_update_no_ctx(struct ahash_request *req) ...@@ -1224,11 +1289,12 @@ static int ahash_update_no_ctx(struct ahash_request *req)
to_hash = in_len - *next_buflen; 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 * keep last block in internal buffer
*/ */
if (is_xcbc_aes(ctx->adata.algtype) && to_hash >= blocksize && if ((is_xcbc_aes(ctx->adata.algtype) ||
(*next_buflen == 0)) { is_cmac_aes(ctx->adata.algtype)) && to_hash >= blocksize &&
(*next_buflen == 0)) {
*next_buflen = blocksize; *next_buflen = blocksize;
to_hash -= blocksize; to_hash -= blocksize;
} }
...@@ -1448,11 +1514,12 @@ static int ahash_update_first(struct ahash_request *req) ...@@ -1448,11 +1514,12 @@ static int ahash_update_first(struct ahash_request *req)
to_hash = req->nbytes - *next_buflen; 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 * keep last block in internal buffer
*/ */
if (is_xcbc_aes(ctx->adata.algtype) && to_hash >= blocksize && if ((is_xcbc_aes(ctx->adata.algtype) ||
(*next_buflen == 0)) { is_cmac_aes(ctx->adata.algtype)) && to_hash >= blocksize &&
(*next_buflen == 0)) {
*next_buflen = blocksize; *next_buflen = blocksize;
to_hash -= blocksize; to_hash -= blocksize;
} }
...@@ -1783,6 +1850,25 @@ static struct caam_hash_template driver_hash[] = { ...@@ -1783,6 +1850,25 @@ static struct caam_hash_template driver_hash[] = {
}, },
}, },
.alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_XCBC_MAC, .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) ...@@ -1839,6 +1925,10 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm)
caam_jr_free(ctx->jrdev); caam_jr_free(ctx->jrdev);
return -ENOMEM; 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 { } else {
ctx->dir = priv->era >= 6 ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE; ctx->dir = priv->era >= 6 ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Shared descriptors for ahash algorithms * Shared descriptors for ahash algorithms
* *
* Copyright 2017-2018 NXP * Copyright 2017-2019 NXP
*/ */
#include "compat.h" #include "compat.h"
...@@ -76,7 +76,8 @@ void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state, ...@@ -76,7 +76,8 @@ void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
EXPORT_SYMBOL(cnstr_shdsc_ahash); 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 * @desc: pointer to buffer used for descriptor construction
* @adata: pointer to authentication transform definitions. * @adata: pointer to authentication transform definitions.
* @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE} * @state: algorithm state OP_ALG_AS_{INIT, FINALIZE, INITFINALIZE, UPDATE}
...@@ -84,8 +85,8 @@ EXPORT_SYMBOL(cnstr_shdsc_ahash); ...@@ -84,8 +85,8 @@ EXPORT_SYMBOL(cnstr_shdsc_ahash);
* @ctx_len: size of Context Register * @ctx_len: size of Context Register
* @key_dma: I/O Virtual Address of the key * @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) int digestsize, int ctx_len, dma_addr_t key_dma)
{ {
u32 *skip_key_load; u32 *skip_key_load;
...@@ -98,9 +99,14 @@ void cnstr_shdsc_axcbc(u32 * const desc, struct alginfo *adata, u32 state, ...@@ -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, append_key_as_imm(desc, adata->key_virt, adata->keylen,
adata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); adata->keylen, CLASS_1 | KEY_DEST_CLASS_REG);
} else { /* UPDATE, FINALIZE */ } else { /* UPDATE, FINALIZE */
/* Load K1 */ if (is_xcbc_aes(adata->algtype))
append_key(desc, adata->key_dma, adata->keylen, /* Load K1 */
CLASS_1 | KEY_DEST_CLASS_REG | KEY_ENC); 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 */ /* Restore context */
append_seq_load(desc, ctx_len, LDST_CLASS_1_CCB | append_seq_load(desc, ctx_len, LDST_CLASS_1_CCB |
LDST_SRCDST_BYTE_CONTEXT); LDST_SRCDST_BYTE_CONTEXT);
...@@ -121,15 +127,19 @@ void cnstr_shdsc_axcbc(u32 * const desc, struct alginfo *adata, u32 state, ...@@ -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 | append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_LAST1 |
FIFOLD_TYPE_MSG | FIFOLDST_VLF); 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 | append_seq_store(desc, digestsize, LDST_CLASS_1_CCB |
LDST_SRCDST_BYTE_CONTEXT); LDST_SRCDST_BYTE_CONTEXT);
if (state == OP_ALG_AS_INIT) if (is_xcbc_aes(adata->algtype) && state == OP_ALG_AS_INIT)
/* Save K1 */ /* Save K1 */
append_fifo_store(desc, key_dma, adata->keylen, append_fifo_store(desc, key_dma, adata->keylen,
LDST_CLASS_1_CCB | FIFOST_TYPE_KEY_KEK); 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_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("FSL CAAM ahash descriptors support"); MODULE_DESCRIPTION("FSL CAAM ahash descriptors support");
......
...@@ -15,9 +15,15 @@ ...@@ -15,9 +15,15 @@
#define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ) #define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ)
#define DESC_AHASH_DIGEST_LEN (DESC_AHASH_BASE + 4 * 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, void cnstr_shdsc_ahash(u32 * const desc, struct alginfo *adata, u32 state,
int digestsize, int ctx_len, bool import_ctx, int era); 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); int digestsize, int ctx_len, dma_addr_t key_dma);
#endif /* _CAAMHASH_DESC_H_ */ #endif /* _CAAMHASH_DESC_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment