~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/s390/crypto/hmac_s390.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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  */
 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 
 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 
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 
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 
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 
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 
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 
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 
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 
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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php