120a884f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
2604973f1SJan Glauber /*
3604973f1SJan Glauber * Cryptographic API.
4604973f1SJan Glauber *
5604973f1SJan Glauber * s390 generic implementation of the SHA Secure Hash Algorithms.
6604973f1SJan Glauber *
7604973f1SJan Glauber * Copyright IBM Corp. 2007
8604973f1SJan Glauber * Author(s): Jan Glauber (jang@de.ibm.com)
9604973f1SJan Glauber */
10604973f1SJan Glauber
11563f346dSHerbert Xu #include <crypto/internal/hash.h>
123a4c5d59SHeiko Carstens #include <linux/module.h>
13c7d4d259SMartin Schwidefsky #include <asm/cpacf.h>
14604973f1SJan Glauber #include "sha.h"
15604973f1SJan Glauber
s390_sha_update(struct shash_desc * desc,const u8 * data,unsigned int len)16563f346dSHerbert Xu int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len)
17604973f1SJan Glauber {
18563f346dSHerbert Xu struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
19563f346dSHerbert Xu unsigned int bsize = crypto_shash_blocksize(desc->tfm);
200177db01SMartin Schwidefsky unsigned int index, n;
21604973f1SJan Glauber
22604973f1SJan Glauber /* how much is already in the buffer? */
233c2eb6b7SJoerg Schmidbauer index = ctx->count % bsize;
24604973f1SJan Glauber ctx->count += len;
25604973f1SJan Glauber
26604973f1SJan Glauber if ((index + len) < bsize)
27604973f1SJan Glauber goto store;
28604973f1SJan Glauber
29604973f1SJan Glauber /* process one stored block */
30604973f1SJan Glauber if (index) {
31604973f1SJan Glauber memcpy(ctx->buf + index, data, bsize - index);
320177db01SMartin Schwidefsky cpacf_kimd(ctx->func, ctx->state, ctx->buf, bsize);
33604973f1SJan Glauber data += bsize - index;
34604973f1SJan Glauber len -= bsize - index;
359d20b571SHerbert Xu index = 0;
36604973f1SJan Glauber }
37604973f1SJan Glauber
38604973f1SJan Glauber /* process as many blocks as possible */
39604973f1SJan Glauber if (len >= bsize) {
403c2eb6b7SJoerg Schmidbauer n = (len / bsize) * bsize;
410177db01SMartin Schwidefsky cpacf_kimd(ctx->func, ctx->state, data, n);
420177db01SMartin Schwidefsky data += n;
430177db01SMartin Schwidefsky len -= n;
44604973f1SJan Glauber }
45604973f1SJan Glauber store:
46604973f1SJan Glauber if (len)
47604973f1SJan Glauber memcpy(ctx->buf + index , data, len);
48563f346dSHerbert Xu
49563f346dSHerbert Xu return 0;
50604973f1SJan Glauber }
51604973f1SJan Glauber EXPORT_SYMBOL_GPL(s390_sha_update);
52604973f1SJan Glauber
s390_crypto_shash_parmsize(int func)533c2eb6b7SJoerg Schmidbauer static int s390_crypto_shash_parmsize(int func)
543c2eb6b7SJoerg Schmidbauer {
553c2eb6b7SJoerg Schmidbauer switch (func) {
563c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA_1:
573c2eb6b7SJoerg Schmidbauer return 20;
583c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA_256:
593c2eb6b7SJoerg Schmidbauer return 32;
603c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA_512:
613c2eb6b7SJoerg Schmidbauer return 64;
623c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA3_224:
633c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA3_256:
643c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA3_384:
653c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA3_512:
663c2eb6b7SJoerg Schmidbauer return 200;
673c2eb6b7SJoerg Schmidbauer default:
683c2eb6b7SJoerg Schmidbauer return -EINVAL;
693c2eb6b7SJoerg Schmidbauer }
703c2eb6b7SJoerg Schmidbauer }
713c2eb6b7SJoerg Schmidbauer
s390_sha_final(struct shash_desc * desc,u8 * out)72563f346dSHerbert Xu int s390_sha_final(struct shash_desc *desc, u8 *out)
73604973f1SJan Glauber {
74563f346dSHerbert Xu struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
75563f346dSHerbert Xu unsigned int bsize = crypto_shash_blocksize(desc->tfm);
76604973f1SJan Glauber u64 bits;
77*0398d4abSYueHaibing unsigned int n;
78*0398d4abSYueHaibing int mbl_offset;
79604973f1SJan Glauber
803c2eb6b7SJoerg Schmidbauer n = ctx->count % bsize;
81604973f1SJan Glauber bits = ctx->count * 8;
82*0398d4abSYueHaibing mbl_offset = s390_crypto_shash_parmsize(ctx->func);
833c2eb6b7SJoerg Schmidbauer if (mbl_offset < 0)
843c2eb6b7SJoerg Schmidbauer return -EINVAL;
853c2eb6b7SJoerg Schmidbauer
86*0398d4abSYueHaibing mbl_offset = mbl_offset / sizeof(u32);
87*0398d4abSYueHaibing
883c2eb6b7SJoerg Schmidbauer /* set total msg bit length (mbl) in CPACF parmblock */
893c2eb6b7SJoerg Schmidbauer switch (ctx->func) {
903c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA_1:
913c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA_256:
923c2eb6b7SJoerg Schmidbauer memcpy(ctx->state + mbl_offset, &bits, sizeof(bits));
933c2eb6b7SJoerg Schmidbauer break;
943c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA_512:
953c2eb6b7SJoerg Schmidbauer /*
963c2eb6b7SJoerg Schmidbauer * the SHA512 parmblock has a 128-bit mbl field, clear
973c2eb6b7SJoerg Schmidbauer * high-order u64 field, copy bits to low-order u64 field
983c2eb6b7SJoerg Schmidbauer */
993c2eb6b7SJoerg Schmidbauer memset(ctx->state + mbl_offset, 0x00, sizeof(bits));
1003c2eb6b7SJoerg Schmidbauer mbl_offset += sizeof(u64) / sizeof(u32);
1013c2eb6b7SJoerg Schmidbauer memcpy(ctx->state + mbl_offset, &bits, sizeof(bits));
1023c2eb6b7SJoerg Schmidbauer break;
1033c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA3_224:
1043c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA3_256:
1053c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA3_384:
1063c2eb6b7SJoerg Schmidbauer case CPACF_KLMD_SHA3_512:
1073c2eb6b7SJoerg Schmidbauer break;
1083c2eb6b7SJoerg Schmidbauer default:
1093c2eb6b7SJoerg Schmidbauer return -EINVAL;
1103c2eb6b7SJoerg Schmidbauer }
1113c2eb6b7SJoerg Schmidbauer
1123c2eb6b7SJoerg Schmidbauer cpacf_klmd(ctx->func, ctx->state, ctx->buf, n);
113604973f1SJan Glauber
114604973f1SJan Glauber /* copy digest to out */
115563f346dSHerbert Xu memcpy(out, ctx->state, crypto_shash_digestsize(desc->tfm));
116604973f1SJan Glauber /* wipe context */
117604973f1SJan Glauber memset(ctx, 0, sizeof *ctx);
118563f346dSHerbert Xu
119563f346dSHerbert Xu return 0;
120604973f1SJan Glauber }
121604973f1SJan Glauber EXPORT_SYMBOL_GPL(s390_sha_final);
122604973f1SJan Glauber
123604973f1SJan Glauber MODULE_LICENSE("GPL");
124604973f1SJan Glauber MODULE_DESCRIPTION("s390 SHA cipher common functions");
125