/* SPDX-License-Identifier: GPL-2.0-only */ /* * sha512_base.h - core logic for SHA-512 implementations * * Copyright (C) 2015 Linaro Ltd */ #ifndef _CRYPTO_SHA512_BASE_H #define _CRYPTO_SHA512_BASE_H #include #include #include #include #include #include #include typedef void (sha512_block_fn)(struct sha512_state *sst, u8 const *src, int blocks); static inline int sha384_base_init(struct shash_desc *desc) { struct sha512_state *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA384_H0; sctx->state[1] = SHA384_H1; sctx->state[2] = SHA384_H2; sctx->state[3] = SHA384_H3; sctx->state[4] = SHA384_H4; sctx->state[5] = SHA384_H5; sctx->state[6] = SHA384_H6; sctx->state[7] = SHA384_H7; sctx->count[0] = sctx->count[1] = 0; return 0; } static inline int sha512_base_init(struct shash_desc *desc) { struct sha512_state *sctx = shash_desc_ctx(desc); sctx->state[0] = SHA512_H0; sctx->state[1] = SHA512_H1; sctx->state[2] = SHA512_H2; sctx->state[3] = SHA512_H3; sctx->state[4] = SHA512_H4; sctx->state[5] = SHA512_H5; sctx->state[6] = SHA512_H6; sctx->state[7] = SHA512_H7; sctx->count[0] = sctx->count[1] = 0; return 0; } static inline int sha512_base_do_update_blocks(struct shash_desc *desc, const u8 *data, unsigned int len, sha512_block_fn *block_fn) { unsigned int remain = len - round_down(len, SHA512_BLOCK_SIZE); struct sha512_state *sctx = shash_desc_ctx(desc); len -= remain; sctx->count[0] += len; if (sctx->count[0] < len) sctx->count[1]++; block_fn(sctx, data, len / SHA512_BLOCK_SIZE); return remain; } static inline int sha512_base_do_finup(struct shash_desc *desc, const u8 *src, unsigned int len, sha512_block_fn *block_fn) { unsigned int bit_offset = SHA512_BLOCK_SIZE / 8 - 2; struct sha512_state *sctx = shash_desc_ctx(desc); union { __be64 b64[SHA512_BLOCK_SIZE / 4]; u8 u8[SHA512_BLOCK_SIZE * 2]; } block = {}; if (len >= SHA512_BLOCK_SIZE) { int remain; remain = sha512_base_do_update_blocks(desc, src, len, block_fn); src += len - remain; len = remain; } if (len >= bit_offset * 8) bit_offset += SHA512_BLOCK_SIZE / 8; memcpy(&block, src, len); block.u8[len] = 0x80; sctx->count[0] += len; block.b64[bit_offset] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61); block.b64[bit_offset + 1] = cpu_to_be64(sctx->count[0] << 3); block_fn(sctx, block.u8, (bit_offset + 2) * 8 / SHA512_BLOCK_SIZE); memzero_explicit(&block, sizeof(block)); return 0; } static inline int sha512_base_finish(struct shash_desc *desc, u8 *out) { unsigned int digest_size = crypto_shash_digestsize(desc->tfm); struct sha512_state *sctx = shash_desc_ctx(desc); __be64 *digest = (__be64 *)out; int i; for (i = 0; digest_size > 0; i++, digest_size -= sizeof(__be64)) put_unaligned_be64(sctx->state[i], digest++); return 0; } void sha512_generic_block_fn(struct sha512_state *sst, u8 const *src, int blocks); #endif /* _CRYPTO_SHA512_BASE_H */