File Index
Files and directories
Sign in
FILE

hmac_s390.c

File preview with syntax highlighting.

linux-6.19.14/arch/s390/crypto/hmac_s390.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright IBM Corp. 2024
  4 *
  5 * s390 specific HMAC support.
  6 */
  7
  8#define pr_fmt(fmt) "hmac_s390: " fmt
  9
 10#include <asm/cpacf.h>
 11#include <crypto/internal/hash.h>
 12#include <crypto/hmac.h>
 13#include <crypto/sha2.h>
 14#include <linux/cpufeature.h>
 15#include <linux/errno.h>
 16#include <linux/kernel.h>
 17#include <linux/module.h>
 18#include <linux/string.h>
 19
 20/*
 21 * KMAC param block layout for sha2 function codes:
 22 * The layout of the param block for the KMAC instruction depends on the
 23 * blocksize of the used hashing sha2-algorithm function codes. The param block
 24 * contains the hash chaining value (cv), the input message bit-length (imbl)
 25 * and the hmac-secret (key). To prevent code duplication, the sizes of all
 26 * these are calculated based on the blocksize.
 27 *
 28 * param-block:
 29 * +-------+
 30 * | cv    |
 31 * +-------+
 32 * | imbl  |
 33 * +-------+
 34 * | key   |
 35 * +-------+
 36 *
 37 * sizes:
 38 * part | sh2-alg | calculation | size | type
 39 * -----+---------+-------------+------+--------
 40 * cv	| 224/256 | blocksize/2 |   32 |  u64[8]
 41 *	| 384/512 |		|   64 | u128[8]
 42 * imbl | 224/256 | blocksize/8 |    8 |     u64
 43 *	| 384/512 |		|   16 |    u128
 44 * key	| 224/256 | blocksize	|   64 |  u8[64]
 45 *	| 384/512 |		|  128 | u8[128]
 46 */
 47
 48#define MAX_DIGEST_SIZE		SHA512_DIGEST_SIZE
 49#define MAX_IMBL_SIZE		sizeof(u128)
 50#define MAX_BLOCK_SIZE		SHA512_BLOCK_SIZE
 51
 52#define SHA2_CV_SIZE(bs)	((bs) >> 1)
 53#define SHA2_IMBL_SIZE(bs)	((bs) >> 3)
 54
 55#define SHA2_IMBL_OFFSET(bs)	(SHA2_CV_SIZE(bs))
 56#define SHA2_KEY_OFFSET(bs)	(SHA2_CV_SIZE(bs) + SHA2_IMBL_SIZE(bs))
 57
 58struct s390_hmac_ctx {
 59	u8 key[MAX_BLOCK_SIZE];
 60};
 61
 62union s390_kmac_gr0 {
 63	unsigned long reg;
 64	struct {
 65		unsigned long		: 48;
 66		unsigned long ikp	:  1;
 67		unsigned long iimp	:  1;
 68		unsigned long ccup	:  1;
 69		unsigned long		:  6;
 70		unsigned long fc	:  7;
 71	};
 72};
 73
 74struct s390_kmac_sha2_ctx {
 75	u8 param[MAX_DIGEST_SIZE + MAX_IMBL_SIZE + MAX_BLOCK_SIZE];
 76	union s390_kmac_gr0 gr0;
 77	u64 buflen[2];
 78};
 79
 80/*
 81 * kmac_sha2_set_imbl - sets the input message bit-length based on the blocksize
 82 */
 83static inline void kmac_sha2_set_imbl(u8 *param, u64 buflen_lo,
 84				      u64 buflen_hi, unsigned int blocksize)
 85{
 86	u8 *imbl = param + SHA2_IMBL_OFFSET(blocksize);
 87
 88	switch (blocksize) {
 89	case SHA256_BLOCK_SIZE:
 90		*(u64 *)imbl = buflen_lo * BITS_PER_BYTE;
 91		break;
 92	case SHA512_BLOCK_SIZE:
 93		*(u128 *)imbl = (((u128)buflen_hi << 64) + buflen_lo) << 3;
 94		break;
 95	default:
 96		break;
 97	}
 98}
 99
