xref: /openbmc/linux/arch/arm64/crypto/sha256-glue.c (revision 22d55f02)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Linux/arm64 port of the OpenSSL SHA256 implementation for AArch64
4  *
5  * Copyright (c) 2016 Linaro Ltd. <ard.biesheuvel@linaro.org>
6  */
7 
8 #include <asm/hwcap.h>
9 #include <asm/neon.h>
10 #include <asm/simd.h>
11 #include <crypto/internal/hash.h>
12 #include <crypto/internal/simd.h>
13 #include <crypto/sha.h>
14 #include <crypto/sha256_base.h>
15 #include <linux/cryptohash.h>
16 #include <linux/types.h>
17 #include <linux/string.h>
18 
19 MODULE_DESCRIPTION("SHA-224/SHA-256 secure hash for arm64");
20 MODULE_AUTHOR("Andy Polyakov <appro@openssl.org>");
21 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
22 MODULE_LICENSE("GPL v2");
23 MODULE_ALIAS_CRYPTO("sha224");
24 MODULE_ALIAS_CRYPTO("sha256");
25 
26 asmlinkage void sha256_block_data_order(u32 *digest, const void *data,
27 					unsigned int num_blks);
28 EXPORT_SYMBOL(sha256_block_data_order);
29 
30 asmlinkage void sha256_block_neon(u32 *digest, const void *data,
31 				  unsigned int num_blks);
32 
33 static int sha256_update(struct shash_desc *desc, const u8 *data,
34 			 unsigned int len)
35 {
36 	return sha256_base_do_update(desc, data, len,
37 				(sha256_block_fn *)sha256_block_data_order);
38 }
39 
40 static int sha256_finup(struct shash_desc *desc, const u8 *data,
41 			unsigned int len, u8 *out)
42 {
43 	if (len)
44 		sha256_base_do_update(desc, data, len,
45 				(sha256_block_fn *)sha256_block_data_order);
46 	sha256_base_do_finalize(desc,
47 				(sha256_block_fn *)sha256_block_data_order);
48 
49 	return sha256_base_finish(desc, out);
50 }
51 
52 static int sha256_final(struct shash_desc *desc, u8 *out)
53 {
54 	return sha256_finup(desc, NULL, 0, out);
55 }
56 
57 static struct shash_alg algs[] = { {
58 	.digestsize		= SHA256_DIGEST_SIZE,
59 	.init			= sha256_base_init,
60 	.update			= sha256_update,
61 	.final			= sha256_final,
62 	.finup			= sha256_finup,
63 	.descsize		= sizeof(struct sha256_state),
64 	.base.cra_name		= "sha256",
65 	.base.cra_driver_name	= "sha256-arm64",
66 	.base.cra_priority	= 125,
67 	.base.cra_blocksize	= SHA256_BLOCK_SIZE,
68 	.base.cra_module	= THIS_MODULE,
69 }, {
70 	.digestsize		= SHA224_DIGEST_SIZE,
71 	.init			= sha224_base_init,
72 	.update			= sha256_update,
73 	.final			= sha256_final,
74 	.finup			= sha256_finup,
75 	.descsize		= sizeof(struct sha256_state),
76 	.base.cra_name		= "sha224",
77 	.base.cra_driver_name	= "sha224-arm64",
78 	.base.cra_priority	= 125,
79 	.base.cra_blocksize	= SHA224_BLOCK_SIZE,
80 	.base.cra_module	= THIS_MODULE,
81 } };
82 
83 static int sha256_update_neon(struct shash_desc *desc, const u8 *data,
84 			      unsigned int len)
85 {
86 	struct sha256_state *sctx = shash_desc_ctx(desc);
87 
88 	if (!crypto_simd_usable())
89 		return sha256_base_do_update(desc, data, len,
90 				(sha256_block_fn *)sha256_block_data_order);
91 
92 	while (len > 0) {
93 		unsigned int chunk = len;
94 
95 		/*
96 		 * Don't hog the CPU for the entire time it takes to process all
97 		 * input when running on a preemptible kernel, but process the
98 		 * data block by block instead.
99 		 */
100 		if (IS_ENABLED(CONFIG_PREEMPT) &&
101 		    chunk + sctx->count % SHA256_BLOCK_SIZE > SHA256_BLOCK_SIZE)
102 			chunk = SHA256_BLOCK_SIZE -
103 				sctx->count % SHA256_BLOCK_SIZE;
104 
105 		kernel_neon_begin();
106 		sha256_base_do_update(desc, data, chunk,
107 				      (sha256_block_fn *)sha256_block_neon);
108 		kernel_neon_end();
109 		data += chunk;
110 		len -= chunk;
111 	}
112 	return 0;
113 }
114 
115 static int sha256_finup_neon(struct shash_desc *desc, const u8 *data,
116 			     unsigned int len, u8 *out)
117 {
118 	if (!crypto_simd_usable()) {
119 		if (len)
120 			sha256_base_do_update(desc, data, len,
121 				(sha256_block_fn *)sha256_block_data_order);
122 		sha256_base_do_finalize(desc,
123 				(sha256_block_fn *)sha256_block_data_order);
124 	} else {
125 		if (len)
126 			sha256_update_neon(desc, data, len);
127 		kernel_neon_begin();
128 		sha256_base_do_finalize(desc,
129 				(sha256_block_fn *)sha256_block_neon);
130 		kernel_neon_end();
131 	}
132 	return sha256_base_finish(desc, out);
133 }
134 
135 static int sha256_final_neon(struct shash_desc *desc, u8 *out)
136 {
137 	return sha256_finup_neon(desc, NULL, 0, out);
138 }
139 
140 static struct shash_alg neon_algs[] = { {
141 	.digestsize		= SHA256_DIGEST_SIZE,
142 	.init			= sha256_base_init,
143 	.update			= sha256_update_neon,
144 	.final			= sha256_final_neon,
145 	.finup			= sha256_finup_neon,
146 	.descsize		= sizeof(struct sha256_state),
147 	.base.cra_name		= "sha256",
148 	.base.cra_driver_name	= "sha256-arm64-neon",
149 	.base.cra_priority	= 150,
150 	.base.cra_blocksize	= SHA256_BLOCK_SIZE,
151 	.base.cra_module	= THIS_MODULE,
152 }, {
153 	.digestsize		= SHA224_DIGEST_SIZE,
154 	.init			= sha224_base_init,
155 	.update			= sha256_update_neon,
156 	.final			= sha256_final_neon,
157 	.finup			= sha256_finup_neon,
158 	.descsize		= sizeof(struct sha256_state),
159 	.base.cra_name		= "sha224",
160 	.base.cra_driver_name	= "sha224-arm64-neon",
161 	.base.cra_priority	= 150,
162 	.base.cra_blocksize	= SHA224_BLOCK_SIZE,
163 	.base.cra_module	= THIS_MODULE,
164 } };
165 
166 static int __init sha256_mod_init(void)
167 {
168 	int ret = crypto_register_shashes(algs, ARRAY_SIZE(algs));
169 	if (ret)
170 		return ret;
171 
172 	if (cpu_have_named_feature(ASIMD)) {
173 		ret = crypto_register_shashes(neon_algs, ARRAY_SIZE(neon_algs));
174 		if (ret)
175 			crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
176 	}
177 	return ret;
178 }
179 
180 static void __exit sha256_mod_fini(void)
181 {
182 	if (cpu_have_named_feature(ASIMD))
183 		crypto_unregister_shashes(neon_algs, ARRAY_SIZE(neon_algs));
184 	crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
185 }
186 
187 module_init(sha256_mod_init);
188 module_exit(sha256_mod_fini);
189