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> 12df1309ceSGerald Schaefer 13df1309ceSGerald Schaefer #include "crypt_s390.h" 14df1309ceSGerald Schaefer 15df1309ceSGerald Schaefer #define GHASH_BLOCK_SIZE 16 16df1309ceSGerald Schaefer #define GHASH_DIGEST_SIZE 16 17df1309ceSGerald Schaefer 18df1309ceSGerald Schaefer struct ghash_ctx { 19*a1cae34eSHarald Freudenberger u8 key[GHASH_BLOCK_SIZE]; 20df1309ceSGerald Schaefer }; 21df1309ceSGerald Schaefer 22df1309ceSGerald Schaefer struct ghash_desc_ctx { 23*a1cae34eSHarald Freudenberger u8 icv[GHASH_BLOCK_SIZE]; 24*a1cae34eSHarald Freudenberger u8 key[GHASH_BLOCK_SIZE]; 25df1309ceSGerald Schaefer u8 buffer[GHASH_BLOCK_SIZE]; 26df1309ceSGerald Schaefer u32 bytes; 27df1309ceSGerald Schaefer }; 28df1309ceSGerald Schaefer 29df1309ceSGerald Schaefer static int ghash_init(struct shash_desc *desc) 30df1309ceSGerald Schaefer { 31df1309ceSGerald Schaefer struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 32*a1cae34eSHarald Freudenberger struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); 33df1309ceSGerald Schaefer 34df1309ceSGerald Schaefer memset(dctx, 0, sizeof(*dctx)); 35*a1cae34eSHarald Freudenberger memcpy(dctx->key, ctx->key, GHASH_BLOCK_SIZE); 36df1309ceSGerald Schaefer 37df1309ceSGerald Schaefer return 0; 38df1309ceSGerald Schaefer } 39df1309ceSGerald Schaefer 40df1309ceSGerald Schaefer static int ghash_setkey(struct crypto_shash *tfm, 41df1309ceSGerald Schaefer const u8 *key, unsigned int keylen) 42df1309ceSGerald Schaefer { 43df1309ceSGerald Schaefer struct ghash_ctx *ctx = crypto_shash_ctx(tfm); 44df1309ceSGerald Schaefer 45df1309ceSGerald Schaefer if (keylen != GHASH_BLOCK_SIZE) { 46df1309ceSGerald Schaefer crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); 47df1309ceSGerald Schaefer return -EINVAL; 48df1309ceSGerald Schaefer } 49df1309ceSGerald Schaefer 50df1309ceSGerald Schaefer memcpy(ctx->key, key, GHASH_BLOCK_SIZE); 51df1309ceSGerald Schaefer 52df1309ceSGerald Schaefer return 0; 53df1309ceSGerald Schaefer } 54df1309ceSGerald Schaefer 55df1309ceSGerald Schaefer static int ghash_update(struct shash_desc *desc, 56df1309ceSGerald Schaefer const u8 *src, unsigned int srclen) 57df1309ceSGerald Schaefer { 58df1309ceSGerald Schaefer struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 59df1309ceSGerald Schaefer unsigned int n; 60df1309ceSGerald Schaefer u8 *buf = dctx->buffer; 61df1309ceSGerald Schaefer int ret; 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) { 74*a1cae34eSHarald Freudenberger ret = crypt_s390_kimd(KIMD_GHASH, dctx, buf, 75df1309ceSGerald Schaefer GHASH_BLOCK_SIZE); 7636eb2caaSJan Glauber if (ret != GHASH_BLOCK_SIZE) 7736eb2caaSJan Glauber return -EIO; 78df1309ceSGerald Schaefer } 79df1309ceSGerald Schaefer } 80df1309ceSGerald Schaefer 81df1309ceSGerald Schaefer n = srclen & ~(GHASH_BLOCK_SIZE - 1); 82df1309ceSGerald Schaefer if (n) { 83*a1cae34eSHarald Freudenberger ret = crypt_s390_kimd(KIMD_GHASH, dctx, src, n); 8436eb2caaSJan Glauber if (ret != n) 8536eb2caaSJan Glauber return -EIO; 86df1309ceSGerald Schaefer src += n; 87df1309ceSGerald Schaefer srclen -= n; 88df1309ceSGerald Schaefer } 89df1309ceSGerald Schaefer 90df1309ceSGerald Schaefer if (srclen) { 91df1309ceSGerald Schaefer dctx->bytes = GHASH_BLOCK_SIZE - srclen; 92df1309ceSGerald Schaefer memcpy(buf, src, srclen); 93df1309ceSGerald Schaefer } 94df1309ceSGerald Schaefer 95df1309ceSGerald Schaefer return 0; 96df1309ceSGerald Schaefer } 97df1309ceSGerald Schaefer 98*a1cae34eSHarald Freudenberger static int ghash_flush(struct ghash_desc_ctx *dctx) 99df1309ceSGerald Schaefer { 100df1309ceSGerald Schaefer u8 *buf = dctx->buffer; 101df1309ceSGerald Schaefer int ret; 102df1309ceSGerald Schaefer 103df1309ceSGerald Schaefer if (dctx->bytes) { 104df1309ceSGerald Schaefer u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes); 105df1309ceSGerald Schaefer 106df1309ceSGerald Schaefer memset(pos, 0, dctx->bytes); 107df1309ceSGerald Schaefer 108*a1cae34eSHarald Freudenberger ret = crypt_s390_kimd(KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE); 10936eb2caaSJan Glauber if (ret != GHASH_BLOCK_SIZE) 11036eb2caaSJan Glauber return -EIO; 111df1309ceSGerald Schaefer 112df1309ceSGerald Schaefer dctx->bytes = 0; 113*a1cae34eSHarald Freudenberger } 114*a1cae34eSHarald Freudenberger 11536eb2caaSJan Glauber return 0; 116df1309ceSGerald Schaefer } 117df1309ceSGerald Schaefer 118df1309ceSGerald Schaefer static int ghash_final(struct shash_desc *desc, u8 *dst) 119df1309ceSGerald Schaefer { 120df1309ceSGerald Schaefer struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 12136eb2caaSJan Glauber int ret; 122df1309ceSGerald Schaefer 123*a1cae34eSHarald Freudenberger ret = ghash_flush(dctx); 12436eb2caaSJan Glauber if (!ret) 125*a1cae34eSHarald Freudenberger memcpy(dst, dctx->icv, GHASH_BLOCK_SIZE); 12636eb2caaSJan Glauber return ret; 127df1309ceSGerald Schaefer } 128df1309ceSGerald Schaefer 129df1309ceSGerald Schaefer static struct shash_alg ghash_alg = { 130df1309ceSGerald Schaefer .digestsize = GHASH_DIGEST_SIZE, 131df1309ceSGerald Schaefer .init = ghash_init, 132df1309ceSGerald Schaefer .update = ghash_update, 133df1309ceSGerald Schaefer .final = ghash_final, 134df1309ceSGerald Schaefer .setkey = ghash_setkey, 135df1309ceSGerald Schaefer .descsize = sizeof(struct ghash_desc_ctx), 136df1309ceSGerald Schaefer .base = { 137df1309ceSGerald Schaefer .cra_name = "ghash", 138df1309ceSGerald Schaefer .cra_driver_name = "ghash-s390", 139df1309ceSGerald Schaefer .cra_priority = CRYPT_S390_PRIORITY, 140df1309ceSGerald Schaefer .cra_flags = CRYPTO_ALG_TYPE_SHASH, 141df1309ceSGerald Schaefer .cra_blocksize = GHASH_BLOCK_SIZE, 142df1309ceSGerald Schaefer .cra_ctxsize = sizeof(struct ghash_ctx), 143df1309ceSGerald Schaefer .cra_module = THIS_MODULE, 144df1309ceSGerald Schaefer }, 145df1309ceSGerald Schaefer }; 146df1309ceSGerald Schaefer 147df1309ceSGerald Schaefer static int __init ghash_mod_init(void) 148df1309ceSGerald Schaefer { 149df1309ceSGerald Schaefer if (!crypt_s390_func_available(KIMD_GHASH, 150df1309ceSGerald Schaefer CRYPT_S390_MSA | CRYPT_S390_MSA4)) 151df1309ceSGerald Schaefer return -EOPNOTSUPP; 152df1309ceSGerald Schaefer 153df1309ceSGerald Schaefer return crypto_register_shash(&ghash_alg); 154df1309ceSGerald Schaefer } 155df1309ceSGerald Schaefer 156df1309ceSGerald Schaefer static void __exit ghash_mod_exit(void) 157df1309ceSGerald Schaefer { 158df1309ceSGerald Schaefer crypto_unregister_shash(&ghash_alg); 159df1309ceSGerald Schaefer } 160df1309ceSGerald Schaefer 161df1309ceSGerald Schaefer module_init(ghash_mod_init); 162df1309ceSGerald Schaefer module_exit(ghash_mod_exit); 163df1309ceSGerald Schaefer 1645d26a105SKees Cook MODULE_ALIAS_CRYPTO("ghash"); 165df1309ceSGerald Schaefer 166df1309ceSGerald Schaefer MODULE_LICENSE("GPL"); 167df1309ceSGerald Schaefer MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation"); 168