diff options
Diffstat (limited to 'arch/s390/crypto/ghash_s390.c')
-rw-r--r-- | arch/s390/crypto/ghash_s390.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c new file mode 100644 index 000000000000..b1bd170f24b1 --- /dev/null +++ b/arch/s390/crypto/ghash_s390.c | |||
@@ -0,0 +1,162 @@ | |||
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"); | ||