120a884f5SGreg 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 46*674f368aSEric Biggers if (keylen != GHASH_BLOCK_SIZE) 47df1309ceSGerald Schaefer return -EINVAL; 48df1309ceSGerald Schaefer 49df1309ceSGerald Schaefer memcpy(ctx->key, key, GHASH_BLOCK_SIZE); 50df1309ceSGerald Schaefer 51df1309ceSGerald Schaefer return 0; 52df1309ceSGerald Schaefer } 53df1309ceSGerald Schaefer 54df1309ceSGerald Schaefer static int ghash_update(struct shash_desc *desc, 55df1309ceSGerald Schaefer const u8 *src, unsigned int srclen) 56df1309ceSGerald Schaefer { 57df1309ceSGerald Schaefer struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 58df1309ceSGerald Schaefer unsigned int n; 59df1309ceSGerald Schaefer u8 *buf = dctx->buffer; 60df1309ceSGerald Schaefer 61df1309ceSGerald Schaefer if (dctx->bytes) { 62df1309ceSGerald Schaefer u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); 63df1309ceSGerald Schaefer 64df1309ceSGerald Schaefer n = min(srclen, dctx->bytes); 65df1309ceSGerald Schaefer dctx->bytes -= n; 66df1309ceSGerald Schaefer srclen -= n; 67df1309ceSGerald Schaefer 68df1309ceSGerald Schaefer memcpy(pos, src, n); 69df1309ceSGerald Schaefer src += n; 70df1309ceSGerald Schaefer 71df1309ceSGerald Schaefer if (!dctx->bytes) { 720177db01SMartin Schwidefsky cpacf_kimd(CPACF_KIMD_GHASH, dctx, buf, 73df1309ceSGerald Schaefer GHASH_BLOCK_SIZE); 74df1309ceSGerald Schaefer } 75df1309ceSGerald Schaefer } 76df1309ceSGerald Schaefer 77df1309ceSGerald Schaefer n = srclen & ~(GHASH_BLOCK_SIZE - 1); 78df1309ceSGerald Schaefer if (n) { 790177db01SMartin Schwidefsky cpacf_kimd(CPACF_KIMD_GHASH, dctx, src, n); 80df1309ceSGerald Schaefer src += n; 81df1309ceSGerald Schaefer srclen -= n; 82df1309ceSGerald Schaefer } 83df1309ceSGerald Schaefer 84df1309ceSGerald Schaefer if (srclen) { 85df1309ceSGerald Schaefer dctx->bytes = GHASH_BLOCK_SIZE - srclen; 86df1309ceSGerald Schaefer memcpy(buf, src, srclen); 87df1309ceSGerald Schaefer } 88df1309ceSGerald Schaefer 89df1309ceSGerald Schaefer return 0; 90df1309ceSGerald Schaefer } 91df1309ceSGerald Schaefer 92a1cae34eSHarald Freudenberger static int ghash_flush(struct ghash_desc_ctx *dctx) 93df1309ceSGerald Schaefer { 94df1309ceSGerald Schaefer u8 *buf = dctx->buffer; 95df1309ceSGerald Schaefer 96df1309ceSGerald Schaefer if (dctx->bytes) { 97df1309ceSGerald Schaefer u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); 98df1309ceSGerald Schaefer 99df1309ceSGerald Schaefer memset(pos, 0, dctx->bytes); 1000177db01SMartin Schwidefsky cpacf_kimd(CPACF_KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE); 101df1309ceSGerald Schaefer dctx->bytes = 0; 102a1cae34eSHarald Freudenberger } 103a1cae34eSHarald Freudenberger 10436eb2caaSJan Glauber return 0; 105df1309ceSGerald Schaefer } 106df1309ceSGerald Schaefer 107df1309ceSGerald Schaefer static int ghash_final(struct shash_desc *desc, u8 *dst) 108df1309ceSGerald Schaefer { 109df1309ceSGerald Schaefer struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 11036eb2caaSJan Glauber int ret; 111df1309ceSGerald Schaefer 112a1cae34eSHarald Freudenberger ret = ghash_flush(dctx); 11336eb2caaSJan Glauber if (!ret) 114a1cae34eSHarald Freudenberger memcpy(dst, dctx->icv, GHASH_BLOCK_SIZE); 11536eb2caaSJan Glauber return ret; 116df1309ceSGerald Schaefer } 117df1309ceSGerald Schaefer 118df1309ceSGerald Schaefer static struct shash_alg ghash_alg = { 119df1309ceSGerald Schaefer .digestsize = GHASH_DIGEST_SIZE, 120df1309ceSGerald Schaefer .init = ghash_init, 121df1309ceSGerald Schaefer .update = ghash_update, 122df1309ceSGerald Schaefer .final = ghash_final, 123df1309ceSGerald Schaefer .setkey = ghash_setkey, 124df1309ceSGerald Schaefer .descsize = sizeof(struct ghash_desc_ctx), 125df1309ceSGerald Schaefer .base = { 126df1309ceSGerald Schaefer .cra_name = "ghash", 127df1309ceSGerald Schaefer .cra_driver_name = "ghash-s390", 128c7d4d259SMartin Schwidefsky .cra_priority = 300, 129df1309ceSGerald Schaefer .cra_blocksize = GHASH_BLOCK_SIZE, 130df1309ceSGerald Schaefer .cra_ctxsize = sizeof(struct ghash_ctx), 131df1309ceSGerald Schaefer .cra_module = THIS_MODULE, 132df1309ceSGerald Schaefer }, 133df1309ceSGerald Schaefer }; 134df1309ceSGerald Schaefer 135df1309ceSGerald Schaefer static int __init ghash_mod_init(void) 136df1309ceSGerald Schaefer { 13769c0e360SMartin Schwidefsky if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_GHASH)) 1381c0908fcSDavid Hildenbrand return -ENODEV; 139df1309ceSGerald Schaefer 140df1309ceSGerald Schaefer return crypto_register_shash(&ghash_alg); 141df1309ceSGerald Schaefer } 142df1309ceSGerald Schaefer 143df1309ceSGerald Schaefer static void __exit ghash_mod_exit(void) 144df1309ceSGerald Schaefer { 145df1309ceSGerald Schaefer crypto_unregister_shash(&ghash_alg); 146df1309ceSGerald Schaefer } 147df1309ceSGerald Schaefer 148d05377c1SHendrik Brueckner module_cpu_feature_match(MSA, ghash_mod_init); 149df1309ceSGerald Schaefer module_exit(ghash_mod_exit); 150df1309ceSGerald Schaefer 1515d26a105SKees Cook MODULE_ALIAS_CRYPTO("ghash"); 152df1309ceSGerald Schaefer 153df1309ceSGerald Schaefer MODULE_LICENSE("GPL"); 1548dfa20fcSEric Biggers MODULE_DESCRIPTION("GHASH hash function, s390 implementation"); 155