162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Cryptographic API.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * s390 generic implementation of the SHA Secure Hash Algorithms.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright IBM Corp. 2007
862306a36Sopenharmony_ci * Author(s): Jan Glauber (jang@de.ibm.com)
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <asm/cpacf.h>
1462306a36Sopenharmony_ci#include "sha.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciint s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len)
1762306a36Sopenharmony_ci{
1862306a36Sopenharmony_ci	struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
1962306a36Sopenharmony_ci	unsigned int bsize = crypto_shash_blocksize(desc->tfm);
2062306a36Sopenharmony_ci	unsigned int index, n;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	/* how much is already in the buffer? */
2362306a36Sopenharmony_ci	index = ctx->count % bsize;
2462306a36Sopenharmony_ci	ctx->count += len;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	if ((index + len) < bsize)
2762306a36Sopenharmony_ci		goto store;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	/* process one stored block */
3062306a36Sopenharmony_ci	if (index) {
3162306a36Sopenharmony_ci		memcpy(ctx->buf + index, data, bsize - index);
3262306a36Sopenharmony_ci		cpacf_kimd(ctx->func, ctx->state, ctx->buf, bsize);
3362306a36Sopenharmony_ci		data += bsize - index;
3462306a36Sopenharmony_ci		len -= bsize - index;
3562306a36Sopenharmony_ci		index = 0;
3662306a36Sopenharmony_ci	}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/* process as many blocks as possible */
3962306a36Sopenharmony_ci	if (len >= bsize) {
4062306a36Sopenharmony_ci		n = (len / bsize) * bsize;
4162306a36Sopenharmony_ci		cpacf_kimd(ctx->func, ctx->state, data, n);
4262306a36Sopenharmony_ci		data += n;
4362306a36Sopenharmony_ci		len -= n;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_cistore:
4662306a36Sopenharmony_ci	if (len)
4762306a36Sopenharmony_ci		memcpy(ctx->buf + index , data, len);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	return 0;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(s390_sha_update);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int s390_crypto_shash_parmsize(int func)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	switch (func) {
5662306a36Sopenharmony_ci	case CPACF_KLMD_SHA_1:
5762306a36Sopenharmony_ci		return 20;
5862306a36Sopenharmony_ci	case CPACF_KLMD_SHA_256:
5962306a36Sopenharmony_ci		return 32;
6062306a36Sopenharmony_ci	case CPACF_KLMD_SHA_512:
6162306a36Sopenharmony_ci		return 64;
6262306a36Sopenharmony_ci	case CPACF_KLMD_SHA3_224:
6362306a36Sopenharmony_ci	case CPACF_KLMD_SHA3_256:
6462306a36Sopenharmony_ci	case CPACF_KLMD_SHA3_384:
6562306a36Sopenharmony_ci	case CPACF_KLMD_SHA3_512:
6662306a36Sopenharmony_ci		return 200;
6762306a36Sopenharmony_ci	default:
6862306a36Sopenharmony_ci		return -EINVAL;
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ciint s390_sha_final(struct shash_desc *desc, u8 *out)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	struct s390_sha_ctx *ctx = shash_desc_ctx(desc);
7562306a36Sopenharmony_ci	unsigned int bsize = crypto_shash_blocksize(desc->tfm);
7662306a36Sopenharmony_ci	u64 bits;
7762306a36Sopenharmony_ci	unsigned int n;
7862306a36Sopenharmony_ci	int mbl_offset;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	n = ctx->count % bsize;
8162306a36Sopenharmony_ci	bits = ctx->count * 8;
8262306a36Sopenharmony_ci	mbl_offset = s390_crypto_shash_parmsize(ctx->func);
8362306a36Sopenharmony_ci	if (mbl_offset < 0)
8462306a36Sopenharmony_ci		return -EINVAL;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	mbl_offset = mbl_offset / sizeof(u32);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* set total msg bit length (mbl) in CPACF parmblock */
8962306a36Sopenharmony_ci	switch (ctx->func) {
9062306a36Sopenharmony_ci	case CPACF_KLMD_SHA_1:
9162306a36Sopenharmony_ci	case CPACF_KLMD_SHA_256:
9262306a36Sopenharmony_ci		memcpy(ctx->state + mbl_offset, &bits, sizeof(bits));
9362306a36Sopenharmony_ci		break;
9462306a36Sopenharmony_ci	case CPACF_KLMD_SHA_512:
9562306a36Sopenharmony_ci		/*
9662306a36Sopenharmony_ci		 * the SHA512 parmblock has a 128-bit mbl field, clear
9762306a36Sopenharmony_ci		 * high-order u64 field, copy bits to low-order u64 field
9862306a36Sopenharmony_ci		 */
9962306a36Sopenharmony_ci		memset(ctx->state + mbl_offset, 0x00, sizeof(bits));
10062306a36Sopenharmony_ci		mbl_offset += sizeof(u64) / sizeof(u32);
10162306a36Sopenharmony_ci		memcpy(ctx->state + mbl_offset, &bits, sizeof(bits));
10262306a36Sopenharmony_ci		break;
10362306a36Sopenharmony_ci	case CPACF_KLMD_SHA3_224:
10462306a36Sopenharmony_ci	case CPACF_KLMD_SHA3_256:
10562306a36Sopenharmony_ci	case CPACF_KLMD_SHA3_384:
10662306a36Sopenharmony_ci	case CPACF_KLMD_SHA3_512:
10762306a36Sopenharmony_ci		break;
10862306a36Sopenharmony_ci	default:
10962306a36Sopenharmony_ci		return -EINVAL;
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	cpacf_klmd(ctx->func, ctx->state, ctx->buf, n);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* copy digest to out */
11562306a36Sopenharmony_ci	memcpy(out, ctx->state, crypto_shash_digestsize(desc->tfm));
11662306a36Sopenharmony_ci	/* wipe context */
11762306a36Sopenharmony_ci	memset(ctx, 0, sizeof *ctx);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(s390_sha_final);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
12462306a36Sopenharmony_ciMODULE_DESCRIPTION("s390 SHA cipher common functions");
125