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