xref: /freebsd/contrib/wpa/src/crypto/sha512-internal.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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  */
sha512_vector(size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)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 
101780fb4a2SCy Schubert #define ROR64c(x, y) \
102780fb4a2SCy Schubert     ( ((((x) & CONST64(0xFFFFFFFFFFFFFFFF)) >> ((u64) (y) & CONST64(63))) | \
103780fb4a2SCy Schubert       ((x) << ((u64) (64 - ((y) & CONST64(63)))))) & \
104780fb4a2SCy Schubert       CONST64(0xFFFFFFFFFFFFFFFF))
105780fb4a2SCy Schubert 
106780fb4a2SCy Schubert /* compress 1024-bits */
sha512_compress(struct sha512_state * md,unsigned char * buf)107780fb4a2SCy Schubert static int sha512_compress(struct sha512_state *md, unsigned char *buf)
108780fb4a2SCy Schubert {
109*4bc52338SCy Schubert 	u64 S[8], t0, t1;
110*4bc52338SCy Schubert 	u64 *W;
111780fb4a2SCy Schubert 	int i;
112780fb4a2SCy Schubert 
113*4bc52338SCy Schubert 	W = os_malloc(80 * sizeof(u64));
114*4bc52338SCy Schubert 	if (!W)
115*4bc52338SCy Schubert 		return -1;
116*4bc52338SCy Schubert 
117780fb4a2SCy Schubert 	/* copy state into S */
118780fb4a2SCy Schubert 	for (i = 0; i < 8; i++) {
119780fb4a2SCy Schubert 		S[i] = md->state[i];
120780fb4a2SCy Schubert 	}
121780fb4a2SCy Schubert 
122780fb4a2SCy Schubert 	/* copy the state into 1024-bits into W[0..15] */
123780fb4a2SCy Schubert 	for (i = 0; i < 16; i++)
124780fb4a2SCy Schubert 		W[i] = WPA_GET_BE64(buf + (8 * i));
125780fb4a2SCy Schubert 
126780fb4a2SCy Schubert 	/* fill W[16..79] */
127780fb4a2SCy Schubert 	for (i = 16; i < 80; i++) {
128780fb4a2SCy Schubert 		W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
129780fb4a2SCy Schubert 			W[i - 16];
130780fb4a2SCy Schubert 	}
131780fb4a2SCy Schubert 
132780fb4a2SCy Schubert 	/* Compress */
133780fb4a2SCy Schubert 	for (i = 0; i < 80; i++) {
134780fb4a2SCy Schubert 		t0 = S[7] + Sigma1(S[4]) + Ch(S[4], S[5], S[6]) + K[i] + W[i];
135780fb4a2SCy Schubert 		t1 = Sigma0(S[0]) + Maj(S[0], S[1], S[2]);
136780fb4a2SCy Schubert 		S[7] = S[6];
137780fb4a2SCy Schubert 		S[6] = S[5];
138780fb4a2SCy Schubert 		S[5] = S[4];
139780fb4a2SCy Schubert 		S[4] = S[3] + t0;
140780fb4a2SCy Schubert 		S[3] = S[2];
141780fb4a2SCy Schubert 		S[2] = S[1];
142780fb4a2SCy Schubert 		S[1] = S[0];
143780fb4a2SCy Schubert 		S[0] = t0 + t1;
144780fb4a2SCy Schubert 	}
145780fb4a2SCy Schubert 
146780fb4a2SCy Schubert 	/* feedback */
147780fb4a2SCy Schubert 	for (i = 0; i < 8; i++) {
148780fb4a2SCy Schubert 		md->state[i] = md->state[i] + S[i];
149780fb4a2SCy Schubert 	}
150780fb4a2SCy Schubert 
151*4bc52338SCy Schubert 	os_free(W);
152780fb4a2SCy Schubert 	return 0;
153780fb4a2SCy Schubert }
154780fb4a2SCy Schubert 
155780fb4a2SCy Schubert 
156780fb4a2SCy Schubert /**
157780fb4a2SCy Schubert    Initialize the hash state
158780fb4a2SCy Schubert    @param md   The hash state you wish to initialize
159780fb4a2SCy Schubert    @return CRYPT_OK if successful
160780fb4a2SCy Schubert */
sha512_init(struct sha512_state * md)161780fb4a2SCy Schubert void sha512_init(struct sha512_state *md)
162780fb4a2SCy Schubert {
163780fb4a2SCy Schubert 	md->curlen = 0;
164780fb4a2SCy Schubert 	md->length = 0;
165780fb4a2SCy Schubert 	md->state[0] = CONST64(0x6a09e667f3bcc908);
166780fb4a2SCy Schubert 	md->state[1] = CONST64(0xbb67ae8584caa73b);
167780fb4a2SCy Schubert 	md->state[2] = CONST64(0x3c6ef372fe94f82b);
168780fb4a2SCy Schubert 	md->state[3] = CONST64(0xa54ff53a5f1d36f1);
169780fb4a2SCy Schubert 	md->state[4] = CONST64(0x510e527fade682d1);
170780fb4a2SCy Schubert 	md->state[5] = CONST64(0x9b05688c2b3e6c1f);
171780fb4a2SCy Schubert 	md->state[6] = CONST64(0x1f83d9abfb41bd6b);
172780fb4a2SCy Schubert 	md->state[7] = CONST64(0x5be0cd19137e2179);
173780fb4a2SCy Schubert }
174780fb4a2SCy Schubert 
175780fb4a2SCy Schubert 
176780fb4a2SCy Schubert /**
177780fb4a2SCy Schubert    Process a block of memory though the hash
178780fb4a2SCy Schubert    @param md     The hash state
179780fb4a2SCy Schubert    @param in     The data to hash
180780fb4a2SCy Schubert    @param inlen  The length of the data (octets)
181780fb4a2SCy Schubert    @return CRYPT_OK if successful
182780fb4a2SCy Schubert */
sha512_process(struct sha512_state * md,const unsigned char * in,unsigned long inlen)183780fb4a2SCy Schubert int sha512_process(struct sha512_state *md, const unsigned char *in,
184780fb4a2SCy Schubert 		   unsigned long inlen)
185780fb4a2SCy Schubert {
186780fb4a2SCy Schubert 	unsigned long n;
187780fb4a2SCy Schubert 
188780fb4a2SCy Schubert 	if (md->curlen >= sizeof(md->buf))
189780fb4a2SCy Schubert 		return -1;
190780fb4a2SCy Schubert 
191780fb4a2SCy Schubert 	while (inlen > 0) {
192780fb4a2SCy Schubert 		if (md->curlen == 0 && inlen >= SHA512_BLOCK_SIZE) {
193780fb4a2SCy Schubert 			if (sha512_compress(md, (unsigned char *) in) < 0)
194780fb4a2SCy Schubert 				return -1;
195780fb4a2SCy Schubert 			md->length += SHA512_BLOCK_SIZE * 8;
196780fb4a2SCy Schubert 			in += SHA512_BLOCK_SIZE;
197780fb4a2SCy Schubert 			inlen -= SHA512_BLOCK_SIZE;
198780fb4a2SCy Schubert 		} else {
199780fb4a2SCy Schubert 			n = MIN(inlen, (SHA512_BLOCK_SIZE - md->curlen));
200780fb4a2SCy Schubert 			os_memcpy(md->buf + md->curlen, in, n);
201780fb4a2SCy Schubert 			md->curlen += n;
202780fb4a2SCy Schubert 			in += n;
203780fb4a2SCy Schubert 			inlen -= n;
204780fb4a2SCy Schubert 			if (md->curlen == SHA512_BLOCK_SIZE) {
205780fb4a2SCy Schubert 				if (sha512_compress(md, md->buf) < 0)
206780fb4a2SCy Schubert 					return -1;
207780fb4a2SCy Schubert 				md->length += 8 * SHA512_BLOCK_SIZE;
208780fb4a2SCy Schubert 				md->curlen = 0;
209780fb4a2SCy Schubert 			}
210780fb4a2SCy Schubert 		}
211780fb4a2SCy Schubert 	}
212780fb4a2SCy Schubert 
213780fb4a2SCy Schubert 	return 0;
214780fb4a2SCy Schubert }
215780fb4a2SCy Schubert 
216780fb4a2SCy Schubert 
217780fb4a2SCy Schubert /**
218780fb4a2SCy Schubert    Terminate the hash to get the digest
219780fb4a2SCy Schubert    @param md  The hash state
220780fb4a2SCy Schubert    @param out [out] The destination of the hash (64 bytes)
221780fb4a2SCy Schubert    @return CRYPT_OK if successful
222780fb4a2SCy Schubert */
sha512_done(struct sha512_state * md,unsigned char * out)223780fb4a2SCy Schubert int sha512_done(struct sha512_state *md, unsigned char *out)
224780fb4a2SCy Schubert {
225780fb4a2SCy Schubert 	int i;
226780fb4a2SCy Schubert 
227780fb4a2SCy Schubert 	if (md->curlen >= sizeof(md->buf))
228780fb4a2SCy Schubert 		return -1;
229780fb4a2SCy Schubert 
230780fb4a2SCy Schubert 	/* increase the length of the message */
231780fb4a2SCy Schubert 	md->length += md->curlen * CONST64(8);
232780fb4a2SCy Schubert 
233780fb4a2SCy Schubert 	/* append the '1' bit */
234780fb4a2SCy Schubert 	md->buf[md->curlen++] = (unsigned char) 0x80;
235780fb4a2SCy Schubert 
236780fb4a2SCy Schubert 	/* if the length is currently above 112 bytes we append zeros
237780fb4a2SCy Schubert 	 * then compress.  Then we can fall back to padding zeros and length
238780fb4a2SCy Schubert 	 * encoding like normal.
239780fb4a2SCy Schubert 	 */
240780fb4a2SCy Schubert 	if (md->curlen > 112) {
241780fb4a2SCy Schubert 		while (md->curlen < 128) {
242780fb4a2SCy Schubert 			md->buf[md->curlen++] = (unsigned char) 0;
243780fb4a2SCy Schubert 		}
244780fb4a2SCy Schubert 		sha512_compress(md, md->buf);
245780fb4a2SCy Schubert 		md->curlen = 0;
246780fb4a2SCy Schubert 	}
247780fb4a2SCy Schubert 
248780fb4a2SCy Schubert 	/* pad up to 120 bytes of zeroes
249780fb4a2SCy Schubert 	 * note: that from 112 to 120 is the 64 MSB of the length.  We assume
250780fb4a2SCy Schubert 	 * that you won't hash > 2^64 bits of data... :-)
251780fb4a2SCy Schubert 	 */
252780fb4a2SCy Schubert 	while (md->curlen < 120) {
253780fb4a2SCy Schubert 		md->buf[md->curlen++] = (unsigned char) 0;
254780fb4a2SCy Schubert 	}
255780fb4a2SCy Schubert 
256780fb4a2SCy Schubert 	/* store length */
257780fb4a2SCy Schubert 	WPA_PUT_BE64(md->buf + 120, md->length);
258780fb4a2SCy Schubert 	sha512_compress(md, md->buf);
259780fb4a2SCy Schubert 
260780fb4a2SCy Schubert 	/* copy output */
261780fb4a2SCy Schubert 	for (i = 0; i < 8; i++)
262780fb4a2SCy Schubert 		WPA_PUT_BE64(out + (8 * i), md->state[i]);
263780fb4a2SCy Schubert 
264780fb4a2SCy Schubert 	return 0;
265780fb4a2SCy Schubert }
266780fb4a2SCy Schubert 
267780fb4a2SCy Schubert /* ===== end - public domain SHA512 implementation ===== */
268