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, ¶m, in, inlen); 148 149 memcpy(digest, ¶m, 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.