1*20a884f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2df1309ceSGerald Schaefer /* 3df1309ceSGerald Schaefer * Cryptographic API. 4df1309ceSGerald Schaefer * 5df1309ceSGerald Schaefer * s390 implementation of the GHASH algorithm for GCM (Galois/Counter Mode). 6df1309ceSGerald Schaefer * 7df1309ceSGerald Schaefer * Copyright IBM Corp. 2011 8df1309ceSGerald Schaefer * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com> 9df1309ceSGerald Schaefer */ 10df1309ceSGerald Schaefer 11df1309ceSGerald Schaefer #include <crypto/internal/hash.h> 12df1309ceSGerald Schaefer #include <linux/module.h> 13d05377c1SHendrik Brueckner #include <linux/cpufeature.h> 14c7d4d259SMartin Schwidefsky #include <asm/cpacf.h> 15df1309ceSGerald Schaefer 16df1309ceSGerald Schaefer #define GHASH_BLOCK_SIZE 16 17df1309ceSGerald Schaefer #define GHASH_DIGEST_SIZE 16 18df1309ceSGerald Schaefer 19df1309ceSGerald Schaefer struct ghash_ctx { 20a1cae34eSHarald Freudenberger u8 key[GHASH_BLOCK_SIZE]; 21df1309ceSGerald Schaefer }; 22df1309ceSGerald Schaefer 23df1309ceSGerald Schaefer struct ghash_desc_ctx { 24a1cae34eSHarald Freudenberger u8 icv[GHASH_BLOCK_SIZE]; 25a1cae34eSHarald Freudenberger u8 key[GHASH_BLOCK_SIZE]; 26df1309ceSGerald Schaefer u8 buffer[GHASH_BLOCK_SIZE]; 27df1309ceSGerald Schaefer u32 bytes; 28df1309ceSGerald Schaefer }; 29df1309ceSGerald Schaefer 30df1309ceSGerald Schaefer static int ghash_init(struct shash_desc *desc) 31df1309ceSGerald Schaefer { 32df1309ceSGerald Schaefer struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 33a1cae34eSHarald Freudenberger struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); 34df1309ceSGerald Schaefer 35df1309ceSGerald Schaefer memset(dctx, 0, sizeof(*dctx)); 36a1cae34eSHarald Freudenberger memcpy(dctx->key, ctx->key, GHASH_BLOCK_SIZE); 37df1309ceSGerald Schaefer 38df1309ceSGerald Schaefer return 0; 39df1309ceSGerald Schaefer } 40df1309ceSGerald Schaefer 41df1309ceSGerald Schaefer static int ghash_setkey(struct crypto_shash *tfm, 42df1309ceSGerald Schaefer const u8 *key, unsigned int keylen) 43df1309ceSGerald Schaefer { 44df1309ceSGerald Schaefer struct ghash_ctx *ctx = crypto_shash_ctx(tfm); 45df1309ceSGerald Schaefer 46df1309ceSGerald Schaefer if (keylen != GHASH_BLOCK_SIZE) { 47df1309ceSGerald Schaefer crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); 48df1309ceSGerald Schaefer return -EINVAL; 49df1309ceSGerald Schaefer } 50df1309ceSGerald Schaefer 51df1309ceSGerald Schaefer memcpy(ctx->key, key, GHASH_BLOCK_SIZE); 52df1309ceSGerald Schaefer 53df1309ceSGerald Schaefer return 0; 54df1309ceSGerald Schaefer } 55df1309ceSGerald Schaefer 56df1309ceSGerald Schaefer static int ghash_update(struct shash_desc *desc, 57df1309ceSGerald Schaefer const u8 *src, unsigned int srclen) 58df1309ceSGerald Schaefer { 59df1309ceSGerald Schaefer struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 60df1309ceSGerald Schaefer unsigned int n; 61df1309ceSGerald Schaefer u8 *buf = dctx->buffer; 62df1309ceSGerald Schaefer 63df1309ceSGerald Schaefer if (dctx->bytes) { 64df1309ceSGerald Schaefer u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); 65df1309ceSGerald Schaefer 66df1309ceSGerald Schaefer n = min(srclen, dctx->bytes); 67df1309ceSGerald Schaefer dctx->bytes -= n; 68df1309ceSGerald Schaefer srclen -= n; 69df1309ceSGerald Schaefer 70df1309ceSGerald Schaefer memcpy(pos, src, n); 71df1309ceSGerald Schaefer src += n; 72df1309ceSGerald Schaefer 73df1309ceSGerald Schaefer if (!dctx->bytes) { 740177db01SMartin Schwidefsky cpacf_kimd(CPACF_KIMD_GHASH, dctx, buf, 75df1309ceSGerald Schaefer GHASH_BLOCK_SIZE); 76df1309ceSGerald Schaefer } 77df1309ceSGerald Schaefer } 78df1309ceSGerald Schaefer 79df1309ceSGerald Schaefer n = srclen & ~(GHASH_BLOCK_SIZE - 1); 80df1309ceSGerald Schaefer if (n) { 810177db01SMartin Schwidefsky cpacf_kimd(CPACF_KIMD_GHASH, dctx, src, n); 82df1309ceSGerald Schaefer src += n; 83df1309ceSGerald Schaefer srclen -= n; 84df1309ceSGerald Schaefer } 85df1309ceSGerald Schaefer 86df1309ceSGerald Schaefer if (srclen) { 87df1309ceSGerald Schaefer dctx->bytes = GHASH_BLOCK_SIZE - srclen; 88df1309ceSGerald Schaefer memcpy(buf, src, srclen); 89df1309ceSGerald Schaefer } 90df1309ceSGerald Schaefer 91df1309ceSGerald Schaefer return 0; 92df1309ceSGerald Schaefer } 93df1309ceSGerald Schaefer 94a1cae34eSHarald Freudenberger static int ghash_flush(struct ghash_desc_ctx *dctx) 95df1309ceSGerald Schaefer { 96df1309ceSGerald Schaefer u8 *buf = dctx->buffer; 97df1309ceSGerald Schaefer 98df1309ceSGerald Schaefer if (dctx->bytes) { 99df1309ceSGerald Schaefer u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); 100df1309ceSGerald Schaefer 101df1309ceSGerald Schaefer memset(pos, 0, dctx->bytes); 1020177db01SMartin Schwidefsky cpacf_kimd(CPACF_KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE); 103df1309ceSGerald Schaefer dctx->bytes = 0; 104a1cae34eSHarald Freudenberger } 105a1cae34eSHarald Freudenberger 10636eb2caaSJan Glauber return 0; 107df1309ceSGerald Schaefer } 108df1309ceSGerald Schaefer 109df1309ceSGerald Schaefer static int ghash_final(struct shash_desc *desc, u8 *dst) 110df1309ceSGerald Schaefer { 111df1309ceSGerald Schaefer struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 11236eb2caaSJan Glauber int ret; 113df1309ceSGerald Schaefer 114a1cae34eSHarald Freudenberger ret = ghash_flush(dctx); 11536eb2caaSJan Glauber if (!ret) 116a1cae34eSHarald Freudenberger memcpy(dst, dctx->icv, GHASH_BLOCK_SIZE); 11736eb2caaSJan Glauber return ret; 118df1309ceSGerald Schaefer } 119df1309ceSGerald Schaefer 120df1309ceSGerald Schaefer static struct shash_alg ghash_alg = { 121df1309ceSGerald Schaefer .digestsize = GHASH_DIGEST_SIZE, 122df1309ceSGerald Schaefer .init = ghash_init, 123df1309ceSGerald Schaefer .update = ghash_update, 124df1309ceSGerald Schaefer .final = ghash_final, 125df1309ceSGerald Schaefer .setkey = ghash_setkey, 126df1309ceSGerald Schaefer .descsize = sizeof(struct ghash_desc_ctx), 127df1309ceSGerald Schaefer .base = { 128df1309ceSGerald Schaefer .cra_name = "ghash", 129df1309ceSGerald Schaefer .cra_driver_name = "ghash-s390", 130c7d4d259SMartin Schwidefsky .cra_priority = 300, 131df1309ceSGerald Schaefer .cra_flags = CRYPTO_ALG_TYPE_SHASH, 132df1309ceSGerald Schaefer .cra_blocksize = GHASH_BLOCK_SIZE, 133df1309ceSGerald Schaefer .cra_ctxsize = sizeof(struct ghash_ctx), 134df1309ceSGerald Schaefer .cra_module = THIS_MODULE, 135df1309ceSGerald Schaefer }, 136df1309ceSGerald Schaefer }; 137df1309ceSGerald Schaefer 138df1309ceSGerald Schaefer static int __init ghash_mod_init(void) 139df1309ceSGerald Schaefer { 14069c0e360SMartin Schwidefsky if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_GHASH)) 141df1309ceSGerald Schaefer return -EOPNOTSUPP; 142df1309ceSGerald Schaefer 143df1309ceSGerald Schaefer return crypto_register_shash(&ghash_alg); 144df1309ceSGerald Schaefer } 145df1309ceSGerald Schaefer 146df1309ceSGerald Schaefer static void __exit ghash_mod_exit(void) 147df1309ceSGerald Schaefer { 148df1309ceSGerald Schaefer crypto_unregister_shash(&ghash_alg); 149df1309ceSGerald Schaefer } 150df1309ceSGerald Schaefer 151d05377c1SHendrik Brueckner module_cpu_feature_match(MSA, ghash_mod_init); 152df1309ceSGerald Schaefer module_exit(ghash_mod_exit); 153df1309ceSGerald Schaefer 1545d26a105SKees Cook MODULE_ALIAS_CRYPTO("ghash"); 155df1309ceSGerald Schaefer 156df1309ceSGerald Schaefer MODULE_LICENSE("GPL"); 157df1309ceSGerald Schaefer MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation"); 158