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