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