162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * sm3_base.h - core logic for SM3 implementations 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017 ARM Limited or its affiliates. 662306a36Sopenharmony_ci * Written by Gilad Ben-Yossef <gilad@benyossef.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#ifndef _CRYPTO_SM3_BASE_H 1062306a36Sopenharmony_ci#define _CRYPTO_SM3_BASE_H 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1362306a36Sopenharmony_ci#include <crypto/sm3.h> 1462306a36Sopenharmony_ci#include <linux/crypto.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <asm/unaligned.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_citypedef void (sm3_block_fn)(struct sm3_state *sst, u8 const *src, int blocks); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic inline int sm3_base_init(struct shash_desc *desc) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct sm3_state *sctx = shash_desc_ctx(desc); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci sctx->state[0] = SM3_IVA; 2662306a36Sopenharmony_ci sctx->state[1] = SM3_IVB; 2762306a36Sopenharmony_ci sctx->state[2] = SM3_IVC; 2862306a36Sopenharmony_ci sctx->state[3] = SM3_IVD; 2962306a36Sopenharmony_ci sctx->state[4] = SM3_IVE; 3062306a36Sopenharmony_ci sctx->state[5] = SM3_IVF; 3162306a36Sopenharmony_ci sctx->state[6] = SM3_IVG; 3262306a36Sopenharmony_ci sctx->state[7] = SM3_IVH; 3362306a36Sopenharmony_ci sctx->count = 0; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return 0; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic inline int sm3_base_do_update(struct shash_desc *desc, 3962306a36Sopenharmony_ci const u8 *data, 4062306a36Sopenharmony_ci unsigned int len, 4162306a36Sopenharmony_ci sm3_block_fn *block_fn) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct sm3_state *sctx = shash_desc_ctx(desc); 4462306a36Sopenharmony_ci unsigned int partial = sctx->count % SM3_BLOCK_SIZE; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci sctx->count += len; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (unlikely((partial + len) >= SM3_BLOCK_SIZE)) { 4962306a36Sopenharmony_ci int blocks; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (partial) { 5262306a36Sopenharmony_ci int p = SM3_BLOCK_SIZE - partial; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci memcpy(sctx->buffer + partial, data, p); 5562306a36Sopenharmony_ci data += p; 5662306a36Sopenharmony_ci len -= p; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci block_fn(sctx, sctx->buffer, 1); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci blocks = len / SM3_BLOCK_SIZE; 6262306a36Sopenharmony_ci len %= SM3_BLOCK_SIZE; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (blocks) { 6562306a36Sopenharmony_ci block_fn(sctx, data, blocks); 6662306a36Sopenharmony_ci data += blocks * SM3_BLOCK_SIZE; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci partial = 0; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci if (len) 7162306a36Sopenharmony_ci memcpy(sctx->buffer + partial, data, len); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic inline int sm3_base_do_finalize(struct shash_desc *desc, 7762306a36Sopenharmony_ci sm3_block_fn *block_fn) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci const int bit_offset = SM3_BLOCK_SIZE - sizeof(__be64); 8062306a36Sopenharmony_ci struct sm3_state *sctx = shash_desc_ctx(desc); 8162306a36Sopenharmony_ci __be64 *bits = (__be64 *)(sctx->buffer + bit_offset); 8262306a36Sopenharmony_ci unsigned int partial = sctx->count % SM3_BLOCK_SIZE; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci sctx->buffer[partial++] = 0x80; 8562306a36Sopenharmony_ci if (partial > bit_offset) { 8662306a36Sopenharmony_ci memset(sctx->buffer + partial, 0x0, SM3_BLOCK_SIZE - partial); 8762306a36Sopenharmony_ci partial = 0; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci block_fn(sctx, sctx->buffer, 1); 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci memset(sctx->buffer + partial, 0x0, bit_offset - partial); 9362306a36Sopenharmony_ci *bits = cpu_to_be64(sctx->count << 3); 9462306a36Sopenharmony_ci block_fn(sctx, sctx->buffer, 1); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return 0; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic inline int sm3_base_finish(struct shash_desc *desc, u8 *out) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct sm3_state *sctx = shash_desc_ctx(desc); 10262306a36Sopenharmony_ci __be32 *digest = (__be32 *)out; 10362306a36Sopenharmony_ci int i; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci for (i = 0; i < SM3_DIGEST_SIZE / sizeof(__be32); i++) 10662306a36Sopenharmony_ci put_unaligned_be32(sctx->state[i], digest++); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci memzero_explicit(sctx, sizeof(*sctx)); 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#endif /* _CRYPTO_SM3_BASE_H */ 113