xref: /freebsd/contrib/wpa/src/crypto/sha512-internal.c (revision 4bc523382c7e72183c32be2c3aedecc1f5e844dd)
1780fb4a2SCy Schubert /*
2780fb4a2SCy Schubert  * SHA-512 hash implementation and interface functions
3780fb4a2SCy Schubert  * Copyright (c) 2015, Pali Rohár <pali.rohar@gmail.com>
4780fb4a2SCy Schubert  *
5780fb4a2SCy Schubert  * This software may be distributed under the terms of the BSD license.
6780fb4a2SCy Schubert  * See README for more details.
7780fb4a2SCy Schubert  */
8780fb4a2SCy Schubert 
9780fb4a2SCy Schubert #include "includes.h"
10780fb4a2SCy Schubert 
11780fb4a2SCy Schubert #include "common.h"
12780fb4a2SCy Schubert #include "sha512_i.h"
13780fb4a2SCy Schubert #include "crypto.h"
14780fb4a2SCy Schubert 
15780fb4a2SCy Schubert 
16780fb4a2SCy Schubert /**
17780fb4a2SCy Schubert  * sha512_vector - SHA512 hash for data vector
18780fb4a2SCy Schubert  * @num_elem: Number of elements in the data vector
19780fb4a2SCy Schubert  * @addr: Pointers to the data areas
20780fb4a2SCy Schubert  * @len: Lengths of the data blocks
21780fb4a2SCy Schubert  * @mac: Buffer for the hash
22780fb4a2SCy Schubert  * Returns: 0 on success, -1 of failure
23780fb4a2SCy Schubert  */
24780fb4a2SCy Schubert int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
25780fb4a2SCy Schubert 		  u8 *mac)
26780fb4a2SCy Schubert {
27780fb4a2SCy Schubert 	struct sha512_state ctx;
28780fb4a2SCy Schubert 	size_t i;
29780fb4a2SCy Schubert 
30780fb4a2SCy Schubert 	sha512_init(&ctx);
31780fb4a2SCy Schubert 	for (i = 0; i < num_elem; i++)
32780fb4a2SCy Schubert 		if (sha512_process(&ctx, addr[i], len[i]))
33780fb4a2SCy Schubert 			return -1;
34780fb4a2SCy Schubert 	if (sha512_done(&ctx, mac))
35780fb4a2SCy Schubert 		return -1;
36780fb4a2SCy Schubert 	return 0;
37780fb4a2SCy Schubert }
38780fb4a2SCy Schubert 
39780fb4a2SCy Schubert 
40780fb4a2SCy Schubert /* ===== start - public domain SHA512 implementation ===== */
41780fb4a2SCy Schubert 
42780fb4a2SCy Schubert /* This is based on SHA512 implementation in LibTomCrypt that was released into
43780fb4a2SCy Schubert  * public domain by Tom St Denis. */
44780fb4a2SCy Schubert 
45780fb4a2SCy Schubert #define CONST64(n) n ## ULL
46780fb4a2SCy Schubert 
47780fb4a2SCy Schubert /* the K array */
48780fb4a2SCy Schubert static const u64 K[80] = {
49780fb4a2SCy Schubert 	CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
50780fb4a2SCy Schubert 	CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
51780fb4a2SCy Schubert 	CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
52780fb4a2SCy Schubert 	CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
53780fb4a2SCy Schubert 	CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
54780fb4a2SCy Schubert 	CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
55780fb4a2SCy Schubert 	CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
56780fb4a2SCy Schubert 	CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
57780fb4a2SCy Schubert 	CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
58780fb4a2SCy Schubert 	CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
59780fb4a2SCy Schubert 	CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
60780fb4a2SCy Schubert 	CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
61780fb4a2SCy Schubert 	CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
62780fb4a2SCy Schubert 	CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
63780fb4a2SCy Schubert 	CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
64780fb4a2SCy Schubert 	CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
65780fb4a2SCy Schubert 	CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
66780fb4a2SCy Schubert 	CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
67780fb4a2SCy Schubert 	CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
68780fb4a2SCy Schubert 	CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
69780fb4a2SCy Schubert 	CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
70780fb4a2SCy Schubert 	CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
71780fb4a2SCy Schubert 	CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
72780fb4a2SCy Schubert 	CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
73780fb4a2SCy Schubert 	CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
74780fb4a2SCy Schubert 	CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
75780fb4a2SCy Schubert 	CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
76780fb4a2SCy Schubert 	CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
77780fb4a2SCy Schubert 	CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
78780fb4a2SCy Schubert 	CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
79780fb4a2SCy Schubert 	CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
80780fb4a2SCy Schubert 	CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
81780fb4a2SCy Schubert 	CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
82780fb4a2SCy Schubert 	CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
83780fb4a2SCy Schubert 	CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
84780fb4a2SCy Schubert 	CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
85780fb4a2SCy Schubert 	CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
86780fb4a2SCy Schubert 	CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
87780fb4a2SCy Schubert 	CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
88780fb4a2SCy Schubert 	CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)
89780fb4a2SCy Schubert };
90780fb4a2SCy Schubert 
91780fb4a2SCy Schubert /* Various logical functions */
92780fb4a2SCy Schubert #define Ch(x,y,z)       (z ^ (x & (y ^ z)))
93780fb4a2SCy Schubert #define Maj(x,y,z)      (((x | y) & z) | (x & y))
94780fb4a2SCy Schubert #define S(x, n)         ROR64c(x, n)
95780fb4a2SCy Schubert #define R(x, n)         (((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) n))
96780fb4a2SCy Schubert #define Sigma0(x)       (S(x, 28) ^ S(x, 34) ^ S(x, 39))
97780fb4a2SCy Schubert #define Sigma1(x)       (S(x, 14) ^ S(x, 18) ^ S(x, 41))
98780fb4a2SCy Schubert #define Gamma0(x)       (S(x, 1) ^ S(x, 8) ^ R(x, 7))
99780fb4a2SCy Schubert #define Gamma1(x)       (S(x, 19) ^ S(x, 61) ^ R(x, 6))
100780fb4a2SCy Schubert #ifndef MIN
101780fb4a2SCy Schubert #define MIN(x, y) (((x) < (y)) ? (x) : (y))
102780fb4a2SCy Schubert #endif
103780fb4a2SCy Schubert 
104780fb4a2SCy Schubert #define ROR64c(x, y) \
105780fb4a2SCy Schubert     ( ((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) (y) & CONST64(63))) | \
106780fb4a2SCy Schubert       ((x) << ((u64) (64 - ((y) & CONST64(63)))))) & \
107780fb4a2SCy Schubert       CONST64(0xFFFFFFFFFFFFFFFF))
108780fb4a2SCy Schubert 
109780fb4a2SCy Schubert /* compress 1024-bits */
110780fb4a2SCy Schubert static int sha512_compress(struct sha512_state *md, unsigned char *buf)
111780fb4a2SCy Schubert {
112*4bc52338SCy Schubert 	u64 S[8], t0, t1;
113*4bc52338SCy Schubert 	u64 *W;
114780fb4a2SCy Schubert 	int i;
115780fb4a2SCy Schubert 
116*4bc52338SCy Schubert 	W = os_malloc(80 * sizeof(u64));
117*4bc52338SCy Schubert 	if (!W)
118*4bc52338SCy Schubert 		return -1;
119*4bc52338SCy Schubert 
120780fb4a2SCy Schubert 	/* copy state into S */
121780fb4a2SCy Schubert 	for (i = 0; i < 8; i++) {
122780fb4a2SCy Schubert 		S[i] = md->state[i];
123780fb4a2SCy Schubert 	}
124780fb4a2SCy Schubert 
125780fb4a2SCy Schubert 	/* copy the state into 1024-bits into W[0..15] */
126780fb4a2SCy Schubert 	for (i = 0; i < 16; i++)
127780fb4a2SCy Schubert 		W[i] = WPA_GET_BE64(buf + (8 * i));
128780fb4a2SCy Schubert 
129780fb4a2SCy Schubert 	/* fill W[16..79] */
130780fb4a2SCy Schubert 	for (i = 16; i < 80; i++) {
131780fb4a2SCy Schubert 		W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
132780fb4a2SCy Schubert 			W[i - 16];
133780fb4a2SCy Schubert 	}
134780fb4a2SCy Schubert 
135780fb4a2SCy Schubert 	/* Compress */
136780fb4a2SCy Schubert 	for (i = 0; i < 80; i++) {
137780fb4a2SCy Schubert 		t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i];
138780fb4a2SCy Schubert 		t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]);
139780fb4a2SCy Schubert 		S[7] = S[6];
140780fb4a2SCy Schubert 		S[6] = S[5];
141780fb4a2SCy Schubert 		S[5] = S[4];
142780fb4a2SCy Schubert 		S[4] = S[3] + t0;
143780fb4a2SCy Schubert 		S[3] = S[2];
144780fb4a2SCy Schubert 		S[2] = S[1];
145780fb4a2SCy Schubert 		S[1] = S[0];
146780fb4a2SCy Schubert 		S[0] = t0 + t1;
147780fb4a2SCy Schubert 	}
148780fb4a2SCy Schubert 
149780fb4a2SCy Schubert 	/* feedback */
150780fb4a2SCy Schubert 	for (i = 0; i < 8; i++) {
151780fb4a2SCy Schubert 		md->state[i] = md->state[i] + S[i];
152780fb4a2SCy Schubert 	}
153780fb4a2SCy Schubert 
154*4bc52338SCy Schubert 	os_free(W);
155780fb4a2SCy Schubert 	return 0;
156780fb4a2SCy Schubert }
157780fb4a2SCy Schubert 
158780fb4a2SCy Schubert 
159780fb4a2SCy Schubert /**
160780fb4a2SCy Schubert    Initialize the hash state
161780fb4a2SCy Schubert    @param md   The hash state you wish to initialize
162780fb4a2SCy Schubert    @return CRYPT_OK if successful
163780fb4a2SCy Schubert */
164780fb4a2SCy Schubert void sha512_init(struct sha512_state *md)
165780fb4a2SCy Schubert {
166780fb4a2SCy Schubert 	md->curlen = 0;
167780fb4a2SCy Schubert 	md->length = 0;
168780fb4a2SCy Schubert 	md->state[0] = CONST64(0x6a09e667f3bcc908);
169780fb4a2SCy Schubert 	md->state[1] = CONST64(0xbb67ae8584caa73b);
170780fb4a2SCy Schubert 	md->state[2] = CONST64(0x3c6ef372fe94f82b);
171780fb4a2SCy Schubert 	md->state[3] = CONST64(0xa54ff53a5f1d36f1);
172780fb4a2SCy Schubert 	md->state[4] = CONST64(0x510e527fade682d1);
173780fb4a2SCy Schubert 	md->state[5] = CONST64(0x9b05688c2b3e6c1f);
174780fb4a2SCy Schubert 	md->state[6] = CONST64(0x1f83d9abfb41bd6b);
175780fb4a2SCy Schubert 	md->state[7] = CONST64(0x5be0cd19137e2179);
176780fb4a2SCy Schubert }
177780fb4a2SCy Schubert 
178780fb4a2SCy Schubert 
179780fb4a2SCy Schubert /**
180780fb4a2SCy Schubert    Process a block of memory though the hash
181780fb4a2SCy Schubert    @param md     The hash state
182780fb4a2SCy Schubert    @param in     The data to hash
183780fb4a2SCy Schubert    @param inlen  The length of the data (octets)
184780fb4a2SCy Schubert    @return CRYPT_OK if successful
185780fb4a2SCy Schubert */
186780fb4a2SCy Schubert int sha512_process(struct sha512_state *md, const unsigned char *in,
187780fb4a2SCy Schubert 		   unsigned long inlen)
188780fb4a2SCy Schubert {
189780fb4a2SCy Schubert 	unsigned long n;
190780fb4a2SCy Schubert 
191780fb4a2SCy Schubert 	if (md->curlen >= sizeof(md->buf))
192780fb4a2SCy Schubert 		return -1;
193780fb4a2SCy Schubert 
194780fb4a2SCy Schubert 	while (inlen > 0) {
195780fb4a2SCy Schubert 		if (md->curlen == 0 && inlen >= SHA512_BLOCK_SIZE) {
196780fb4a2SCy Schubert 			if (sha512_compress(md, (unsigned char *) in) < 0)
197780fb4a2SCy Schubert 				return -1;
198780fb4a2SCy Schubert 			md->length += SHA512_BLOCK_SIZE * 8;
199780fb4a2SCy Schubert 			in += SHA512_BLOCK_SIZE;
200780fb4a2SCy Schubert 			inlen -= SHA512_BLOCK_SIZE;
201780fb4a2SCy Schubert 		} else {
202780fb4a2SCy Schubert 			n = MIN(inlen, (SHA512_BLOCK_SIZE - md->curlen));
203780fb4a2SCy Schubert 			os_memcpy(md->buf + md->curlen, in, n);
204780fb4a2SCy Schubert 			md->curlen += n;
205780fb4a2SCy Schubert 			in += n;
206780fb4a2SCy Schubert 			inlen -= n;
207780fb4a2SCy Schubert 			if (md->curlen == SHA512_BLOCK_SIZE) {
208780fb4a2SCy Schubert 				if (sha512_compress(md, md->buf) < 0)
209780fb4a2SCy Schubert 					return -1;
210780fb4a2SCy Schubert 				md->length += 8 * SHA512_BLOCK_SIZE;
211780fb4a2SCy Schubert 				md->curlen = 0;
212780fb4a2SCy Schubert 			}
213780fb4a2SCy Schubert 		}
214780fb4a2SCy Schubert 	}
215780fb4a2SCy Schubert 
216780fb4a2SCy Schubert 	return 0;
217780fb4a2SCy Schubert }
218780fb4a2SCy Schubert 
219780fb4a2SCy Schubert 
220780fb4a2SCy Schubert /**
221780fb4a2SCy Schubert    Terminate the hash to get the digest
222780fb4a2SCy Schubert    @param md  The hash state
223780fb4a2SCy Schubert    @param out [out] The destination of the hash (64 bytes)
224780fb4a2SCy Schubert    @return CRYPT_OK if successful
225780fb4a2SCy Schubert */
226780fb4a2SCy Schubert int sha512_done(struct sha512_state *md, unsigned char *out)
227780fb4a2SCy Schubert {
228780fb4a2SCy Schubert 	int i;
229780fb4a2SCy Schubert 
230780fb4a2SCy Schubert 	if (md->curlen >= sizeof(md->buf))
231780fb4a2SCy Schubert 		return -1;
232780fb4a2SCy Schubert 
233780fb4a2SCy Schubert 	/* increase the length of the message */
234780fb4a2SCy Schubert 	md->length += md->curlen * CONST64(8);
235780fb4a2SCy Schubert 
236780fb4a2SCy Schubert 	/* append the '1' bit */
237780fb4a2SCy Schubert 	md->buf[md->curlen++] = (unsigned char) 0x80;
238780fb4a2SCy Schubert 
239780fb4a2SCy Schubert 	/* if the length is currently above 112 bytes we append zeros
240780fb4a2SCy Schubert 	 * then compress.  Then we can fall back to padding zeros and length
241780fb4a2SCy Schubert 	 * encoding like normal.
242780fb4a2SCy Schubert 	 */
243780fb4a2SCy Schubert 	if (md->curlen > 112) {
244780fb4a2SCy Schubert 		while (md->curlen < 128) {
245780fb4a2SCy Schubert 			md->buf[md->curlen++] = (unsigned char) 0;
246780fb4a2SCy Schubert 		}
247780fb4a2SCy Schubert 		sha512_compress(md, md->buf);
248780fb4a2SCy Schubert 		md->curlen = 0;
249780fb4a2SCy Schubert 	}
250780fb4a2SCy Schubert 
251780fb4a2SCy Schubert 	/* pad up to 120 bytes of zeroes
252780fb4a2SCy Schubert 	 * note: that from 112 to 120 is the 64 MSB of the length.  We assume
253780fb4a2SCy Schubert 	 * that you won't hash > 2^64 bits of data... :-)
254780fb4a2SCy Schubert 	 */
255780fb4a2SCy Schubert 	while (md->curlen < 120) {
256780fb4a2SCy Schubert 		md->buf[md->curlen++] = (unsigned char) 0;
257780fb4a2SCy Schubert 	}
258780fb4a2SCy Schubert 
259780fb4a2SCy Schubert 	/* store length */
260780fb4a2SCy Schubert 	WPA_PUT_BE64(md->buf + 120, md->length);
261780fb4a2SCy Schubert 	sha512_compress(md, md->buf);
262780fb4a2SCy Schubert 
263780fb4a2SCy Schubert 	/* copy output */
264780fb4a2SCy Schubert 	for (i = 0; i < 8; i++)
265780fb4a2SCy Schubert 		WPA_PUT_BE64(out + (8 * i), md->state[i]);
266780fb4a2SCy Schubert 
267780fb4a2SCy Schubert 	return 0;
268780fb4a2SCy Schubert }
269780fb4a2SCy Schubert 
270780fb4a2SCy Schubert /* ===== end - public domain SHA512 implementation ===== */
271