100static int hash_data(const u8 *in, unsigned int inlen,
101		     u8 *digest, unsigned int digestsize, bool final)
102{
103	unsigned long func;
104	union {
105		struct sha256_paramblock {
106			u32 h[8];
107			u64 mbl;
108		} sha256;
109		struct sha512_paramblock {
110			u64 h[8];
111			u128 mbl;
112		} sha512;
113	} __packed param;
114
115#define PARAM_INIT(x, y, z)		   \
116	param.sha##x.h[0] = SHA##y ## _H0; \
117	param.sha##x.h[1] = SHA##y ## _H1; \
118	param.sha##x.h[2] = SHA##y ## _H2; \
119	param.sha##x.h[3] = SHA##y ## _H3; \
120	param.sha##x.h[4] = SHA##y ## _H4; \
121	param.sha##x.h[5] = SHA##y ## _H5; \
122	param.sha##x.h[6] = SHA##y ## _H6; \
123	param.sha##x.h[7] = SHA##y ## _H7; \
124	param.sha##x.mbl = (z)
125
126	switch (digestsize) {
127	case SHA224_DIGEST_SIZE:
128		func = final ? CPACF_KLMD_SHA_256 : CPACF_KIMD_SHA_256;
129		PARAM_INIT(256, 224, inlen * 8);
130		if (!final)
131			digestsize = SHA256_DIGEST_SIZE;
132		break;
133	case SHA256_DIGEST_SIZE:
134		func = final ? CPACF_KLMD_SHA_256 : CPACF_KIMD_SHA_256;
135		PARAM_INIT(256, 256, inlen * 8);
136		break;
137	case SHA384_DIGEST_SIZE:
138		func = final ? CPACF_KLMD_SHA_512 : CPACF_KIMD_SHA_512;
139		PARAM_INIT(512, 384, inlen * 8);
140		if (!final)
141			digestsize = SHA512_DIGEST_SIZE;
142		break;
143	case SHA512_DIGEST_SIZE:
144		func = final ? CPACF_KLMD_SHA_512 : CPACF_KIMD_SHA_512;
145		PARAM_INIT(512, 512, inlen * 8);
146		break;
147	default:
148		return -EINVAL;
149	}
150
151#undef PARAM_INIT
152
153	cpacf_klmd(func, &param, in, inlen);
154
155	memcpy(digest, &param, digestsize);
156
157	return 0;
158}
159
160static int hash_key(const u8 *in, unsigned int inlen,
161		    u8 *digest, unsigned int digestsize)
162{
163	return hash_data(in, inlen, digest, digestsize, true);
164}
165
166static int s390_hmac_sha2_setkey(struct crypto_shash *tfm,
167				 const u8 *key, unsigned int keylen)
168{
169	struct s390_hmac_ctx *tfm_ctx = crypto_shash_ctx(tfm);
170	unsigned int ds = crypto_shash_digestsize(tfm);
171	unsigned int bs = crypto_shash_blocksize(tfm);
172
173	memset(tfm_ctx, 0, sizeof(*tfm_ctx));
174
175	if (keylen > bs)
176		return hash_key(key, keylen, tfm_ctx->key, ds);
177
178	memcpy(tfm_ctx->key, key, keylen);
179	return 0;
180}
181
182static int s390_hmac_sha2_init(struct shash_desc *desc)
183{
184	struct s390_hmac_ctx *tfm_ctx = crypto_shash_ctx(desc->tfm);
185	struct s390_kmac_sha2_ctx *ctx = shash_desc_ctx(desc);
186	unsigned int bs = crypto_shash_blocksize(desc->tfm);
187
188	memcpy(ctx->param + SHA2_KEY_OFFSET(bs),
189	       tfm_ctx->key, bs);
190
191	ctx->buflen[0] = 0;
192	ctx->buflen[1] = 0;
193	ctx->gr0.reg = 0;
194	switch (crypto_shash_digestsize(desc->tfm)) {
195	case SHA224_DIGEST_SIZE:
196		ctx->gr0.fc = CPACF_KMAC_HMAC_SHA_224;
197		break;
198	case SHA256_DIGEST_SIZE:
199		ctx->gr0.fc = CPACF_KMAC_HMAC_SHA_256;
200		break;
201	case SHA384_DIGEST_SIZE:
202		ctx->gr0.fc = CPACF_KMAC_HMAC_SHA_384;
203		break;
204	case SHA512_DIGEST_SIZE:
205		ctx->gr0.fc = CPACF_KMAC_HMAC_SHA_512;
206		break;
207	default:
208		return -EINVAL;
209	}
210
211	return 0;
212}
213
214static int s390_hmac_sha2_update(struct shash_desc *desc,
215				 const u8 *data, unsigned int len)
216{
217	struct s390_kmac_sha2_ctx *ctx = shash_desc_ctx(desc);
218	unsigned int bs = crypto_shash_blocksize(desc->tfm);
219	unsigned int n = round_down(len, bs);
220
221	ctx->buflen[0] += n;
222	if (ctx->buflen[0] < n)
223		ctx->buflen[1]++;
224
225	/* process as many blocks as possible */
226	ctx->gr0.iimp = 1;
227	_cpacf_kmac(&ctx->gr0.reg, ctx->param, data, n);
228	return len - n;
229}
230
231static int s390_hmac_sha2_finup(struct shash_desc *desc, const u8 *src,
232				unsigned int len, u8 *out)
233{
234	struct s390_kmac_sha2_ctx *ctx = shash_desc_ctx(desc);
235	unsigned int bs = crypto_shash_blocksize(desc->tfm);
236
237	ctx->buflen[0] += len;
238	if (ctx->buflen[0] < len)
239		ctx->buflen[1]++;
240
241	ctx->gr0.iimp = 0;
242	kmac_sha2_set_imbl(ctx->param, ctx->buflen[0], ctx->buflen[1], bs);
243	_cpacf_kmac(&ctx->gr0.reg, ctx->param, src, len);
244	memcpy(out, ctx->param, crypto_shash_digestsize(desc->tfm));
245
246	return 0;
247}
248
249static int s390_hmac_sha2_digest(struct shash_desc *desc,
250				 const u8 *data, unsigned int len, u8 *out)
251{
252	struct s390_kmac_sha2_ctx *ctx = shash_desc_ctx(desc);
253	unsigned int ds = crypto_shash_digestsize(desc->tfm);
254	int rc;
255
256	rc = s390_hmac_sha2_init(desc);
257	if (rc)
258		return rc;
259
260	ctx->gr0.iimp = 0;
261	kmac_sha2_set_imbl(ctx->param, len, 0,
262			   crypto_shash_blocksize(desc->tfm));
263	_cpacf_kmac(&ctx->gr0.reg, ctx->param, data, len);
264	memcpy(out, ctx->param, ds);
265
266	return 0;
267}
268
269static int s390_hmac_export_zero(struct shash_desc *desc, void *out)
270{
271	struct crypto_shash *tfm = desc->tfm;
272	u8 ipad[SHA512_BLOCK_SIZE];
273	struct s390_hmac_ctx *ctx;
274	unsigned int bs;
275	int err, i;
276
277	ctx = crypto_shash_ctx(tfm);
278	bs = crypto_shash_blocksize(tfm);
279	for (i = 0; i < bs; i++)
280		ipad[i] = ctx->key[i] ^ HMAC_IPAD_VALUE;
281
282	err = hash_data(ipad, bs, out, crypto_shash_digestsize(tfm), false);
283	memzero_explicit(ipad, sizeof(ipad));
284	return err;
285}
286
287static int s390_hmac_export(struct shash_desc *desc, void *out)
288{
289	struct s390_kmac_sha2_ctx *ctx = shash_desc_ctx(desc);
290	unsigned int bs = crypto_shash_blocksize(desc->tfm);
291	unsigned int ds = bs / 2;
292	u64 lo = ctx->buflen[0];
293	union {
294		u8 *u8;
295		u64 *u64;
296	} p = { .u8 = out };
297	int err = 0;
298
299	if (!ctx->gr0.ikp)
300		err = s390_hmac_export_zero(desc, out);
301	else
302		memcpy(p.u8, ctx->param, ds);
303	p.u8 += ds;
304	lo += bs;
305	put_unaligned(lo, p.u64++);
306	if (ds == SHA512_DIGEST_SIZE)
307		put_unaligned(ctx->buflen[1] + (lo < bs), p.u64);
308	return err;
309}
310
311static int s390_hmac_import(struct shash_desc *desc, const void *in)
312{
313	struct s390_kmac_sha2_ctx *ctx = shash_desc_ctx(desc);
314	unsigned int bs = crypto_shash_blocksize(desc->tfm);
315	unsigned int ds = bs / 2;
316	union {
317		const u8 *u8;
318		const u64 *u64;
319	} p = { .u8 = in };
320	u64 lo;
321	int err;
322
323	err = s390_hmac_sha2_init(desc);
324	memcpy(ctx->param, p.u8, ds);
325	p.u8 += ds;
326	lo = get_unaligned(p.u64++);
327	ctx->buflen[0] = lo - bs;
328	if (ds == SHA512_DIGEST_SIZE)
329		ctx->buflen[1] = get_unaligned(p.u64) - (lo < bs);
330	if (ctx->buflen[0] | ctx->buflen[1])
331		ctx->gr0.ikp = 1;
332	return err;
333}
334
335#define S390_HMAC_SHA2_ALG(x, ss) {					\
336	.fc = CPACF_KMAC_HMAC_SHA_##x,					\
337	.alg = {							\
338		.init = s390_hmac_sha2_init,				\
339		.update = s390_hmac_sha2_update,			\
340		.finup = s390_hmac_sha2_finup,				\
341		.digest = s390_hmac_sha2_digest,			\
342		.setkey = s390_hmac_sha2_setkey,			\
343		.export = s390_hmac_export,				\
344		.import = s390_hmac_import,				\
345		.descsize = sizeof(struct s390_kmac_sha2_ctx),		\
346		.halg = {						\
347			.statesize = ss,				\
348			.digestsize = SHA##x##_DIGEST_SIZE,		\
349			.base = {					\
350				.cra_name = "hmac(sha" #x ")",		\
351				.cra_driver_name = "hmac_s390_sha" #x,	\
352				.cra_blocksize = SHA##x##_BLOCK_SIZE,	\
353				.cra_priority = 400,			\
354				.cra_flags = CRYPTO_AHASH_ALG_BLOCK_ONLY | \
355					     CRYPTO_AHASH_ALG_FINUP_MAX, \
356				.cra_ctxsize = sizeof(struct s390_hmac_ctx), \
357				.cra_module = THIS_MODULE,		\
358			},						\
359		},							\
360	},								\
361}
362
363static struct s390_hmac_alg {
364	bool registered;
365	unsigned int fc;
366	struct shash_alg alg;
367} s390_hmac_algs[] = {
368	S390_HMAC_SHA2_ALG(224, sizeof(struct crypto_sha256_state)),
369	S390_HMAC_SHA2_ALG(256, sizeof(struct crypto_sha256_state)),
370	S390_HMAC_SHA2_ALG(384, SHA512_STATE_SIZE),
371	S390_HMAC_SHA2_ALG(512, SHA512_STATE_SIZE),
372};
373
374static __always_inline void _s390_hmac_algs_unregister(void)
375{
376	struct s390_hmac_alg *hmac;
377	int i;
378
379	for (i = ARRAY_SIZE(s390_hmac_algs) - 1; i >= 0; i--) {
380		hmac = &s390_hmac_algs[i];
381		if (!hmac->registered)
382			continue;
383		crypto_unregister_shash(&hmac->alg);
384	}
385}
386
387static int __init hmac_s390_init(void)
388{
389	struct s390_hmac_alg *hmac;
390	int i, rc = -ENODEV;
391
392	if (!cpacf_query_func(CPACF_KLMD, CPACF_KLMD_SHA_256))
393		return -ENODEV;
394	if (!cpacf_query_func(CPACF_KLMD, CPACF_KLMD_SHA_512))
395		return -ENODEV;
396
397	for (i = 0; i < ARRAY_SIZE(s390_hmac_algs); i++) {
398		hmac = &s390_hmac_algs[i];
399		if (!cpacf_query_func(CPACF_KMAC, hmac->fc))
400			continue;
401
402		rc = crypto_register_shash(&hmac->alg);
403		if (rc) {
404			pr_err("unable to register %s\n",
405			       hmac->alg.halg.base.cra_name);
406			goto out;
407		}
408		hmac->registered = true;
409		pr_debug("registered %s\n", hmac->alg.halg.base.cra_name);
410	}
411	return rc;
412out:
413	_s390_hmac_algs_unregister();
414	return rc;
415}
416
417static void __exit hmac_s390_exit(void)
418{
419	_s390_hmac_algs_unregister();
420}
421
422module_cpu_feature_match(S390_CPU_FEATURE_MSA, hmac_s390_init);
423module_exit(hmac_s390_exit);
424
425MODULE_DESCRIPTION("S390 HMAC driver");
426MODULE_LICENSE("GPL");
~/ Read-only file preview.