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