Support sm3 ce stream mode for sm3-normal and hmac-sm3. And add some parameter check for these mode.
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com --- drv/isa_ce_sm3.c | 270 +++++++++++++++++++++++------- {include/drv => drv}/isa_ce_sm3.h | 40 +++-- 2 files changed, 235 insertions(+), 75 deletions(-) rename {include/drv => drv}/isa_ce_sm3.h (64%)
diff --git a/drv/isa_ce_sm3.c b/drv/isa_ce_sm3.c index d562730..5442b3c 100644 --- a/drv/isa_ce_sm3.c +++ b/drv/isa_ce_sm3.c @@ -61,13 +61,11 @@ static void __attribute__((destructor)) sm3_ce_remove(void)
static int sm3_ce_get_usage(void *param) { - return 0; + return WD_SUCCESS; }
static inline void sm3_ce_init(struct sm3_ce_ctx *sctx) { - memset(sctx, 0, sizeof(*sctx)); - sctx->word_reg[0] = SM3_IVA; sctx->word_reg[1] = SM3_IVB; sctx->word_reg[2] = SM3_IVC; @@ -78,12 +76,35 @@ static inline void sm3_ce_init(struct sm3_ce_ctx *sctx) sctx->word_reg[7] = SM3_IVH; }
+static void trans_output_result(__u8 *out_digest, __u32 *word_reg) +{ + size_t i; + + for (i = 0; i < SM3_STATE_WORDS; i++) + PUTU32_TO_U8(out_digest + i * WORD_TO_CHAR_OFFSET, word_reg[i]); +} + +static void sm3_ce_init_ex(struct sm3_ce_ctx *sctx, __u8 *iv, __u16 iv_bytes) +{ + size_t i; + + if (iv_bytes != SM3_DIGEST_SIZE) { + WD_ERR("invalid iv size: %u\n", iv_bytes); + return; + } + + for (i = 0; i < SM3_STATE_WORDS; i++) + PUTU8_TO_U32(sctx->word_reg[i], iv + i * WORD_TO_CHAR_OFFSET); +} + static void sm3_ce_update(struct sm3_ce_ctx *sctx, const void *data, size_t data_len, sm3_ce_block_fn *block_fn) { size_t remain_data_len, blk_num;
/* Get the data num that need compute currently */ + sctx->num &= (SM3_BLOCK_SIZE - 1); + if (sctx->num) { remain_data_len = SM3_BLOCK_SIZE - sctx->num; /* If data_len does not enough a block size, then leave it to final */ @@ -114,15 +135,16 @@ static void sm3_ce_update(struct sm3_ce_ctx *sctx, const void *data, memcpy(sctx->block, data, data_len); }
-static void sm3_ce_final(struct sm3_ce_ctx *sctx, __u8 *md, - sm3_ce_block_fn *block_fn) +static int sm3_ce_final(struct sm3_ce_ctx *sctx, __u8 *md, + sm3_ce_block_fn *block_fn) { - int i; + size_t i, offset1, offset2; + __u64 nh, nl;
- /* Add padding */ - sctx->block[sctx->num] = 0x80; + sctx->num &= (SM3_BLOCK_SIZE - 1); + sctx->block[sctx->num] = SM3_PADDING_BYTE;
- if (sctx->num <= SM3_BLOCK_SIZE - 9) { + if (sctx->num <= SM3_BLOCK_SIZE - BIT_TO_BLOCK_OFFSET) { memset(sctx->block + sctx->num + 1, 0, SM3_BLOCK_SIZE - sctx->num - 9); } else { memset(sctx->block + sctx->num + 1, 0, SM3_BLOCK_SIZE - sctx->num - 1); @@ -131,75 +153,189 @@ static void sm3_ce_final(struct sm3_ce_ctx *sctx, __u8 *md, }
/* - * Put the length of the message in bits into the last two words, to get - * the length in bits we need to multiply by 8 (or left shift 3). This left shifted - * value is put in the last word. Any bits shifted off the left edge need to be put in the - * penultimate word, we can work out which bits by shifting right the length by 29 bits. + * Put the length of the message in bits into the last + * 64-bits (penultimate two words). */ - PUTU32(sctx->block + 56, sctx->nblocks >> 23); - PUTU32(sctx->block + 60, (sctx->nblocks << 9) + (sctx->num << 3)); + offset2 = SM3_BLOCK_SIZE - WORD_TO_CHAR_OFFSET * 2; + offset1 = SM3_BLOCK_SIZE - WORD_TO_CHAR_OFFSET; + nh = sctx->nblocks >> NH_OFFSET; + nl = (sctx->nblocks << BIT_TO_BLOCK_OFFSET) + (sctx->num << BIT_TO_BYTE_OFFSET); + PUTU32_TO_U8(sctx->block + offset2 , nh); + PUTU32_TO_U8(sctx->block + offset1, nl);
block_fn(sctx->word_reg, sctx->block, 1); - for (i = 0; i < 8; i++) - PUTU32(md + i * 4, sctx->word_reg[i]); + for (i = 0; i < SM3_STATE_WORDS; i++) + PUTU32_TO_U8(md + i * WORD_TO_CHAR_OFFSET, sctx->word_reg[i]); + + return WD_SUCCESS; }
-static int do_sm3_ce(const __u8 *data, size_t len, __u8 *out_digest) +static int do_sm3_ce(struct wd_digest_msg *msg, __u8 *out_digest) { + enum hash_block_type block_type; struct sm3_ce_ctx sctx = {0}; - int ret = 0; + size_t data_len, iv_len; + __u8 *data, *iv;
- sm3_ce_init(&sctx); - sm3_ce_update(&sctx, data, len, sm3_ce_block_compress); - sm3_ce_final(&sctx, out_digest, sm3_ce_block_compress); - - if (!out_digest) { - WD_ERR("failed to get digest!\n"); - ret = -WD_EINVAL; + block_type = get_hash_block_type(msg); + data_len = msg->in_bytes; + data = msg->in; + iv_len = SM3_DIGEST_SIZE; + /* Use last output as the iv in current cycle */ + iv = msg->out; + + switch(block_type) { + case HASH_SINGLE_BLOCK: + sm3_ce_init(&sctx); + sm3_ce_update(&sctx, data, data_len, sm3_ce_block_compress); + sm3_ce_final(&sctx, out_digest, sm3_ce_block_compress); + break; + case HASH_FRIST_BLOCK: + sm3_ce_init(&sctx); + sm3_ce_update(&sctx, data, data_len, sm3_ce_block_compress); + trans_output_result(out_digest, sctx.word_reg); + break; + case HASH_MIDDLE_BLOCK: + sm3_ce_init_ex(&sctx, iv, iv_len); + sm3_ce_update(&sctx, data, data_len, sm3_ce_block_compress); + /* Transform the middle result without final padding */ + trans_output_result(out_digest, sctx.word_reg); + break; + case HASH_END_BLOCK: + sm3_ce_init_ex(&sctx, iv, iv_len); + sm3_ce_update(&sctx, data, data_len, sm3_ce_block_compress); + /* Put the whole message length in last 64-bits */ + sctx.nblocks = msg->long_data_len / SM3_BLOCK_SIZE; + sm3_ce_final(&sctx, out_digest, sm3_ce_block_compress); + break; + default: + WD_ERR("Invalid block type!\n"); + return -WD_EINVAL; }
+ if (msg->out_bytes < SM3_DIGEST_SIZE) + memcpy(msg->out, out_digest, msg->out_bytes); + else + memcpy(msg->out, out_digest, SM3_DIGEST_SIZE); + memset(&sctx, 0, sizeof(struct sm3_ce_ctx)); - return ret; + + return WD_SUCCESS; }
-static int do_hmac_sm3_ce(const __u8 *key, size_t key_len, - const __u8 *data, size_t data_len, - __u8 *out_hmac) +static void sm3_hmac_key_padding(struct hmac_sm3_ctx *hctx, + const uint8_t *key, size_t key_len) { - unsigned char key_buf[HMAC_BLOCK_SIZE] = {0}; - unsigned char ipad[HMAC_BLOCK_SIZE] = {0}; - unsigned char opad[HMAC_BLOCK_SIZE] = {0}; - unsigned char hash[SM3_DIGEST_SIZE] = {0}; - struct sm3_ce_ctx sctx = {0}; - unsigned int i; + size_t i;
- if (!key_len) { - WD_ERR("invalid hmac key_len!\n"); - return -WD_EINVAL; + if (key_len <= SM3_BLOCK_SIZE) { + memcpy(hctx->key, key, key_len); + memset(hctx->key + key_len, 0, SM3_BLOCK_SIZE - key_len); + } else { + sm3_ce_init(&hctx->sctx); + sm3_ce_update(&hctx->sctx, key, key_len, sm3_ce_block_compress); + sm3_ce_final(&hctx->sctx, hctx->key, sm3_ce_block_compress); + /* Pad key to SM3_BLOCK_SIZE after hash */ + memset(hctx->key + SM3_DIGEST_SIZE, 0, + SM3_BLOCK_SIZE - SM3_DIGEST_SIZE); + } + + for (i = 0; i < SM3_BLOCK_SIZE; i++) { + hctx->key[i] ^= IPAD_DATA; + } +} + +static void sm3_ce_hmac_init(struct hmac_sm3_ctx *hctx, const uint8_t *key, size_t key_len) +{ + sm3_hmac_key_padding(hctx, key, key_len); + + /* Ipadded key is the first block to hash in first cycle */ + sm3_ce_init(&hctx->sctx); + sm3_ce_update(&hctx->sctx, hctx->key, SM3_BLOCK_SIZE, sm3_ce_block_compress); +} + +static void sm3_ce_hmac_update(struct hmac_sm3_ctx *hctx, const __u8 *data, size_t data_len) +{ + sm3_ce_update(&hctx->sctx, data, data_len, sm3_ce_block_compress); +} + +static void sm3_ce_hmac_final(struct hmac_sm3_ctx *hctx, __u8 *out_hmac) +{ + __u8 digest[SM3_DIGEST_SIZE] = {0}; + size_t i; + + for (i = 0; i < SM3_BLOCK_SIZE; i++) { + hctx->key[i] ^= (IPAD_DATA ^ OPAD_DATA); }
- if (key_len > HMAC_BLOCK_SIZE) { - do_sm3_ce(key, key_len, key_buf); - key_len = SM3_DIGEST_SIZE; - key = key_buf; + /* Compute the last data from update process */ + sm3_ce_final(&hctx->sctx, digest, sm3_ce_block_compress); + + /* Opadded key is the first block to hash in second cycle */ + memset(&hctx->sctx, 0, sizeof(struct sm3_ce_ctx)); + sm3_ce_init(&hctx->sctx); + sm3_ce_update(&hctx->sctx, hctx->key, SM3_BLOCK_SIZE, sm3_ce_block_compress); + + /* Compute the the first cycle result */ + sm3_ce_update(&hctx->sctx, digest, SM3_DIGEST_SIZE, sm3_ce_block_compress); + sm3_ce_final(&hctx->sctx, out_hmac, sm3_ce_block_compress); +} + +static int do_hmac_sm3_ce(struct wd_digest_msg *msg, __u8 *out_hmac) +{ + size_t data_len, key_len, iv_len; + enum hash_block_type block_type; + struct hmac_sm3_ctx hctx = {0}; + __u8 *data, *key, *iv; + + data_len = msg->in_bytes; + data = msg->in; + key = msg->key; + key_len = msg->key_bytes; + iv_len = SM3_DIGEST_SIZE; + /* Use last output as the iv in current cycle */ + iv = msg->out; + + if (!key_len) { + WD_ERR("invalid hmac key_len is 0!\n"); + return -WD_EINVAL; }
- memset(ipad, 0x36, HMAC_BLOCK_SIZE); - memset(opad, 0x5c, HMAC_BLOCK_SIZE); - for (i = 0; i < key_len; i++) { - ipad[i] ^= key[i]; - opad[i] ^= key[i]; + block_type = get_hash_block_type(msg); + switch(block_type) { + case HASH_SINGLE_BLOCK: + sm3_ce_hmac_init(&hctx, key, key_len); + sm3_ce_hmac_update(&hctx, data, data_len); + sm3_ce_hmac_final(&hctx, out_hmac); + break; + case HASH_FRIST_BLOCK: + sm3_ce_hmac_init(&hctx, key, key_len); + sm3_ce_hmac_update(&hctx, data, data_len); + trans_output_result(out_hmac, hctx.sctx.word_reg); + break; + case HASH_MIDDLE_BLOCK: + sm3_ce_init_ex(&(hctx.sctx), iv, iv_len); + sm3_ce_hmac_update(&hctx, data, data_len); + trans_output_result(out_hmac, hctx.sctx.word_reg); + break; + case HASH_END_BLOCK: + sm3_hmac_key_padding(&hctx, key, key_len); + sm3_ce_init_ex(&(hctx.sctx), iv, iv_len); + sm3_ce_hmac_update(&hctx, data, data_len); + hctx.sctx.nblocks = msg->long_data_len / SM3_BLOCK_SIZE + KEY_BLOCK_NUM; + sm3_ce_hmac_final(&hctx, out_hmac); + break; + default: + WD_ERR("Invalid block type!\n"); + break; }
- sm3_ce_init(&sctx); - sm3_ce_update(&sctx, ipad, HMAC_BLOCK_SIZE, sm3_ce_block_compress); - sm3_ce_update(&sctx, data, data_len, sm3_ce_block_compress); - sm3_ce_final(&sctx, hash, sm3_ce_block_compress); + if (msg->out_bytes < SM3_DIGEST_SIZE) + memcpy(msg->out, out_hmac, msg->out_bytes); + else + memcpy(msg->out, out_hmac, SM3_DIGEST_SIZE);
- sm3_ce_init(&sctx); - sm3_ce_update(&sctx, opad, HMAC_BLOCK_SIZE, sm3_ce_block_compress); - sm3_ce_update(&sctx, hash, SM3_DIGEST_SIZE, sm3_ce_block_compress); - sm3_ce_final(&sctx, out_hmac, sm3_ce_block_compress); + memset(&hctx, 0, sizeof(struct hmac_sm3_ctx));
return WD_SUCCESS; } @@ -207,8 +343,7 @@ static int do_hmac_sm3_ce(const __u8 *key, size_t key_len, static int sm3_ce_drv_send(handle_t ctx, void *digest_msg) { struct wd_digest_msg *msg = (struct wd_digest_msg *)digest_msg; - __u8 *out_digest, *data, *key; - size_t data_size, key_len; + __u8 digest[SM3_DIGEST_SIZE] = {0}; int ret;
if (!msg) { @@ -216,16 +351,15 @@ static int sm3_ce_drv_send(handle_t ctx, void *digest_msg) return -WD_EINVAL; }
- data_size = msg->in_bytes; - out_digest = msg->out; - data = msg->in; - key = msg->key; - key_len = msg->key_bytes; + if (msg->data_fmt == WD_SGL_BUF) { + WD_ERR("invalid: SM3 CE driver do not support sgl data format!\n"); + return -WD_EINVAL; + }
if (msg->mode == WD_DIGEST_NORMAL) { - ret = do_sm3_ce(data, data_size, out_digest); + ret = do_sm3_ce(msg, digest); } else if (msg->mode == WD_DIGEST_HMAC) { - ret = do_hmac_sm3_ce(key, key_len, data, data_size, out_digest); + ret = do_hmac_sm3_ce(msg, digest); } else { WD_ERR("invalid digest mode!\n"); ret = -WD_EINVAL; @@ -241,6 +375,12 @@ static int sm3_ce_drv_recv(handle_t ctx, void *digest_msg)
static int sm3_ce_drv_init(void *conf, void *priv) { + struct wd_ctx_config_internal *config = conf; + struct sm3_ce_drv_ctx *sctx = priv; + + config->epoll_en = false; + memcpy(&sctx->config, config, sizeof(struct wd_ctx_config_internal)); + return WD_SUCCESS; }
diff --git a/include/drv/isa_ce_sm3.h b/drv/isa_ce_sm3.h similarity index 64% rename from include/drv/isa_ce_sm3.h rename to drv/isa_ce_sm3.h index d08c72f..7f68e6e 100644 --- a/include/drv/isa_ce_sm3.h +++ b/drv/isa_ce_sm3.h @@ -3,16 +3,24 @@ #ifndef __ISA_CE_SM3_H #define __ISA_CE_SM3_H
-#include "../wd_alg_common.h" +#include "wd_alg_common.h"
#ifdef __cplusplus extern "C" { #endif
-#define SM3_DIGEST_SIZE 32 -#define SM3_BLOCK_SIZE 64 -#define SM3_STATE_WORDS 8 -#define HMAC_BLOCK_SIZE 64 +#define SM3_DIGEST_SIZE 32 +#define SM3_BLOCK_SIZE 64 +#define SM3_STATE_WORDS 8 +#define HMAC_BLOCK_SIZE 64 +#define WORD_TO_CHAR_OFFSET 4 +#define SM3_PADDING_BYTE 0x80 +#define NH_OFFSET 23 +#define BIT_TO_BLOCK_OFFSET 9 +#define BIT_TO_BYTE_OFFSET 3 +#define IPAD_DATA 0x36 +#define OPAD_DATA 0x5c +#define KEY_BLOCK_NUM 1
#define SM3_IVA 0x7380166f #define SM3_IVB 0x4914b2b9 @@ -23,11 +31,17 @@ extern "C" { #define SM3_IVG 0xe38dee4d #define SM3_IVH 0xb0fb0e4e
-#define PUTU32(p, V) \ - ((p)[0] = (uint8_t)((V) >> 24), \ - (p)[1] = (uint8_t)((V) >> 16), \ - (p)[2] = (uint8_t)((V) >> 8), \ - (p)[3] = (uint8_t)(V)) +#define PUTU32_TO_U8(dst, src) \ + ((dst)[0] = (__u8)((src) >> 24), \ + (dst)[1] = (__u8)((src) >> 16), \ + (dst)[2] = (__u8)((src) >> 8), \ + (dst)[3] = (__u8)(src)) + +#define PUTU8_TO_U32(dst, src) \ + ((dst) = (((__u32)(src)[0]) << 24) + \ + (((__u32)(src)[1]) << 16) + \ + (((__u32)(src)[2]) << 8) + \ + ((__u32)(src)[3]))
struct sm3_ce_ctx { /* @@ -52,6 +66,12 @@ struct sm3_ce_ctx { size_t num; };
+struct hmac_sm3_ctx { + struct sm3_ce_ctx sctx; + /* Save user key */ + __u8 key[SM3_BLOCK_SIZE]; +}; + struct sm3_ce_drv_ctx { struct wd_ctx_config_internal config; };