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 <crypto/internal/hash.h> 12 #include <linux/module.h> 13 #include <linux/cpufeature.h> 14 #include <asm/cpacf.h> 15 16 #define GHASH_BLOCK_SIZE 16 17 #define GHASH_DIGEST_SIZE 16 18 19 struct ghash_ctx { 20 u8 key[GHASH_BLOCK_SIZE]; 21 }; 22 23 struct ghash_desc_ctx { 24 u8 icv[GHASH_BLOCK_SIZE]; 25 u8 key[GHASH_BLOCK_SIZE]; 26 u8 buffer[GHASH_BLOCK_SIZE]; 27 u32 bytes; 28 }; 29 30 static int ghash_init(struct shash_desc *desc) 31 { 32 struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 33 struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); 34 35 memset(dctx, 0, sizeof(*dctx)); 36 memcpy(dctx->key, ctx->key, GHASH_BLOCK_SIZE); 37 38 return 0; 39 } 40 41 static int ghash_setkey(struct crypto_shash *tfm, 42 const u8 *key, unsigned int keylen) 43 { 44 struct ghash_ctx *ctx = crypto_shash_ctx(tfm); 45 46 if (keylen != GHASH_BLOCK_SIZE) 47 return -EINVAL; 48 49 memcpy(ctx->key, key, GHASH_BLOCK_SIZE); 50 51 return 0; 52 } 53 54 static int ghash_update(struct shash_desc *desc, 55 const u8 *src, unsigned int srclen) 56 { 57 struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 58 unsigned int n; 59 u8 *buf = dctx->buffer; 60 61 if (dctx->bytes) { 62 u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); 63 64 n = min(srclen, dctx->bytes); 65 dctx->bytes -= n; 66 srclen -= n; 67 68 memcpy(pos, src, n); 69 src += n; 70 71 if (!dctx->bytes) { 72 cpacf_kimd(CPACF_KIMD_GHASH, dctx, buf, 73 GHASH_BLOCK_SIZE); 74 } 75 } 76 77 n = srclen & ~(GHASH_BLOCK_SIZE - 1); 78 if (n) { 79 cpacf_kimd(CPACF_KIMD_GHASH, dctx, src, n); 80 src += n; 81 srclen -= n; 82 } 83 84 if (srclen) { 85 dctx->bytes = GHASH_BLOCK_SIZE - srclen; 86 memcpy(buf, src, srclen); 87 } 88 89 return 0; 90 } 91 92 static int ghash_flush(struct ghash_desc_ctx *dctx) 93 { 94 u8 *buf = dctx->buffer; 95 96 if (dctx->bytes) { 97 u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); 98 99 memset(pos, 0, dctx->bytes); 100 cpacf_kimd(CPACF_KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE); 101 dctx->bytes = 0; 102 } 103 104 return 0; 105 } 106 107 static int ghash_final(struct shash_desc *desc, u8 *dst) 108 { 109 struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 110 int ret; 111 112 ret = ghash_flush(dctx); 113 if (!ret) 114 memcpy(dst, dctx->icv, GHASH_BLOCK_SIZE); 115 return ret; 116 } 117 118 static struct shash_alg ghash_alg = { 119 .digestsize = GHASH_DIGEST_SIZE, 120 .init = ghash_init, 121 .update = ghash_update, 122 .final = ghash_final, 123 .setkey = ghash_setkey, 124 .descsize = sizeof(struct ghash_desc_ctx), 125 .base = { 126 .cra_name = "ghash", 127 .cra_driver_name = "ghash-s390", 128 .cra_priority = 300, 129 .cra_blocksize = GHASH_BLOCK_SIZE, 130 .cra_ctxsize = sizeof(struct ghash_ctx), 131 .cra_module = THIS_MODULE, 132 }, 133 }; 134 135 static int __init ghash_mod_init(void) 136 { 137 if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_GHASH)) 138 return -ENODEV; 139 140 return crypto_register_shash(&ghash_alg); 141 } 142 143 static void __exit ghash_mod_exit(void) 144 { 145 crypto_unregister_shash(&ghash_alg); 146 } 147 148 module_cpu_feature_match(S390_CPU_FEATURE_MSA, ghash_mod_init); 149 module_exit(ghash_mod_exit); 150 151 MODULE_ALIAS_CRYPTO("ghash"); 152 153 MODULE_LICENSE("GPL"); 154 MODULE_DESCRIPTION("GHASH hash function, s390 implementation"); 155
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.