xref: /openbmc/linux/arch/arm64/crypto/sha1-ce-glue.c (revision 2c98833a42cd194ba0f537cd21917e15e5593715)
1*2c98833aSArd Biesheuvel /*
2*2c98833aSArd Biesheuvel  * sha1-ce-glue.c - SHA-1 secure hash using ARMv8 Crypto Extensions
3*2c98833aSArd Biesheuvel  *
4*2c98833aSArd Biesheuvel  * Copyright (C) 2014 Linaro Ltd <ard.biesheuvel@linaro.org>
5*2c98833aSArd Biesheuvel  *
6*2c98833aSArd Biesheuvel  * This program is free software; you can redistribute it and/or modify
7*2c98833aSArd Biesheuvel  * it under the terms of the GNU General Public License version 2 as
8*2c98833aSArd Biesheuvel  * published by the Free Software Foundation.
9*2c98833aSArd Biesheuvel  */
10*2c98833aSArd Biesheuvel 
11*2c98833aSArd Biesheuvel #include <asm/neon.h>
12*2c98833aSArd Biesheuvel #include <asm/unaligned.h>
13*2c98833aSArd Biesheuvel #include <crypto/internal/hash.h>
14*2c98833aSArd Biesheuvel #include <crypto/sha.h>
15*2c98833aSArd Biesheuvel #include <linux/cpufeature.h>
16*2c98833aSArd Biesheuvel #include <linux/crypto.h>
17*2c98833aSArd Biesheuvel #include <linux/module.h>
18*2c98833aSArd Biesheuvel 
19*2c98833aSArd Biesheuvel MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions");
20*2c98833aSArd Biesheuvel MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
21*2c98833aSArd Biesheuvel MODULE_LICENSE("GPL v2");
22*2c98833aSArd Biesheuvel 
23*2c98833aSArd Biesheuvel asmlinkage void sha1_ce_transform(int blocks, u8 const *src, u32 *state,
24*2c98833aSArd Biesheuvel 				  u8 *head, long bytes);
25*2c98833aSArd Biesheuvel 
26*2c98833aSArd Biesheuvel static int sha1_init(struct shash_desc *desc)
27*2c98833aSArd Biesheuvel {
28*2c98833aSArd Biesheuvel 	struct sha1_state *sctx = shash_desc_ctx(desc);
29*2c98833aSArd Biesheuvel 
30*2c98833aSArd Biesheuvel 	*sctx = (struct sha1_state){
31*2c98833aSArd Biesheuvel 		.state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
32*2c98833aSArd Biesheuvel 	};
33*2c98833aSArd Biesheuvel 	return 0;
34*2c98833aSArd Biesheuvel }
35*2c98833aSArd Biesheuvel 
36*2c98833aSArd Biesheuvel static int sha1_update(struct shash_desc *desc, const u8 *data,
37*2c98833aSArd Biesheuvel 		       unsigned int len)
38*2c98833aSArd Biesheuvel {
39*2c98833aSArd Biesheuvel 	struct sha1_state *sctx = shash_desc_ctx(desc);
40*2c98833aSArd Biesheuvel 	unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
41*2c98833aSArd Biesheuvel 
42*2c98833aSArd Biesheuvel 	sctx->count += len;
43*2c98833aSArd Biesheuvel 
44*2c98833aSArd Biesheuvel 	if ((partial + len) >= SHA1_BLOCK_SIZE) {
45*2c98833aSArd Biesheuvel 		int blocks;
46*2c98833aSArd Biesheuvel 
47*2c98833aSArd Biesheuvel 		if (partial) {
48*2c98833aSArd Biesheuvel 			int p = SHA1_BLOCK_SIZE - partial;
49*2c98833aSArd Biesheuvel 
50*2c98833aSArd Biesheuvel 			memcpy(sctx->buffer + partial, data, p);
51*2c98833aSArd Biesheuvel 			data += p;
52*2c98833aSArd Biesheuvel 			len -= p;
53*2c98833aSArd Biesheuvel 		}
54*2c98833aSArd Biesheuvel 
55*2c98833aSArd Biesheuvel 		blocks = len / SHA1_BLOCK_SIZE;
56*2c98833aSArd Biesheuvel 		len %= SHA1_BLOCK_SIZE;
57*2c98833aSArd Biesheuvel 
58*2c98833aSArd Biesheuvel 		kernel_neon_begin_partial(16);
59*2c98833aSArd Biesheuvel 		sha1_ce_transform(blocks, data, sctx->state,
60*2c98833aSArd Biesheuvel 				  partial ? sctx->buffer : NULL, 0);
61*2c98833aSArd Biesheuvel 		kernel_neon_end();
62*2c98833aSArd Biesheuvel 
63*2c98833aSArd Biesheuvel 		data += blocks * SHA1_BLOCK_SIZE;
64*2c98833aSArd Biesheuvel 		partial = 0;
65*2c98833aSArd Biesheuvel 	}
66*2c98833aSArd Biesheuvel 	if (len)
67*2c98833aSArd Biesheuvel 		memcpy(sctx->buffer + partial, data, len);
68*2c98833aSArd Biesheuvel 	return 0;
69*2c98833aSArd Biesheuvel }
70*2c98833aSArd Biesheuvel 
71*2c98833aSArd Biesheuvel static int sha1_final(struct shash_desc *desc, u8 *out)
72*2c98833aSArd Biesheuvel {
73*2c98833aSArd Biesheuvel 	static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, };
74*2c98833aSArd Biesheuvel 
75*2c98833aSArd Biesheuvel 	struct sha1_state *sctx = shash_desc_ctx(desc);
76*2c98833aSArd Biesheuvel 	__be64 bits = cpu_to_be64(sctx->count << 3);
77*2c98833aSArd Biesheuvel 	__be32 *dst = (__be32 *)out;
78*2c98833aSArd Biesheuvel 	int i;
79*2c98833aSArd Biesheuvel 
80*2c98833aSArd Biesheuvel 	u32 padlen = SHA1_BLOCK_SIZE
81*2c98833aSArd Biesheuvel 		     - ((sctx->count + sizeof(bits)) % SHA1_BLOCK_SIZE);
82*2c98833aSArd Biesheuvel 
83*2c98833aSArd Biesheuvel 	sha1_update(desc, padding, padlen);
84*2c98833aSArd Biesheuvel 	sha1_update(desc, (const u8 *)&bits, sizeof(bits));
85*2c98833aSArd Biesheuvel 
86*2c98833aSArd Biesheuvel 	for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
87*2c98833aSArd Biesheuvel 		put_unaligned_be32(sctx->state[i], dst++);
88*2c98833aSArd Biesheuvel 
89*2c98833aSArd Biesheuvel 	*sctx = (struct sha1_state){};
90*2c98833aSArd Biesheuvel 	return 0;
91*2c98833aSArd Biesheuvel }
92*2c98833aSArd Biesheuvel 
93*2c98833aSArd Biesheuvel static int sha1_finup(struct shash_desc *desc, const u8 *data,
94*2c98833aSArd Biesheuvel 		      unsigned int len, u8 *out)
95*2c98833aSArd Biesheuvel {
96*2c98833aSArd Biesheuvel 	struct sha1_state *sctx = shash_desc_ctx(desc);
97*2c98833aSArd Biesheuvel 	__be32 *dst = (__be32 *)out;
98*2c98833aSArd Biesheuvel 	int blocks;
99*2c98833aSArd Biesheuvel 	int i;
100*2c98833aSArd Biesheuvel 
101*2c98833aSArd Biesheuvel 	if (sctx->count || !len || (len % SHA1_BLOCK_SIZE)) {
102*2c98833aSArd Biesheuvel 		sha1_update(desc, data, len);
103*2c98833aSArd Biesheuvel 		return sha1_final(desc, out);
104*2c98833aSArd Biesheuvel 	}
105*2c98833aSArd Biesheuvel 
106*2c98833aSArd Biesheuvel 	/*
107*2c98833aSArd Biesheuvel 	 * Use a fast path if the input is a multiple of 64 bytes. In
108*2c98833aSArd Biesheuvel 	 * this case, there is no need to copy data around, and we can
109*2c98833aSArd Biesheuvel 	 * perform the entire digest calculation in a single invocation
110*2c98833aSArd Biesheuvel 	 * of sha1_ce_transform()
111*2c98833aSArd Biesheuvel 	 */
112*2c98833aSArd Biesheuvel 	blocks = len / SHA1_BLOCK_SIZE;
113*2c98833aSArd Biesheuvel 
114*2c98833aSArd Biesheuvel 	kernel_neon_begin_partial(16);
115*2c98833aSArd Biesheuvel 	sha1_ce_transform(blocks, data, sctx->state, NULL, len);
116*2c98833aSArd Biesheuvel 	kernel_neon_end();
117*2c98833aSArd Biesheuvel 
118*2c98833aSArd Biesheuvel 	for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
119*2c98833aSArd Biesheuvel 		put_unaligned_be32(sctx->state[i], dst++);
120*2c98833aSArd Biesheuvel 
121*2c98833aSArd Biesheuvel 	*sctx = (struct sha1_state){};
122*2c98833aSArd Biesheuvel 	return 0;
123*2c98833aSArd Biesheuvel }
124*2c98833aSArd Biesheuvel 
125*2c98833aSArd Biesheuvel static int sha1_export(struct shash_desc *desc, void *out)
126*2c98833aSArd Biesheuvel {
127*2c98833aSArd Biesheuvel 	struct sha1_state *sctx = shash_desc_ctx(desc);
128*2c98833aSArd Biesheuvel 	struct sha1_state *dst = out;
129*2c98833aSArd Biesheuvel 
130*2c98833aSArd Biesheuvel 	*dst = *sctx;
131*2c98833aSArd Biesheuvel 	return 0;
132*2c98833aSArd Biesheuvel }
133*2c98833aSArd Biesheuvel 
134*2c98833aSArd Biesheuvel static int sha1_import(struct shash_desc *desc, const void *in)
135*2c98833aSArd Biesheuvel {
136*2c98833aSArd Biesheuvel 	struct sha1_state *sctx = shash_desc_ctx(desc);
137*2c98833aSArd Biesheuvel 	struct sha1_state const *src = in;
138*2c98833aSArd Biesheuvel 
139*2c98833aSArd Biesheuvel 	*sctx = *src;
140*2c98833aSArd Biesheuvel 	return 0;
141*2c98833aSArd Biesheuvel }
142*2c98833aSArd Biesheuvel 
143*2c98833aSArd Biesheuvel static struct shash_alg alg = {
144*2c98833aSArd Biesheuvel 	.init			= sha1_init,
145*2c98833aSArd Biesheuvel 	.update			= sha1_update,
146*2c98833aSArd Biesheuvel 	.final			= sha1_final,
147*2c98833aSArd Biesheuvel 	.finup			= sha1_finup,
148*2c98833aSArd Biesheuvel 	.export			= sha1_export,
149*2c98833aSArd Biesheuvel 	.import			= sha1_import,
150*2c98833aSArd Biesheuvel 	.descsize		= sizeof(struct sha1_state),
151*2c98833aSArd Biesheuvel 	.digestsize		= SHA1_DIGEST_SIZE,
152*2c98833aSArd Biesheuvel 	.statesize		= sizeof(struct sha1_state),
153*2c98833aSArd Biesheuvel 	.base			= {
154*2c98833aSArd Biesheuvel 		.cra_name		= "sha1",
155*2c98833aSArd Biesheuvel 		.cra_driver_name	= "sha1-ce",
156*2c98833aSArd Biesheuvel 		.cra_priority		= 200,
157*2c98833aSArd Biesheuvel 		.cra_flags		= CRYPTO_ALG_TYPE_SHASH,
158*2c98833aSArd Biesheuvel 		.cra_blocksize		= SHA1_BLOCK_SIZE,
159*2c98833aSArd Biesheuvel 		.cra_module		= THIS_MODULE,
160*2c98833aSArd Biesheuvel 	}
161*2c98833aSArd Biesheuvel };
162*2c98833aSArd Biesheuvel 
163*2c98833aSArd Biesheuvel static int __init sha1_ce_mod_init(void)
164*2c98833aSArd Biesheuvel {
165*2c98833aSArd Biesheuvel 	return crypto_register_shash(&alg);
166*2c98833aSArd Biesheuvel }
167*2c98833aSArd Biesheuvel 
168*2c98833aSArd Biesheuvel static void __exit sha1_ce_mod_fini(void)
169*2c98833aSArd Biesheuvel {
170*2c98833aSArd Biesheuvel 	crypto_unregister_shash(&alg);
171*2c98833aSArd Biesheuvel }
172*2c98833aSArd Biesheuvel 
173*2c98833aSArd Biesheuvel module_cpu_feature_match(SHA1, sha1_ce_mod_init);
174*2c98833aSArd Biesheuvel module_exit(sha1_ce_mod_fini);
175