1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Cryptographic API.
4  *
5  * s390 implementation of the GHASH algorithm for GCM (Galois/Counter Mode).
6  *
7  * Copyright IBM Corp. 2011
8  * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
9  */
10 
11 #include <asm/cpacf.h>
12 #include <crypto/ghash.h>
13 #include <crypto/internal/hash.h>
14 #include <linux/cpufeature.h>
15 #include <linux/err.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/string.h>
19 
20 struct s390_ghash_ctx {
21 	u8 key[GHASH_BLOCK_SIZE];
22 };
23 
24 struct s390_ghash_desc_ctx {
25 	u8 icv[GHASH_BLOCK_SIZE];
26 	u8 key[GHASH_BLOCK_SIZE];
27 };
28 
29 static int ghash_init(struct shash_desc *desc)
30 {
31 	struct s390_ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
32 	struct s390_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
33 
34 	memset(dctx, 0, sizeof(*dctx));
35 	memcpy(dctx->key, ctx->key, GHASH_BLOCK_SIZE);
36 
37 	return 0;
38 }
39 
40 static int ghash_setkey(struct crypto_shash *tfm,
41 			const u8 *key, unsigned int keylen)
42 {
43 	struct s390_ghash_ctx *ctx = crypto_shash_ctx(tfm);
44 
45 	if (keylen != GHASH_BLOCK_SIZE)
46 		return -EINVAL;
47 
48 	memcpy(ctx->key, key, GHASH_BLOCK_SIZE);
49 
50 	return 0;
51 }
52 
53 static int ghash_update(struct shash_desc *desc,
54 			 const u8 *src, unsigned int srclen)
55 {
56 	struct s390_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
57 	unsigned int n;
58 
59 	n = srclen & ~(GHASH_BLOCK_SIZE - 1);
60 	cpacf_kimd(CPACF_KIMD_GHASH, dctx, src, n);
61 	return srclen - n;
62 }
63 
64 static void ghash_flush(struct s390_ghash_desc_ctx *dctx, const u8 *src,
65 			unsigned int len)
66 {
67 	if (len) {
68 		u8 buf[GHASH_BLOCK_SIZE] = {};
69 
70 		memcpy(buf, src, len);
71 		cpacf_kimd(CPACF_KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE);
72 		memzero_explicit(buf, sizeof(buf));
73 	}
74 }
75 
76 static int ghash_finup(struct shash_desc *desc, const u8 *src,
77 		       unsigned int len, u8 *dst)
78 {
79 	struct s390_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
80 
81 	ghash_flush(dctx, src, len);
82 	memcpy(dst, dctx->icv, GHASH_BLOCK_SIZE);
83 	return 0;
84 }
85 
86 static int ghash_export(struct shash_desc *desc, void *out)
87 {
88 	struct s390_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
89 
90 	memcpy(out, dctx->icv, GHASH_DIGEST_SIZE);
91 	return 0;
92 }
93 
94 static int ghash_import(struct shash_desc *desc, const void *in)
95 {
96 	struct s390_ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
97 	struct s390_ghash_desc_ctx *dctx = shash_desc_ctx(desc);
98 
99 	memcpy(dctx->icv, in, GHASH_DIGEST_SIZE);
100 	memcpy(dctx->key, ctx->key, GHASH_BLOCK_SIZE);
101 	return 0;
102 }
103 
104 static struct shash_alg ghash_alg = {
105 	.digestsize	= GHASH_DIGEST_SIZE,
106 	.init		= ghash_init,
107 	.update		= ghash_update,
108 	.finup		= ghash_finup,
109 	.setkey		= ghash_setkey,
110 	.export		= ghash_export,
111 	.import		= ghash_import,
112 	.statesize	= sizeof(struct ghash_desc_ctx),
113 	.descsize	= sizeof(struct s390_ghash_desc_ctx),
114 	.base		= {
115 		.cra_name		= "ghash",
116 		.cra_driver_name	= "ghash-s390",
117 		.cra_priority		= 300,
118 		.cra_flags		= CRYPTO_AHASH_ALG_BLOCK_ONLY,
119 		.cra_blocksize		= GHASH_BLOCK_SIZE,
120 		.cra_ctxsize		= sizeof(struct s390_ghash_ctx),
121 		.cra_module		= THIS_MODULE,
122 	},
123 };
124 
125 static int __init ghash_mod_init(void)
126 {
127 	if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_GHASH))
128 		return -ENODEV;
129 
130 	return crypto_register_shash(&ghash_alg);
131 }
132 
133 static void __exit ghash_mod_exit(void)
134 {
135 	crypto_unregister_shash(&ghash_alg);
136 }
137 
138 module_cpu_feature_match(S390_CPU_FEATURE_MSA, ghash_mod_init);
139 module_exit(ghash_mod_exit);
140 
141 MODULE_ALIAS_CRYPTO("ghash");
142 
143 MODULE_LICENSE("GPL");
144 MODULE_DESCRIPTION("GHASH hash function, s390 implementation");
145