1df1309ceSGerald Schaefer /* 2df1309ceSGerald Schaefer * Cryptographic API. 3df1309ceSGerald Schaefer * 4df1309ceSGerald Schaefer * s390 implementation of the GHASH algorithm for GCM (Galois/Counter Mode). 5df1309ceSGerald Schaefer * 6df1309ceSGerald Schaefer * Copyright IBM Corp. 2011 7df1309ceSGerald Schaefer * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com> 8df1309ceSGerald Schaefer */ 9df1309ceSGerald Schaefer 10df1309ceSGerald Schaefer #include <crypto/internal/hash.h> 11df1309ceSGerald Schaefer #include <linux/module.h> 12*d05377c1SHendrik Brueckner #include <linux/cpufeature.h> 13df1309ceSGerald Schaefer 14df1309ceSGerald Schaefer #include "crypt_s390.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 int ret; 63df1309ceSGerald Schaefer 64df1309ceSGerald Schaefer if (dctx->bytes) { 65df1309ceSGerald Schaefer u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); 66df1309ceSGerald Schaefer 67df1309ceSGerald Schaefer n = min(srclen, dctx->bytes); 68df1309ceSGerald Schaefer dctx->bytes -= n; 69df1309ceSGerald Schaefer srclen -= n; 70df1309ceSGerald Schaefer 71df1309ceSGerald Schaefer memcpy(pos, src, n); 72df1309ceSGerald Schaefer src += n; 73df1309ceSGerald Schaefer 74df1309ceSGerald Schaefer if (!dctx->bytes) { 75a1cae34eSHarald Freudenberger ret = crypt_s390_kimd(KIMD_GHASH, dctx, buf, 76df1309ceSGerald Schaefer GHASH_BLOCK_SIZE); 7736eb2caaSJan Glauber if (ret != GHASH_BLOCK_SIZE) 7836eb2caaSJan Glauber return -EIO; 79df1309ceSGerald Schaefer } 80df1309ceSGerald Schaefer } 81df1309ceSGerald Schaefer 82df1309ceSGerald Schaefer n = srclen & ~(GHASH_BLOCK_SIZE - 1); 83df1309ceSGerald Schaefer if (n) { 84a1cae34eSHarald Freudenberger ret = crypt_s390_kimd(KIMD_GHASH, dctx, src, n); 8536eb2caaSJan Glauber if (ret != n) 8636eb2caaSJan Glauber return -EIO; 87df1309ceSGerald Schaefer src += n; 88df1309ceSGerald Schaefer srclen -= n; 89df1309ceSGerald Schaefer } 90df1309ceSGerald Schaefer 91df1309ceSGerald Schaefer if (srclen) { 92df1309ceSGerald Schaefer dctx->bytes = GHASH_BLOCK_SIZE - srclen; 93df1309ceSGerald Schaefer memcpy(buf, src, srclen); 94df1309ceSGerald Schaefer } 95df1309ceSGerald Schaefer 96df1309ceSGerald Schaefer return 0; 97df1309ceSGerald Schaefer } 98df1309ceSGerald Schaefer 99a1cae34eSHarald Freudenberger static int ghash_flush(struct ghash_desc_ctx *dctx) 100df1309ceSGerald Schaefer { 101df1309ceSGerald Schaefer u8 *buf = dctx->buffer; 102df1309ceSGerald Schaefer int ret; 103df1309ceSGerald Schaefer 104df1309ceSGerald Schaefer if (dctx->bytes) { 105df1309ceSGerald Schaefer u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); 106df1309ceSGerald Schaefer 107df1309ceSGerald Schaefer memset(pos, 0, dctx->bytes); 108df1309ceSGerald Schaefer 109a1cae34eSHarald Freudenberger ret = crypt_s390_kimd(KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE); 11036eb2caaSJan Glauber if (ret != GHASH_BLOCK_SIZE) 11136eb2caaSJan Glauber return -EIO; 112df1309ceSGerald Schaefer 113df1309ceSGerald Schaefer dctx->bytes = 0; 114a1cae34eSHarald Freudenberger } 115a1cae34eSHarald Freudenberger 11636eb2caaSJan Glauber return 0; 117df1309ceSGerald Schaefer } 118df1309ceSGerald Schaefer 119df1309ceSGerald Schaefer static int ghash_final(struct shash_desc *desc, u8 *dst) 120df1309ceSGerald Schaefer { 121df1309ceSGerald Schaefer struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 12236eb2caaSJan Glauber int ret; 123df1309ceSGerald Schaefer 124a1cae34eSHarald Freudenberger ret = ghash_flush(dctx); 12536eb2caaSJan Glauber if (!ret) 126a1cae34eSHarald Freudenberger memcpy(dst, dctx->icv, GHASH_BLOCK_SIZE); 12736eb2caaSJan Glauber return ret; 128df1309ceSGerald Schaefer } 129df1309ceSGerald Schaefer 130df1309ceSGerald Schaefer static struct shash_alg ghash_alg = { 131df1309ceSGerald Schaefer .digestsize = GHASH_DIGEST_SIZE, 132df1309ceSGerald Schaefer .init = ghash_init, 133df1309ceSGerald Schaefer .update = ghash_update, 134df1309ceSGerald Schaefer .final = ghash_final, 135df1309ceSGerald Schaefer .setkey = ghash_setkey, 136df1309ceSGerald Schaefer .descsize = sizeof(struct ghash_desc_ctx), 137df1309ceSGerald Schaefer .base = { 138df1309ceSGerald Schaefer .cra_name = "ghash", 139df1309ceSGerald Schaefer .cra_driver_name = "ghash-s390", 140df1309ceSGerald Schaefer .cra_priority = CRYPT_S390_PRIORITY, 141df1309ceSGerald Schaefer .cra_flags = CRYPTO_ALG_TYPE_SHASH, 142df1309ceSGerald Schaefer .cra_blocksize = GHASH_BLOCK_SIZE, 143df1309ceSGerald Schaefer .cra_ctxsize = sizeof(struct ghash_ctx), 144df1309ceSGerald Schaefer .cra_module = THIS_MODULE, 145df1309ceSGerald Schaefer }, 146df1309ceSGerald Schaefer }; 147df1309ceSGerald Schaefer 148df1309ceSGerald Schaefer static int __init ghash_mod_init(void) 149df1309ceSGerald Schaefer { 150df1309ceSGerald Schaefer if (!crypt_s390_func_available(KIMD_GHASH, 151df1309ceSGerald Schaefer CRYPT_S390_MSA | CRYPT_S390_MSA4)) 152df1309ceSGerald Schaefer return -EOPNOTSUPP; 153df1309ceSGerald Schaefer 154df1309ceSGerald Schaefer return crypto_register_shash(&ghash_alg); 155df1309ceSGerald Schaefer } 156df1309ceSGerald Schaefer 157df1309ceSGerald Schaefer static void __exit ghash_mod_exit(void) 158df1309ceSGerald Schaefer { 159df1309ceSGerald Schaefer crypto_unregister_shash(&ghash_alg); 160df1309ceSGerald Schaefer } 161df1309ceSGerald Schaefer 162*d05377c1SHendrik Brueckner module_cpu_feature_match(MSA, ghash_mod_init); 163df1309ceSGerald Schaefer module_exit(ghash_mod_exit); 164df1309ceSGerald Schaefer 1655d26a105SKees Cook MODULE_ALIAS_CRYPTO("ghash"); 166df1309ceSGerald Schaefer 167df1309ceSGerald Schaefer MODULE_LICENSE("GPL"); 168df1309ceSGerald Schaefer MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation"); 169