xref: /freebsd/contrib/wpa/src/crypto/sha256-internal.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * SHA-256 hash implementation and interface functions
3f05cddf9SRui Paulo  * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #include "common.h"
12e28a4053SRui Paulo #include "sha256.h"
13f05cddf9SRui Paulo #include "sha256_i.h"
14e28a4053SRui Paulo #include "crypto.h"
15e28a4053SRui Paulo 
16e28a4053SRui Paulo 
17e28a4053SRui Paulo /**
18e28a4053SRui Paulo  * sha256_vector - SHA256 hash for data vector
19e28a4053SRui Paulo  * @num_elem: Number of elements in the data vector
20e28a4053SRui Paulo  * @addr: Pointers to the data areas
21e28a4053SRui Paulo  * @len: Lengths of the data blocks
22e28a4053SRui Paulo  * @mac: Buffer for the hash
23e28a4053SRui Paulo  * Returns: 0 on success, -1 of failure
24e28a4053SRui Paulo  */
sha256_vector(size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)25e28a4053SRui Paulo int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
26e28a4053SRui Paulo 		  u8 *mac)
27e28a4053SRui Paulo {
28e28a4053SRui Paulo 	struct sha256_state ctx;
29e28a4053SRui Paulo 	size_t i;
30e28a4053SRui Paulo 
31*780fb4a2SCy Schubert 	if (TEST_FAIL())
32*780fb4a2SCy Schubert 		return -1;
33*780fb4a2SCy Schubert 
34e28a4053SRui Paulo 	sha256_init(&ctx);
35e28a4053SRui Paulo 	for (i = 0; i < num_elem; i++)
36e28a4053SRui Paulo 		if (sha256_process(&ctx, addr[i], len[i]))
37e28a4053SRui Paulo 			return -1;
38e28a4053SRui Paulo 	if (sha256_done(&ctx, mac))
39e28a4053SRui Paulo 		return -1;
40e28a4053SRui Paulo 	return 0;
41e28a4053SRui Paulo }
42e28a4053SRui Paulo 
43e28a4053SRui Paulo 
44e28a4053SRui Paulo /* ===== start - public domain SHA256 implementation ===== */
45e28a4053SRui Paulo 
46e28a4053SRui Paulo /* This is based on SHA256 implementation in LibTomCrypt that was released into
47e28a4053SRui Paulo  * public domain by Tom St Denis. */
48e28a4053SRui Paulo 
49e28a4053SRui Paulo /* the K array */
50e28a4053SRui Paulo static const unsigned long K[64] = {
51e28a4053SRui Paulo 	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
52e28a4053SRui Paulo 	0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
53e28a4053SRui Paulo 	0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
54e28a4053SRui Paulo 	0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
55e28a4053SRui Paulo 	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
56e28a4053SRui Paulo 	0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
57e28a4053SRui Paulo 	0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
58e28a4053SRui Paulo 	0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
59e28a4053SRui Paulo 	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
60e28a4053SRui Paulo 	0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
61e28a4053SRui Paulo 	0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
62e28a4053SRui Paulo 	0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
63e28a4053SRui Paulo 	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
64e28a4053SRui Paulo };
65e28a4053SRui Paulo 
66e28a4053SRui Paulo 
67e28a4053SRui Paulo /* Various logical functions */
68e28a4053SRui Paulo #define RORc(x, y) \
69e28a4053SRui Paulo ( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
70e28a4053SRui Paulo    ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
71e28a4053SRui Paulo #define Ch(x,y,z)       (z ^ (x & (y ^ z)))
72e28a4053SRui Paulo #define Maj(x,y,z)      (((x | y) & z) | (x & y))
73e28a4053SRui Paulo #define S(x, n)         RORc((x), (n))
74e28a4053SRui Paulo #define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
75e28a4053SRui Paulo #define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
76e28a4053SRui Paulo #define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
77e28a4053SRui Paulo #define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
78e28a4053SRui Paulo #define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
79e28a4053SRui Paulo 
80e28a4053SRui Paulo /* compress 512-bits */
sha256_compress(struct sha256_state * md,unsigned char * buf)81e28a4053SRui Paulo static int sha256_compress(struct sha256_state *md, unsigned char *buf)
82e28a4053SRui Paulo {
83e28a4053SRui Paulo 	u32 S[8], W[64], t0, t1;
84e28a4053SRui Paulo 	u32 t;
85e28a4053SRui Paulo 	int i;
86e28a4053SRui Paulo 
87e28a4053SRui Paulo 	/* copy state into S */
88e28a4053SRui Paulo 	for (i = 0; i < 8; i++) {
89e28a4053SRui Paulo 		S[i] = md->state[i];
90e28a4053SRui Paulo 	}
91e28a4053SRui Paulo 
92e28a4053SRui Paulo 	/* copy the state into 512-bits into W[0..15] */
93e28a4053SRui Paulo 	for (i = 0; i < 16; i++)
94e28a4053SRui Paulo 		W[i] = WPA_GET_BE32(buf + (4 * i));
95e28a4053SRui Paulo 
96e28a4053SRui Paulo 	/* fill W[16..63] */
97e28a4053SRui Paulo 	for (i = 16; i < 64; i++) {
98e28a4053SRui Paulo 		W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
99e28a4053SRui Paulo 			W[i - 16];
100e28a4053SRui Paulo 	}
101e28a4053SRui Paulo 
102e28a4053SRui Paulo 	/* Compress */
103e28a4053SRui Paulo #define RND(a,b,c,d,e,f,g,h,i)                          \
104e28a4053SRui Paulo 	t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];	\
105e28a4053SRui Paulo 	t1 = Sigma0(a) + Maj(a, b, c);			\
106e28a4053SRui Paulo 	d += t0;					\
107e28a4053SRui Paulo 	h  = t0 + t1;
108e28a4053SRui Paulo 
109e28a4053SRui Paulo 	for (i = 0; i < 64; ++i) {
110e28a4053SRui Paulo 		RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
111e28a4053SRui Paulo 		t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
112e28a4053SRui Paulo 		S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
113e28a4053SRui Paulo 	}
114e28a4053SRui Paulo 
115e28a4053SRui Paulo 	/* feedback */
116e28a4053SRui Paulo 	for (i = 0; i < 8; i++) {
117e28a4053SRui Paulo 		md->state[i] = md->state[i] + S[i];
118e28a4053SRui Paulo 	}
119e28a4053SRui Paulo 	return 0;
120e28a4053SRui Paulo }
121e28a4053SRui Paulo 
122e28a4053SRui Paulo 
123e28a4053SRui Paulo /* Initialize the hash state */
sha256_init(struct sha256_state * md)124f05cddf9SRui Paulo void sha256_init(struct sha256_state *md)
125e28a4053SRui Paulo {
126e28a4053SRui Paulo 	md->curlen = 0;
127e28a4053SRui Paulo 	md->length = 0;
128e28a4053SRui Paulo 	md->state[0] = 0x6A09E667UL;
129e28a4053SRui Paulo 	md->state[1] = 0xBB67AE85UL;
130e28a4053SRui Paulo 	md->state[2] = 0x3C6EF372UL;
131e28a4053SRui Paulo 	md->state[3] = 0xA54FF53AUL;
132e28a4053SRui Paulo 	md->state[4] = 0x510E527FUL;
133e28a4053SRui Paulo 	md->state[5] = 0x9B05688CUL;
134e28a4053SRui Paulo 	md->state[6] = 0x1F83D9ABUL;
135e28a4053SRui Paulo 	md->state[7] = 0x5BE0CD19UL;
136e28a4053SRui Paulo }
137e28a4053SRui Paulo 
138e28a4053SRui Paulo /**
139e28a4053SRui Paulo    Process a block of memory though the hash
140e28a4053SRui Paulo    @param md     The hash state
141e28a4053SRui Paulo    @param in     The data to hash
142e28a4053SRui Paulo    @param inlen  The length of the data (octets)
143e28a4053SRui Paulo    @return CRYPT_OK if successful
144e28a4053SRui Paulo */
sha256_process(struct sha256_state * md,const unsigned char * in,unsigned long inlen)145f05cddf9SRui Paulo int sha256_process(struct sha256_state *md, const unsigned char *in,
146e28a4053SRui Paulo 		   unsigned long inlen)
147e28a4053SRui Paulo {
148e28a4053SRui Paulo 	unsigned long n;
149e28a4053SRui Paulo 
150f05cddf9SRui Paulo 	if (md->curlen >= sizeof(md->buf))
151e28a4053SRui Paulo 		return -1;
152e28a4053SRui Paulo 
153e28a4053SRui Paulo 	while (inlen > 0) {
154f05cddf9SRui Paulo 		if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) {
155e28a4053SRui Paulo 			if (sha256_compress(md, (unsigned char *) in) < 0)
156e28a4053SRui Paulo 				return -1;
157f05cddf9SRui Paulo 			md->length += SHA256_BLOCK_SIZE * 8;
158f05cddf9SRui Paulo 			in += SHA256_BLOCK_SIZE;
159f05cddf9SRui Paulo 			inlen -= SHA256_BLOCK_SIZE;
160e28a4053SRui Paulo 		} else {
161f05cddf9SRui Paulo 			n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen));
162e28a4053SRui Paulo 			os_memcpy(md->buf + md->curlen, in, n);
163e28a4053SRui Paulo 			md->curlen += n;
164e28a4053SRui Paulo 			in += n;
165e28a4053SRui Paulo 			inlen -= n;
166f05cddf9SRui Paulo 			if (md->curlen == SHA256_BLOCK_SIZE) {
167e28a4053SRui Paulo 				if (sha256_compress(md, md->buf) < 0)
168e28a4053SRui Paulo 					return -1;
169f05cddf9SRui Paulo 				md->length += 8 * SHA256_BLOCK_SIZE;
170e28a4053SRui Paulo 				md->curlen = 0;
171e28a4053SRui Paulo 			}
172e28a4053SRui Paulo 		}
173e28a4053SRui Paulo 	}
174e28a4053SRui Paulo 
175e28a4053SRui Paulo 	return 0;
176e28a4053SRui Paulo }
177e28a4053SRui Paulo 
178e28a4053SRui Paulo 
179e28a4053SRui Paulo /**
180e28a4053SRui Paulo    Terminate the hash to get the digest
181e28a4053SRui Paulo    @param md  The hash state
182e28a4053SRui Paulo    @param out [out] The destination of the hash (32 bytes)
183e28a4053SRui Paulo    @return CRYPT_OK if successful
184e28a4053SRui Paulo */
sha256_done(struct sha256_state * md,unsigned char * out)185f05cddf9SRui Paulo int sha256_done(struct sha256_state *md, unsigned char *out)
186e28a4053SRui Paulo {
187e28a4053SRui Paulo 	int i;
188e28a4053SRui Paulo 
189e28a4053SRui Paulo 	if (md->curlen >= sizeof(md->buf))
190e28a4053SRui Paulo 		return -1;
191e28a4053SRui Paulo 
192e28a4053SRui Paulo 	/* increase the length of the message */
193e28a4053SRui Paulo 	md->length += md->curlen * 8;
194e28a4053SRui Paulo 
195e28a4053SRui Paulo 	/* append the '1' bit */
196e28a4053SRui Paulo 	md->buf[md->curlen++] = (unsigned char) 0x80;
197e28a4053SRui Paulo 
198e28a4053SRui Paulo 	/* if the length is currently above 56 bytes we append zeros
199e28a4053SRui Paulo 	 * then compress.  Then we can fall back to padding zeros and length
200e28a4053SRui Paulo 	 * encoding like normal.
201e28a4053SRui Paulo 	 */
202e28a4053SRui Paulo 	if (md->curlen > 56) {
203f05cddf9SRui Paulo 		while (md->curlen < SHA256_BLOCK_SIZE) {
204e28a4053SRui Paulo 			md->buf[md->curlen++] = (unsigned char) 0;
205e28a4053SRui Paulo 		}
206e28a4053SRui Paulo 		sha256_compress(md, md->buf);
207e28a4053SRui Paulo 		md->curlen = 0;
208e28a4053SRui Paulo 	}
209e28a4053SRui Paulo 
210e28a4053SRui Paulo 	/* pad up to 56 bytes of zeroes */
211e28a4053SRui Paulo 	while (md->curlen < 56) {
212e28a4053SRui Paulo 		md->buf[md->curlen++] = (unsigned char) 0;
213e28a4053SRui Paulo 	}
214e28a4053SRui Paulo 
215e28a4053SRui Paulo 	/* store length */
216e28a4053SRui Paulo 	WPA_PUT_BE64(md->buf + 56, md->length);
217e28a4053SRui Paulo 	sha256_compress(md, md->buf);
218e28a4053SRui Paulo 
219e28a4053SRui Paulo 	/* copy output */
220e28a4053SRui Paulo 	for (i = 0; i < 8; i++)
221e28a4053SRui Paulo 		WPA_PUT_BE32(out + (4 * i), md->state[i]);
222e28a4053SRui Paulo 
223e28a4053SRui Paulo 	return 0;
224e28a4053SRui Paulo }
225e28a4053SRui Paulo 
226e28a4053SRui Paulo /* ===== end - public domain SHA256 implementation ===== */
227