xref: /linux/crypto/sha512_generic.c (revision 6ae51ffe)
18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
278f8b3a2SJan Glauber /* SHA-512 code by Jean-Luc Cooke <jlcooke@certainkey.com>
378f8b3a2SJan Glauber  *
478f8b3a2SJan Glauber  * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
578f8b3a2SJan Glauber  * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
678f8b3a2SJan Glauber  * Copyright (c) 2003 Kyle McMartin <kyle@debian.org>
778f8b3a2SJan Glauber  */
8bd9d20dbSAdrian-Ken Rueegsegger #include <crypto/internal/hash.h>
978f8b3a2SJan Glauber #include <linux/kernel.h>
1078f8b3a2SJan Glauber #include <linux/module.h>
1178f8b3a2SJan Glauber #include <linux/mm.h>
1278f8b3a2SJan Glauber #include <linux/init.h>
1378f8b3a2SJan Glauber #include <linux/crypto.h>
1478f8b3a2SJan Glauber #include <linux/types.h>
15*a24d22b2SEric Biggers #include <crypto/sha2.h>
16ca142584SArd Biesheuvel #include <crypto/sha512_base.h>
17f9e2bca6SAdrian-Ken Rueegsegger #include <linux/percpu.h>
1878f8b3a2SJan Glauber #include <asm/byteorder.h>
19be34c4efSDavid S. Miller #include <asm/unaligned.h>
2078f8b3a2SJan Glauber 
2126f7120bSAntoine Tenart const u8 sha384_zero_message_hash[SHA384_DIGEST_SIZE] = {
2226f7120bSAntoine Tenart 	0x38, 0xb0, 0x60, 0xa7, 0x51, 0xac, 0x96, 0x38,
2326f7120bSAntoine Tenart 	0x4c, 0xd9, 0x32, 0x7e, 0xb1, 0xb1, 0xe3, 0x6a,
2426f7120bSAntoine Tenart 	0x21, 0xfd, 0xb7, 0x11, 0x14, 0xbe, 0x07, 0x43,
2526f7120bSAntoine Tenart 	0x4c, 0x0c, 0xc7, 0xbf, 0x63, 0xf6, 0xe1, 0xda,
2626f7120bSAntoine Tenart 	0x27, 0x4e, 0xde, 0xbf, 0xe7, 0x6f, 0x65, 0xfb,
2726f7120bSAntoine Tenart 	0xd5, 0x1a, 0xd2, 0xf1, 0x48, 0x98, 0xb9, 0x5b
2826f7120bSAntoine Tenart };
2926f7120bSAntoine Tenart EXPORT_SYMBOL_GPL(sha384_zero_message_hash);
3026f7120bSAntoine Tenart 
3130c217efSAntoine Tenart const u8 sha512_zero_message_hash[SHA512_DIGEST_SIZE] = {
3230c217efSAntoine Tenart 	0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd,
3330c217efSAntoine Tenart 	0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07,
3430c217efSAntoine Tenart 	0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc,
3530c217efSAntoine Tenart 	0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce,
3630c217efSAntoine Tenart 	0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0,
3730c217efSAntoine Tenart 	0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f,
3830c217efSAntoine Tenart 	0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81,
3930c217efSAntoine Tenart 	0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e
4030c217efSAntoine Tenart };
4130c217efSAntoine Tenart EXPORT_SYMBOL_GPL(sha512_zero_message_hash);
4230c217efSAntoine Tenart 
Ch(u64 x,u64 y,u64 z)4378f8b3a2SJan Glauber static inline u64 Ch(u64 x, u64 y, u64 z)
4478f8b3a2SJan Glauber {
4578f8b3a2SJan Glauber         return z ^ (x & (y ^ z));
4678f8b3a2SJan Glauber }
4778f8b3a2SJan Glauber 
Maj(u64 x,u64 y,u64 z)4878f8b3a2SJan Glauber static inline u64 Maj(u64 x, u64 y, u64 z)
4978f8b3a2SJan Glauber {
5078f8b3a2SJan Glauber         return (x & y) | (z & (x | y));
5178f8b3a2SJan Glauber }
5278f8b3a2SJan Glauber 
5378f8b3a2SJan Glauber static const u64 sha512_K[80] = {
5478f8b3a2SJan Glauber         0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
5578f8b3a2SJan Glauber         0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
5678f8b3a2SJan Glauber         0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
5778f8b3a2SJan Glauber         0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
5878f8b3a2SJan Glauber         0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
5978f8b3a2SJan Glauber         0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
6078f8b3a2SJan Glauber         0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
6178f8b3a2SJan Glauber         0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
6278f8b3a2SJan Glauber         0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
6378f8b3a2SJan Glauber         0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
6478f8b3a2SJan Glauber         0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
6578f8b3a2SJan Glauber         0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
6678f8b3a2SJan Glauber         0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
6778f8b3a2SJan Glauber         0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
6878f8b3a2SJan Glauber         0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
6978f8b3a2SJan Glauber         0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
7078f8b3a2SJan Glauber         0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
7178f8b3a2SJan Glauber         0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
7278f8b3a2SJan Glauber         0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
7378f8b3a2SJan Glauber         0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
7478f8b3a2SJan Glauber         0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
7578f8b3a2SJan Glauber         0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
7678f8b3a2SJan Glauber         0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
7778f8b3a2SJan Glauber         0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
7878f8b3a2SJan Glauber         0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
7978f8b3a2SJan Glauber         0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
8078f8b3a2SJan Glauber         0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
8178f8b3a2SJan Glauber };
8278f8b3a2SJan Glauber 
83f2ea0f5fSAlexey Dobriyan #define e0(x)       (ror64(x,28) ^ ror64(x,34) ^ ror64(x,39))
84f2ea0f5fSAlexey Dobriyan #define e1(x)       (ror64(x,14) ^ ror64(x,18) ^ ror64(x,41))
85f2ea0f5fSAlexey Dobriyan #define s0(x)       (ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7))
86f2ea0f5fSAlexey Dobriyan #define s1(x)       (ror64(x,19) ^ ror64(x,61) ^ (x >> 6))
8778f8b3a2SJan Glauber 
LOAD_OP(int I,u64 * W,const u8 * input)8878f8b3a2SJan Glauber static inline void LOAD_OP(int I, u64 *W, const u8 *input)
8978f8b3a2SJan Glauber {
90be34c4efSDavid S. Miller 	W[I] = get_unaligned_be64((__u64 *)input + I);
9178f8b3a2SJan Glauber }
9278f8b3a2SJan Glauber 
BLEND_OP(int I,u64 * W)9378f8b3a2SJan Glauber static inline void BLEND_OP(int I, u64 *W)
9478f8b3a2SJan Glauber {
9558d7d18bSHerbert Xu 	W[I & 15] += s1(W[(I-2) & 15]) + W[(I-7) & 15] + s0(W[(I-15) & 15]);
9678f8b3a2SJan Glauber }
9778f8b3a2SJan Glauber 
9878f8b3a2SJan Glauber static void
sha512_transform(u64 * state,const u8 * input)99f9e2bca6SAdrian-Ken Rueegsegger sha512_transform(u64 *state, const u8 *input)
10078f8b3a2SJan Glauber {
10178f8b3a2SJan Glauber 	u64 a, b, c, d, e, f, g, h, t1, t2;
10278f8b3a2SJan Glauber 
10378f8b3a2SJan Glauber 	int i;
10451fc6dc8SAlexey Dobriyan 	u64 W[16];
10578f8b3a2SJan Glauber 
10678f8b3a2SJan Glauber 	/* load the state into our registers */
10778f8b3a2SJan Glauber 	a=state[0];   b=state[1];   c=state[2];   d=state[3];
10878f8b3a2SJan Glauber 	e=state[4];   f=state[5];   g=state[6];   h=state[7];
10978f8b3a2SJan Glauber 
1103a92d687SHerbert Xu 	/* now iterate */
1113a92d687SHerbert Xu 	for (i=0; i<80; i+=8) {
1123a92d687SHerbert Xu 		if (!(i & 8)) {
1133a92d687SHerbert Xu 			int j;
11451fc6dc8SAlexey Dobriyan 
1153a92d687SHerbert Xu 			if (i < 16) {
1163a92d687SHerbert Xu 				/* load the input */
1173a92d687SHerbert Xu 				for (j = 0; j < 16; j++)
1183a92d687SHerbert Xu 					LOAD_OP(i + j, W, input);
1193a92d687SHerbert Xu 			} else {
1203a92d687SHerbert Xu 				for (j = 0; j < 16; j++) {
1213a92d687SHerbert Xu 					BLEND_OP(i + j, W);
12251fc6dc8SAlexey Dobriyan 				}
1233a92d687SHerbert Xu 			}
1243a92d687SHerbert Xu 		}
1253a92d687SHerbert Xu 
1263a92d687SHerbert Xu 		t1 = h + e1(e) + Ch(e,f,g) + sha512_K[i  ] + W[(i & 15)];
1273a92d687SHerbert Xu 		t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
1283a92d687SHerbert Xu 		t1 = g + e1(d) + Ch(d,e,f) + sha512_K[i+1] + W[(i & 15) + 1];
1293a92d687SHerbert Xu 		t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
1303a92d687SHerbert Xu 		t1 = f + e1(c) + Ch(c,d,e) + sha512_K[i+2] + W[(i & 15) + 2];
1313a92d687SHerbert Xu 		t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
1323a92d687SHerbert Xu 		t1 = e + e1(b) + Ch(b,c,d) + sha512_K[i+3] + W[(i & 15) + 3];
1333a92d687SHerbert Xu 		t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
1343a92d687SHerbert Xu 		t1 = d + e1(a) + Ch(a,b,c) + sha512_K[i+4] + W[(i & 15) + 4];
1353a92d687SHerbert Xu 		t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
1363a92d687SHerbert Xu 		t1 = c + e1(h) + Ch(h,a,b) + sha512_K[i+5] + W[(i & 15) + 5];
1373a92d687SHerbert Xu 		t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
1383a92d687SHerbert Xu 		t1 = b + e1(g) + Ch(g,h,a) + sha512_K[i+6] + W[(i & 15) + 6];
1393a92d687SHerbert Xu 		t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
1403a92d687SHerbert Xu 		t1 = a + e1(f) + Ch(f,g,h) + sha512_K[i+7] + W[(i & 15) + 7];
1413a92d687SHerbert Xu 		t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
14278f8b3a2SJan Glauber 	}
14378f8b3a2SJan Glauber 
14478f8b3a2SJan Glauber 	state[0] += a; state[1] += b; state[2] += c; state[3] += d;
14578f8b3a2SJan Glauber 	state[4] += e; state[5] += f; state[6] += g; state[7] += h;
14678f8b3a2SJan Glauber }
14778f8b3a2SJan Glauber 
sha512_generic_block_fn(struct sha512_state * sst,u8 const * src,int blocks)148ca142584SArd Biesheuvel static void sha512_generic_block_fn(struct sha512_state *sst, u8 const *src,
149ca142584SArd Biesheuvel 				    int blocks)
15078f8b3a2SJan Glauber {
151ca142584SArd Biesheuvel 	while (blocks--) {
152ca142584SArd Biesheuvel 		sha512_transform(sst->state, src);
153ca142584SArd Biesheuvel 		src += SHA512_BLOCK_SIZE;
15478f8b3a2SJan Glauber 	}
15578f8b3a2SJan Glauber }
15678f8b3a2SJan Glauber 
crypto_sha512_update(struct shash_desc * desc,const u8 * data,unsigned int len)157bf70fa9dSTim Chen int crypto_sha512_update(struct shash_desc *desc, const u8 *data,
158bf70fa9dSTim Chen 			unsigned int len)
15978f8b3a2SJan Glauber {
160ca142584SArd Biesheuvel 	return sha512_base_do_update(desc, data, len, sha512_generic_block_fn);
16178f8b3a2SJan Glauber }
162bf70fa9dSTim Chen EXPORT_SYMBOL(crypto_sha512_update);
16378f8b3a2SJan Glauber 
sha512_final(struct shash_desc * desc,u8 * hash)164ca142584SArd Biesheuvel static int sha512_final(struct shash_desc *desc, u8 *hash)
16578f8b3a2SJan Glauber {
166ca142584SArd Biesheuvel 	sha512_base_do_finalize(desc, sha512_generic_block_fn);
167ca142584SArd Biesheuvel 	return sha512_base_finish(desc, hash);
16878f8b3a2SJan Glauber }
16978f8b3a2SJan Glauber 
crypto_sha512_finup(struct shash_desc * desc,const u8 * data,unsigned int len,u8 * hash)170ca142584SArd Biesheuvel int crypto_sha512_finup(struct shash_desc *desc, const u8 *data,
171ca142584SArd Biesheuvel 			unsigned int len, u8 *hash)
17278f8b3a2SJan Glauber {
173ca142584SArd Biesheuvel 	sha512_base_do_update(desc, data, len, sha512_generic_block_fn);
174ca142584SArd Biesheuvel 	return sha512_final(desc, hash);
17578f8b3a2SJan Glauber }
176ca142584SArd Biesheuvel EXPORT_SYMBOL(crypto_sha512_finup);
17778f8b3a2SJan Glauber 
178648b2a10SJussi Kivilinna static struct shash_alg sha512_algs[2] = { {
179bd9d20dbSAdrian-Ken Rueegsegger 	.digestsize	=	SHA512_DIGEST_SIZE,
180ca142584SArd Biesheuvel 	.init		=	sha512_base_init,
181bf70fa9dSTim Chen 	.update		=	crypto_sha512_update,
182bd9d20dbSAdrian-Ken Rueegsegger 	.final		=	sha512_final,
183ca142584SArd Biesheuvel 	.finup		=	crypto_sha512_finup,
1841f38ad83SHerbert Xu 	.descsize	=	sizeof(struct sha512_state),
185bd9d20dbSAdrian-Ken Rueegsegger 	.base		=	{
18678f8b3a2SJan Glauber 		.cra_name	=	"sha512",
187d3295814SJussi Kivilinna 		.cra_driver_name =	"sha512-generic",
188e4789016SEric Biggers 		.cra_priority	=	100,
18978f8b3a2SJan Glauber 		.cra_blocksize	=	SHA512_BLOCK_SIZE,
19078f8b3a2SJan Glauber 		.cra_module	=	THIS_MODULE,
19178f8b3a2SJan Glauber 	}
192648b2a10SJussi Kivilinna }, {
193bd9d20dbSAdrian-Ken Rueegsegger 	.digestsize	=	SHA384_DIGEST_SIZE,
194ca142584SArd Biesheuvel 	.init		=	sha384_base_init,
195bf70fa9dSTim Chen 	.update		=	crypto_sha512_update,
196ca142584SArd Biesheuvel 	.final		=	sha512_final,
197ca142584SArd Biesheuvel 	.finup		=	crypto_sha512_finup,
1981f38ad83SHerbert Xu 	.descsize	=	sizeof(struct sha512_state),
199bd9d20dbSAdrian-Ken Rueegsegger 	.base		=	{
20078f8b3a2SJan Glauber 		.cra_name	=	"sha384",
201d3295814SJussi Kivilinna 		.cra_driver_name =	"sha384-generic",
202e4789016SEric Biggers 		.cra_priority	=	100,
20378f8b3a2SJan Glauber 		.cra_blocksize	=	SHA384_BLOCK_SIZE,
20478f8b3a2SJan Glauber 		.cra_module	=	THIS_MODULE,
20578f8b3a2SJan Glauber 	}
206648b2a10SJussi Kivilinna } };
20778f8b3a2SJan Glauber 
sha512_generic_mod_init(void)2083af5b90bSKamalesh Babulal static int __init sha512_generic_mod_init(void)
20978f8b3a2SJan Glauber {
210648b2a10SJussi Kivilinna 	return crypto_register_shashes(sha512_algs, ARRAY_SIZE(sha512_algs));
21178f8b3a2SJan Glauber }
21278f8b3a2SJan Glauber 
sha512_generic_mod_fini(void)2133af5b90bSKamalesh Babulal static void __exit sha512_generic_mod_fini(void)
21478f8b3a2SJan Glauber {
215648b2a10SJussi Kivilinna 	crypto_unregister_shashes(sha512_algs, ARRAY_SIZE(sha512_algs));
21678f8b3a2SJan Glauber }
21778f8b3a2SJan Glauber 
218c4741b23SEric Biggers subsys_initcall(sha512_generic_mod_init);
2193af5b90bSKamalesh Babulal module_exit(sha512_generic_mod_fini);
22078f8b3a2SJan Glauber 
22178f8b3a2SJan Glauber MODULE_LICENSE("GPL");
22278f8b3a2SJan Glauber MODULE_DESCRIPTION("SHA-512 and SHA-384 Secure Hash Algorithms");
22378f8b3a2SJan Glauber 
2245d26a105SKees Cook MODULE_ALIAS_CRYPTO("sha384");
2253e14dcf7SMathias Krause MODULE_ALIAS_CRYPTO("sha384-generic");
2265d26a105SKees Cook MODULE_ALIAS_CRYPTO("sha512");
2273e14dcf7SMathias Krause MODULE_ALIAS_CRYPTO("sha512-generic");
228