xref: /openbmc/linux/lib/crypto/sha256.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1ad767ee8SHans de Goede // SPDX-License-Identifier: GPL-2.0-or-later
2ad767ee8SHans de Goede /*
3ad767ee8SHans de Goede  * SHA-256, as specified in
4ad767ee8SHans de Goede  * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf
5ad767ee8SHans de Goede  *
6ad767ee8SHans de Goede  * SHA-256 code by Jean-Luc Cooke <jlcooke@certainkey.com>.
7ad767ee8SHans de Goede  *
8ad767ee8SHans de Goede  * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
9ad767ee8SHans de Goede  * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
10ad767ee8SHans de Goede  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
11ad767ee8SHans de Goede  * Copyright (c) 2014 Red Hat Inc.
12ad767ee8SHans de Goede  */
13ad767ee8SHans de Goede 
14*6c19f3bfSHerbert Xu #include <asm/unaligned.h>
15*6c19f3bfSHerbert Xu #include <crypto/sha256_base.h>
16*6c19f3bfSHerbert Xu #include <linux/kernel.h>
179ecf5ad5SHans de Goede #include <linux/module.h>
18ad767ee8SHans de Goede #include <linux/string.h>
19ad767ee8SHans de Goede 
2063642d5cSArvind Sankar static const u32 SHA256_K[] = {
2163642d5cSArvind Sankar 	0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
2263642d5cSArvind Sankar 	0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
2363642d5cSArvind Sankar 	0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
2463642d5cSArvind Sankar 	0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
2563642d5cSArvind Sankar 	0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
2663642d5cSArvind Sankar 	0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
2763642d5cSArvind Sankar 	0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
2863642d5cSArvind Sankar 	0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
2963642d5cSArvind Sankar 	0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
3063642d5cSArvind Sankar 	0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
3163642d5cSArvind Sankar 	0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
3263642d5cSArvind Sankar 	0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
3363642d5cSArvind Sankar 	0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
3463642d5cSArvind Sankar 	0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
3563642d5cSArvind Sankar 	0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
3663642d5cSArvind Sankar 	0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
3763642d5cSArvind Sankar };
3863642d5cSArvind Sankar 
Ch(u32 x,u32 y,u32 z)39ad767ee8SHans de Goede static inline u32 Ch(u32 x, u32 y, u32 z)
40ad767ee8SHans de Goede {
41ad767ee8SHans de Goede 	return z ^ (x & (y ^ z));
42ad767ee8SHans de Goede }
43ad767ee8SHans de Goede 
Maj(u32 x,u32 y,u32 z)44ad767ee8SHans de Goede static inline u32 Maj(u32 x, u32 y, u32 z)
45ad767ee8SHans de Goede {
46ad767ee8SHans de Goede 	return (x & y) | (z & (x | y));
47ad767ee8SHans de Goede }
48ad767ee8SHans de Goede 
49ad767ee8SHans de Goede #define e0(x)       (ror32(x, 2) ^ ror32(x, 13) ^ ror32(x, 22))
50ad767ee8SHans de Goede #define e1(x)       (ror32(x, 6) ^ ror32(x, 11) ^ ror32(x, 25))
51ad767ee8SHans de Goede #define s0(x)       (ror32(x, 7) ^ ror32(x, 18) ^ (x >> 3))
52ad767ee8SHans de Goede #define s1(x)       (ror32(x, 17) ^ ror32(x, 19) ^ (x >> 10))
53ad767ee8SHans de Goede 
LOAD_OP(int I,u32 * W,const u8 * input)54ad767ee8SHans de Goede static inline void LOAD_OP(int I, u32 *W, const u8 *input)
55ad767ee8SHans de Goede {
56906a4bb9SHans de Goede 	W[I] = get_unaligned_be32((__u32 *)input + I);
57ad767ee8SHans de Goede }
58ad767ee8SHans de Goede 
BLEND_OP(int I,u32 * W)59ad767ee8SHans de Goede static inline void BLEND_OP(int I, u32 *W)
60ad767ee8SHans de Goede {
61ad767ee8SHans de Goede 	W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
62ad767ee8SHans de Goede }
63ad767ee8SHans de Goede 
6463642d5cSArvind Sankar #define SHA256_ROUND(i, a, b, c, d, e, f, g, h) do {		\
6563642d5cSArvind Sankar 	u32 t1, t2;						\
6663642d5cSArvind Sankar 	t1 = h + e1(e) + Ch(e, f, g) + SHA256_K[i] + W[i];	\
6763642d5cSArvind Sankar 	t2 = e0(a) + Maj(a, b, c);				\
6863642d5cSArvind Sankar 	d += t1;						\
6963642d5cSArvind Sankar 	h = t1 + t2;						\
7063642d5cSArvind Sankar } while (0)
7163642d5cSArvind Sankar 
sha256_transform(u32 * state,const u8 * input,u32 * W)72b8399819SArvind Sankar static void sha256_transform(u32 *state, const u8 *input, u32 *W)
73ad767ee8SHans de Goede {
7463642d5cSArvind Sankar 	u32 a, b, c, d, e, f, g, h;
75ad767ee8SHans de Goede 	int i;
76ad767ee8SHans de Goede 
77ad767ee8SHans de Goede 	/* load the input */
7818d05ca4SArvind Sankar 	for (i = 0; i < 16; i += 8) {
7918d05ca4SArvind Sankar 		LOAD_OP(i + 0, W, input);
8018d05ca4SArvind Sankar 		LOAD_OP(i + 1, W, input);
8118d05ca4SArvind Sankar 		LOAD_OP(i + 2, W, input);
8218d05ca4SArvind Sankar 		LOAD_OP(i + 3, W, input);
8318d05ca4SArvind Sankar 		LOAD_OP(i + 4, W, input);
8418d05ca4SArvind Sankar 		LOAD_OP(i + 5, W, input);
8518d05ca4SArvind Sankar 		LOAD_OP(i + 6, W, input);
8618d05ca4SArvind Sankar 		LOAD_OP(i + 7, W, input);
8718d05ca4SArvind Sankar 	}
88ad767ee8SHans de Goede 
89ad767ee8SHans de Goede 	/* now blend */
9018d05ca4SArvind Sankar 	for (i = 16; i < 64; i += 8) {
9118d05ca4SArvind Sankar 		BLEND_OP(i + 0, W);
9218d05ca4SArvind Sankar 		BLEND_OP(i + 1, W);
9318d05ca4SArvind Sankar 		BLEND_OP(i + 2, W);
9418d05ca4SArvind Sankar 		BLEND_OP(i + 3, W);
9518d05ca4SArvind Sankar 		BLEND_OP(i + 4, W);
9618d05ca4SArvind Sankar 		BLEND_OP(i + 5, W);
9718d05ca4SArvind Sankar 		BLEND_OP(i + 6, W);
9818d05ca4SArvind Sankar 		BLEND_OP(i + 7, W);
9918d05ca4SArvind Sankar 	}
100ad767ee8SHans de Goede 
101ad767ee8SHans de Goede 	/* load the state into our registers */
102ad767ee8SHans de Goede 	a = state[0];  b = state[1];  c = state[2];  d = state[3];
103ad767ee8SHans de Goede 	e = state[4];  f = state[5];  g = state[6];  h = state[7];
104ad767ee8SHans de Goede 
105ad767ee8SHans de Goede 	/* now iterate */
10663642d5cSArvind Sankar 	for (i = 0; i < 64; i += 8) {
10763642d5cSArvind Sankar 		SHA256_ROUND(i + 0, a, b, c, d, e, f, g, h);
10863642d5cSArvind Sankar 		SHA256_ROUND(i + 1, h, a, b, c, d, e, f, g);
10963642d5cSArvind Sankar 		SHA256_ROUND(i + 2, g, h, a, b, c, d, e, f);
11063642d5cSArvind Sankar 		SHA256_ROUND(i + 3, f, g, h, a, b, c, d, e);
11163642d5cSArvind Sankar 		SHA256_ROUND(i + 4, e, f, g, h, a, b, c, d);
11263642d5cSArvind Sankar 		SHA256_ROUND(i + 5, d, e, f, g, h, a, b, c);
11363642d5cSArvind Sankar 		SHA256_ROUND(i + 6, c, d, e, f, g, h, a, b);
11463642d5cSArvind Sankar 		SHA256_ROUND(i + 7, b, c, d, e, f, g, h, a);
11563642d5cSArvind Sankar 	}
116ad767ee8SHans de Goede 
117ad767ee8SHans de Goede 	state[0] += a; state[1] += b; state[2] += c; state[3] += d;
118ad767ee8SHans de Goede 	state[4] += e; state[5] += f; state[6] += g; state[7] += h;
119ad767ee8SHans de Goede }
120ad767ee8SHans de Goede 
sha256_transform_blocks(struct sha256_state * sctx,const u8 * input,int blocks)121*6c19f3bfSHerbert Xu static void sha256_transform_blocks(struct sha256_state *sctx,
122*6c19f3bfSHerbert Xu 				    const u8 *input, int blocks)
123ad767ee8SHans de Goede {
124b8399819SArvind Sankar 	u32 W[64];
125ad767ee8SHans de Goede 
126ad767ee8SHans de Goede 	do {
127*6c19f3bfSHerbert Xu 		sha256_transform(sctx->state, input, W);
128*6c19f3bfSHerbert Xu 		input += SHA256_BLOCK_SIZE;
129*6c19f3bfSHerbert Xu 	} while (--blocks);
130ad767ee8SHans de Goede 
131b8399819SArvind Sankar 	memzero_explicit(W, sizeof(W));
132ad767ee8SHans de Goede }
133*6c19f3bfSHerbert Xu 
sha256_update(struct sha256_state * sctx,const u8 * data,unsigned int len)134*6c19f3bfSHerbert Xu void sha256_update(struct sha256_state *sctx, const u8 *data, unsigned int len)
135*6c19f3bfSHerbert Xu {
136*6c19f3bfSHerbert Xu 	lib_sha256_base_do_update(sctx, data, len, sha256_transform_blocks);
137ad767ee8SHans de Goede }
13801d3aee8SHans de Goede EXPORT_SYMBOL(sha256_update);
139ad767ee8SHans de Goede 
__sha256_final(struct sha256_state * sctx,u8 * out,int digest_size)140*6c19f3bfSHerbert Xu static void __sha256_final(struct sha256_state *sctx, u8 *out, int digest_size)
141ad767ee8SHans de Goede {
142*6c19f3bfSHerbert Xu 	lib_sha256_base_do_finalize(sctx, sha256_transform_blocks);
143*6c19f3bfSHerbert Xu 	lib_sha256_base_finish(sctx, out, digest_size);
144ad767ee8SHans de Goede }
1457d2f5b0cSHans de Goede 
sha256_final(struct sha256_state * sctx,u8 * out)14613855fd8SEric Biggers void sha256_final(struct sha256_state *sctx, u8 *out)
1477d2f5b0cSHans de Goede {
148*6c19f3bfSHerbert Xu 	__sha256_final(sctx, out, 32);
1497d2f5b0cSHans de Goede }
15001d3aee8SHans de Goede EXPORT_SYMBOL(sha256_final);
1517d2f5b0cSHans de Goede 
sha224_final(struct sha256_state * sctx,u8 * out)15213855fd8SEric Biggers void sha224_final(struct sha256_state *sctx, u8 *out)
1537d2f5b0cSHans de Goede {
154*6c19f3bfSHerbert Xu 	__sha256_final(sctx, out, 28);
1557d2f5b0cSHans de Goede }
1567d2f5b0cSHans de Goede EXPORT_SYMBOL(sha224_final);
1579ecf5ad5SHans de Goede 
sha256(const u8 * data,unsigned int len,u8 * out)1589ea9c58bSEric Biggers void sha256(const u8 *data, unsigned int len, u8 *out)
1599ea9c58bSEric Biggers {
1609ea9c58bSEric Biggers 	struct sha256_state sctx;
1619ea9c58bSEric Biggers 
1629ea9c58bSEric Biggers 	sha256_init(&sctx);
1639ea9c58bSEric Biggers 	sha256_update(&sctx, data, len);
1649ea9c58bSEric Biggers 	sha256_final(&sctx, out);
1659ea9c58bSEric Biggers }
1669ea9c58bSEric Biggers EXPORT_SYMBOL(sha256);
1679ea9c58bSEric Biggers 
1689ecf5ad5SHans de Goede MODULE_LICENSE("GPL");
169