1214501Srpaulo/*
2214501Srpaulo * SHA-256 hash implementation and interface functions
3214501Srpaulo * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5214501Srpaulo * This program is free software; you can redistribute it and/or modify
6214501Srpaulo * it under the terms of the GNU General Public License version 2 as
7214501Srpaulo * published by the Free Software Foundation.
8214501Srpaulo *
9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD
10214501Srpaulo * license.
11214501Srpaulo *
12214501Srpaulo * See README and COPYING for more details.
13214501Srpaulo */
14214501Srpaulo
15214501Srpaulo#include "includes.h"
16214501Srpaulo
17214501Srpaulo#include "common.h"
18214501Srpaulo#include "sha256.h"
19214501Srpaulo#include "crypto.h"
20214501Srpaulo
21214501Srpaulostruct sha256_state {
22214501Srpaulo	u64 length;
23214501Srpaulo	u32 state[8], curlen;
24214501Srpaulo	u8 buf[64];
25214501Srpaulo};
26214501Srpaulo
27214501Srpaulostatic void sha256_init(struct sha256_state *md);
28214501Srpaulostatic int sha256_process(struct sha256_state *md, const unsigned char *in,
29214501Srpaulo			  unsigned long inlen);
30214501Srpaulostatic int sha256_done(struct sha256_state *md, unsigned char *out);
31214501Srpaulo
32214501Srpaulo
33214501Srpaulo/**
34214501Srpaulo * sha256_vector - SHA256 hash for data vector
35214501Srpaulo * @num_elem: Number of elements in the data vector
36214501Srpaulo * @addr: Pointers to the data areas
37214501Srpaulo * @len: Lengths of the data blocks
38214501Srpaulo * @mac: Buffer for the hash
39214501Srpaulo * Returns: 0 on success, -1 of failure
40214501Srpaulo */
41214501Srpauloint sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
42214501Srpaulo		  u8 *mac)
43214501Srpaulo{
44214501Srpaulo	struct sha256_state ctx;
45214501Srpaulo	size_t i;
46214501Srpaulo
47214501Srpaulo	sha256_init(&ctx);
48214501Srpaulo	for (i = 0; i < num_elem; i++)
49214501Srpaulo		if (sha256_process(&ctx, addr[i], len[i]))
50214501Srpaulo			return -1;
51214501Srpaulo	if (sha256_done(&ctx, mac))
52214501Srpaulo		return -1;
53214501Srpaulo	return 0;
54214501Srpaulo}
55214501Srpaulo
56214501Srpaulo
57214501Srpaulo/* ===== start - public domain SHA256 implementation ===== */
58214501Srpaulo
59214501Srpaulo/* This is based on SHA256 implementation in LibTomCrypt that was released into
60214501Srpaulo * public domain by Tom St Denis. */
61214501Srpaulo
62214501Srpaulo/* the K array */
63214501Srpaulostatic const unsigned long K[64] = {
64214501Srpaulo	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
65214501Srpaulo	0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
66214501Srpaulo	0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
67214501Srpaulo	0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
68214501Srpaulo	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
69214501Srpaulo	0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
70214501Srpaulo	0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
71214501Srpaulo	0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
72214501Srpaulo	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
73214501Srpaulo	0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
74214501Srpaulo	0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
75214501Srpaulo	0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
76214501Srpaulo	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
77214501Srpaulo};
78214501Srpaulo
79214501Srpaulo
80214501Srpaulo/* Various logical functions */
81214501Srpaulo#define RORc(x, y) \
82214501Srpaulo( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
83214501Srpaulo   ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
84214501Srpaulo#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
85214501Srpaulo#define Maj(x,y,z)      (((x | y) & z) | (x & y))
86214501Srpaulo#define S(x, n)         RORc((x), (n))
87214501Srpaulo#define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
88214501Srpaulo#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
89214501Srpaulo#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
90214501Srpaulo#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
91214501Srpaulo#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
92214501Srpaulo#ifndef MIN
93214501Srpaulo#define MIN(x, y) (((x) < (y)) ? (x) : (y))
94214501Srpaulo#endif
95214501Srpaulo
96214501Srpaulo/* compress 512-bits */
97214501Srpaulostatic int sha256_compress(struct sha256_state *md, unsigned char *buf)
98214501Srpaulo{
99214501Srpaulo	u32 S[8], W[64], t0, t1;
100214501Srpaulo	u32 t;
101214501Srpaulo	int i;
102214501Srpaulo
103214501Srpaulo	/* copy state into S */
104214501Srpaulo	for (i = 0; i < 8; i++) {
105214501Srpaulo		S[i] = md->state[i];
106214501Srpaulo	}
107214501Srpaulo
108214501Srpaulo	/* copy the state into 512-bits into W[0..15] */
109214501Srpaulo	for (i = 0; i < 16; i++)
110214501Srpaulo		W[i] = WPA_GET_BE32(buf + (4 * i));
111214501Srpaulo
112214501Srpaulo	/* fill W[16..63] */
113214501Srpaulo	for (i = 16; i < 64; i++) {
114214501Srpaulo		W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
115214501Srpaulo			W[i - 16];
116214501Srpaulo	}
117214501Srpaulo
118214501Srpaulo	/* Compress */
119214501Srpaulo#define RND(a,b,c,d,e,f,g,h,i)                          \
120214501Srpaulo	t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];	\
121214501Srpaulo	t1 = Sigma0(a) + Maj(a, b, c);			\
122214501Srpaulo	d += t0;					\
123214501Srpaulo	h  = t0 + t1;
124214501Srpaulo
125214501Srpaulo	for (i = 0; i < 64; ++i) {
126214501Srpaulo		RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
127214501Srpaulo		t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
128214501Srpaulo		S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
129214501Srpaulo	}
130214501Srpaulo
131214501Srpaulo	/* feedback */
132214501Srpaulo	for (i = 0; i < 8; i++) {
133214501Srpaulo		md->state[i] = md->state[i] + S[i];
134214501Srpaulo	}
135214501Srpaulo	return 0;
136214501Srpaulo}
137214501Srpaulo
138214501Srpaulo
139214501Srpaulo/* Initialize the hash state */
140214501Srpaulostatic void sha256_init(struct sha256_state *md)
141214501Srpaulo{
142214501Srpaulo	md->curlen = 0;
143214501Srpaulo	md->length = 0;
144214501Srpaulo	md->state[0] = 0x6A09E667UL;
145214501Srpaulo	md->state[1] = 0xBB67AE85UL;
146214501Srpaulo	md->state[2] = 0x3C6EF372UL;
147214501Srpaulo	md->state[3] = 0xA54FF53AUL;
148214501Srpaulo	md->state[4] = 0x510E527FUL;
149214501Srpaulo	md->state[5] = 0x9B05688CUL;
150214501Srpaulo	md->state[6] = 0x1F83D9ABUL;
151214501Srpaulo	md->state[7] = 0x5BE0CD19UL;
152214501Srpaulo}
153214501Srpaulo
154214501Srpaulo/**
155214501Srpaulo   Process a block of memory though the hash
156214501Srpaulo   @param md     The hash state
157214501Srpaulo   @param in     The data to hash
158214501Srpaulo   @param inlen  The length of the data (octets)
159214501Srpaulo   @return CRYPT_OK if successful
160214501Srpaulo*/
161214501Srpaulostatic int sha256_process(struct sha256_state *md, const unsigned char *in,
162214501Srpaulo			  unsigned long inlen)
163214501Srpaulo{
164214501Srpaulo	unsigned long n;
165214501Srpaulo#define block_size 64
166214501Srpaulo
167214501Srpaulo	if (md->curlen > sizeof(md->buf))
168214501Srpaulo		return -1;
169214501Srpaulo
170214501Srpaulo	while (inlen > 0) {
171214501Srpaulo		if (md->curlen == 0 && inlen >= block_size) {
172214501Srpaulo			if (sha256_compress(md, (unsigned char *) in) < 0)
173214501Srpaulo				return -1;
174214501Srpaulo			md->length += block_size * 8;
175214501Srpaulo			in += block_size;
176214501Srpaulo			inlen -= block_size;
177214501Srpaulo		} else {
178214501Srpaulo			n = MIN(inlen, (block_size - md->curlen));
179214501Srpaulo			os_memcpy(md->buf + md->curlen, in, n);
180214501Srpaulo			md->curlen += n;
181214501Srpaulo			in += n;
182214501Srpaulo			inlen -= n;
183214501Srpaulo			if (md->curlen == block_size) {
184214501Srpaulo				if (sha256_compress(md, md->buf) < 0)
185214501Srpaulo					return -1;
186214501Srpaulo				md->length += 8 * block_size;
187214501Srpaulo				md->curlen = 0;
188214501Srpaulo			}
189214501Srpaulo		}
190214501Srpaulo	}
191214501Srpaulo
192214501Srpaulo	return 0;
193214501Srpaulo}
194214501Srpaulo
195214501Srpaulo
196214501Srpaulo/**
197214501Srpaulo   Terminate the hash to get the digest
198214501Srpaulo   @param md  The hash state
199214501Srpaulo   @param out [out] The destination of the hash (32 bytes)
200214501Srpaulo   @return CRYPT_OK if successful
201214501Srpaulo*/
202214501Srpaulostatic int sha256_done(struct sha256_state *md, unsigned char *out)
203214501Srpaulo{
204214501Srpaulo	int i;
205214501Srpaulo
206214501Srpaulo	if (md->curlen >= sizeof(md->buf))
207214501Srpaulo		return -1;
208214501Srpaulo
209214501Srpaulo	/* increase the length of the message */
210214501Srpaulo	md->length += md->curlen * 8;
211214501Srpaulo
212214501Srpaulo	/* append the '1' bit */
213214501Srpaulo	md->buf[md->curlen++] = (unsigned char) 0x80;
214214501Srpaulo
215214501Srpaulo	/* if the length is currently above 56 bytes we append zeros
216214501Srpaulo	 * then compress.  Then we can fall back to padding zeros and length
217214501Srpaulo	 * encoding like normal.
218214501Srpaulo	 */
219214501Srpaulo	if (md->curlen > 56) {
220214501Srpaulo		while (md->curlen < 64) {
221214501Srpaulo			md->buf[md->curlen++] = (unsigned char) 0;
222214501Srpaulo		}
223214501Srpaulo		sha256_compress(md, md->buf);
224214501Srpaulo		md->curlen = 0;
225214501Srpaulo	}
226214501Srpaulo
227214501Srpaulo	/* pad upto 56 bytes of zeroes */
228214501Srpaulo	while (md->curlen < 56) {
229214501Srpaulo		md->buf[md->curlen++] = (unsigned char) 0;
230214501Srpaulo	}
231214501Srpaulo
232214501Srpaulo	/* store length */
233214501Srpaulo	WPA_PUT_BE64(md->buf + 56, md->length);
234214501Srpaulo	sha256_compress(md, md->buf);
235214501Srpaulo
236214501Srpaulo	/* copy output */
237214501Srpaulo	for (i = 0; i < 8; i++)
238214501Srpaulo		WPA_PUT_BE32(out + (4 * i), md->state[i]);
239214501Srpaulo
240214501Srpaulo	return 0;
241214501Srpaulo}
242214501Srpaulo
243214501Srpaulo/* ===== end - public domain SHA256 implementation ===== */
244