2 * GHASH routines supporting VMX instructions on the Power 8
4 * Copyright (C) 2015 International Business Machines Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 only.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com>
22 #include <linux/types.h>
23 #include <linux/err.h>
24 #include <linux/crypto.h>
25 #include <linux/delay.h>
26 #include <linux/hardirq.h>
27 #include <asm/switch_to.h>
28 #include <crypto/aes.h>
29 #include <crypto/scatterwalk.h>
30 #include <crypto/internal/hash.h>
31 #include <crypto/b128ops.h>
33 #define IN_INTERRUPT in_interrupt()
35 #define GHASH_BLOCK_SIZE (16)
36 #define GHASH_DIGEST_SIZE (16)
37 #define GHASH_KEY_LEN (16)
39 void gcm_init_p8(u128 htable
[16], const u64 Xi
[2]);
40 void gcm_gmult_p8(u64 Xi
[2], const u128 htable
[16]);
41 void gcm_ghash_p8(u64 Xi
[2], const u128 htable
[16],
42 const u8
*in
, size_t len
);
46 struct crypto_shash
*fallback
;
49 struct p8_ghash_desc_ctx
{
51 u8 buffer
[GHASH_DIGEST_SIZE
];
53 struct shash_desc fallback_desc
;
56 static int p8_ghash_init_tfm(struct crypto_tfm
*tfm
)
59 struct crypto_shash
*fallback
;
60 struct crypto_shash
*shash_tfm
= __crypto_shash_cast(tfm
);
61 struct p8_ghash_ctx
*ctx
= crypto_tfm_ctx(tfm
);
63 if (!(alg
= crypto_tfm_alg_name(tfm
))) {
64 printk(KERN_ERR
"Failed to get algorithm name.\n");
68 fallback
= crypto_alloc_shash(alg
, 0, CRYPTO_ALG_NEED_FALLBACK
);
69 if (IS_ERR(fallback
)) {
71 "Failed to allocate transformation for '%s': %ld\n",
72 alg
, PTR_ERR(fallback
));
73 return PTR_ERR(fallback
);
75 printk(KERN_INFO
"Using '%s' as fallback implementation.\n",
76 crypto_tfm_alg_driver_name(crypto_shash_tfm(fallback
)));
78 crypto_shash_set_flags(fallback
,
79 crypto_shash_get_flags((struct crypto_shash
81 ctx
->fallback
= fallback
;
83 shash_tfm
->descsize
= sizeof(struct p8_ghash_desc_ctx
)
84 + crypto_shash_descsize(fallback
);
89 static void p8_ghash_exit_tfm(struct crypto_tfm
*tfm
)
91 struct p8_ghash_ctx
*ctx
= crypto_tfm_ctx(tfm
);
94 crypto_free_shash(ctx
->fallback
);
99 static int p8_ghash_init(struct shash_desc
*desc
)
101 struct p8_ghash_ctx
*ctx
= crypto_tfm_ctx(crypto_shash_tfm(desc
->tfm
));
102 struct p8_ghash_desc_ctx
*dctx
= shash_desc_ctx(desc
);
105 memset(dctx
->shash
, 0, GHASH_DIGEST_SIZE
);
106 dctx
->fallback_desc
.tfm
= ctx
->fallback
;
107 dctx
->fallback_desc
.flags
= desc
->flags
;
108 return crypto_shash_init(&dctx
->fallback_desc
);
111 static int p8_ghash_setkey(struct crypto_shash
*tfm
, const u8
*key
,
114 struct p8_ghash_ctx
*ctx
= crypto_tfm_ctx(crypto_shash_tfm(tfm
));
116 if (keylen
!= GHASH_KEY_LEN
)
122 gcm_init_p8(ctx
->htable
, (const u64
*) key
);
123 disable_kernel_vsx();
126 return crypto_shash_setkey(ctx
->fallback
, key
, keylen
);
129 static int p8_ghash_update(struct shash_desc
*desc
,
130 const u8
*src
, unsigned int srclen
)
133 struct p8_ghash_ctx
*ctx
= crypto_tfm_ctx(crypto_shash_tfm(desc
->tfm
));
134 struct p8_ghash_desc_ctx
*dctx
= shash_desc_ctx(desc
);
137 return crypto_shash_update(&dctx
->fallback_desc
, src
,
141 if (dctx
->bytes
+ srclen
< GHASH_DIGEST_SIZE
) {
142 memcpy(dctx
->buffer
+ dctx
->bytes
, src
,
144 dctx
->bytes
+= srclen
;
147 memcpy(dctx
->buffer
+ dctx
->bytes
, src
,
148 GHASH_DIGEST_SIZE
- dctx
->bytes
);
152 gcm_ghash_p8(dctx
->shash
, ctx
->htable
,
153 dctx
->buffer
, GHASH_DIGEST_SIZE
);
154 disable_kernel_vsx();
157 src
+= GHASH_DIGEST_SIZE
- dctx
->bytes
;
158 srclen
-= GHASH_DIGEST_SIZE
- dctx
->bytes
;
161 len
= srclen
& ~(GHASH_DIGEST_SIZE
- 1);
166 gcm_ghash_p8(dctx
->shash
, ctx
->htable
, src
, len
);
167 disable_kernel_vsx();
174 memcpy(dctx
->buffer
, src
, srclen
);
175 dctx
->bytes
= srclen
;
181 static int p8_ghash_final(struct shash_desc
*desc
, u8
*out
)
184 struct p8_ghash_ctx
*ctx
= crypto_tfm_ctx(crypto_shash_tfm(desc
->tfm
));
185 struct p8_ghash_desc_ctx
*dctx
= shash_desc_ctx(desc
);
188 return crypto_shash_final(&dctx
->fallback_desc
, out
);
191 for (i
= dctx
->bytes
; i
< GHASH_DIGEST_SIZE
; i
++)
196 gcm_ghash_p8(dctx
->shash
, ctx
->htable
,
197 dctx
->buffer
, GHASH_DIGEST_SIZE
);
198 disable_kernel_vsx();
203 memcpy(out
, dctx
->shash
, GHASH_DIGEST_SIZE
);
208 struct shash_alg p8_ghash_alg
= {
209 .digestsize
= GHASH_DIGEST_SIZE
,
210 .init
= p8_ghash_init
,
211 .update
= p8_ghash_update
,
212 .final
= p8_ghash_final
,
213 .setkey
= p8_ghash_setkey
,
214 .descsize
= sizeof(struct p8_ghash_desc_ctx
),
217 .cra_driver_name
= "p8_ghash",
218 .cra_priority
= 1000,
219 .cra_flags
= CRYPTO_ALG_TYPE_SHASH
| CRYPTO_ALG_NEED_FALLBACK
,
220 .cra_blocksize
= GHASH_BLOCK_SIZE
,
221 .cra_ctxsize
= sizeof(struct p8_ghash_ctx
),
222 .cra_module
= THIS_MODULE
,
223 .cra_init
= p8_ghash_init_tfm
,
224 .cra_exit
= p8_ghash_exit_tfm
,