1/*
2 * sha512.c --- The sha512 algorithm
3 *
4 * Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5 * (copied from libtomcrypt and then relicensed under GPLv2)
6 *
7 * %Begin-Header%
8 * This file may be redistributed under the terms of the GNU Library
9 * General Public License, version 2.
10 * %End-Header%
11 */
12
13
14#include "config.h"
15#if HAVE_SYS_TYPES_H
16#include <sys/types.h>
17#endif
18#include "ext2fs.h"
19
20/* the K array */
21#define CONST64(n) n
22static const __u64 K[80] = {
23	CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd),
24	CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc),
25	CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019),
26	CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118),
27	CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe),
28	CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2),
29	CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1),
30	CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694),
31	CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3),
32	CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65),
33	CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483),
34	CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5),
35	CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210),
36	CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4),
37	CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725),
38	CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70),
39	CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926),
40	CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df),
41	CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8),
42	CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b),
43	CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001),
44	CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30),
45	CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910),
46	CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8),
47	CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53),
48	CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8),
49	CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb),
50	CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3),
51	CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60),
52	CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec),
53	CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9),
54	CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b),
55	CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207),
56	CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178),
57	CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6),
58	CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b),
59	CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493),
60	CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c),
61	CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a),
62	CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817)
63};
64#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
65#define Maj(x,y,z)      (((x | y) & z) | (x & y))
66#define S(x, n)         ROR64c(x, n)
67#define R(x, n)         (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)n))
68#define Sigma0(x)       (S(x, 28) ^ S(x, 34) ^ S(x, 39))
69#define Sigma1(x)       (S(x, 14) ^ S(x, 18) ^ S(x, 41))
70#define Gamma0(x)       (S(x, 1) ^ S(x, 8) ^ R(x, 7))
71#define Gamma1(x)       (S(x, 19) ^ S(x, 61) ^ R(x, 6))
72#define RND(a,b,c,d,e,f,g,h,i)\
73		t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];\
74		t1 = Sigma0(a) + Maj(a, b, c);\
75		d += t0;\
76		h  = t0 + t1;
77#define STORE64H(x, y) \
78	do { \
79		(y)[0] = (unsigned char)(((x)>>56)&255);\
80		(y)[1] = (unsigned char)(((x)>>48)&255);\
81		(y)[2] = (unsigned char)(((x)>>40)&255);\
82		(y)[3] = (unsigned char)(((x)>>32)&255);\
83		(y)[4] = (unsigned char)(((x)>>24)&255);\
84		(y)[5] = (unsigned char)(((x)>>16)&255);\
85		(y)[6] = (unsigned char)(((x)>>8)&255);\
86		(y)[7] = (unsigned char)((x)&255); } while(0)
87
88#define LOAD64H(x, y)\
89	do {x = \
90		(((__u64)((y)[0] & 255)) << 56) |\
91		(((__u64)((y)[1] & 255)) << 48) |\
92		(((__u64)((y)[2] & 255)) << 40) |\
93		(((__u64)((y)[3] & 255)) << 32) |\
94		(((__u64)((y)[4] & 255)) << 24) |\
95		(((__u64)((y)[5] & 255)) << 16) |\
96		(((__u64)((y)[6] & 255)) << 8) |\
97		(((__u64)((y)[7] & 255)));\
98	} while(0)
99
100#define ROR64c(x, y) \
101    ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)(y)&CONST64(63))) | \
102      ((x)<<((__u64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
103
104struct sha512_state {
105	__u64  length, state[8];
106	unsigned long curlen;
107	unsigned char buf[128];
108};
109
110/* This is a highly simplified version from libtomcrypt */
111struct hash_state {
112	struct sha512_state sha512;
113};
114
115static void sha512_compress(struct hash_state * md, const unsigned char *buf)
116{
117	__u64 S[8], W[80], t0, t1;
118	int i;
119
120	/* copy state into S */
121	for (i = 0; i < 8; i++) {
122		S[i] = md->sha512.state[i];
123	}
124
125	/* copy the state into 1024-bits into W[0..15] */
126	for (i = 0; i < 16; i++) {
127		LOAD64H(W[i], buf + (8*i));
128	}
129
130	/* fill W[16..79] */
131	for (i = 16; i < 80; i++) {
132		W[i] = Gamma1(W[i - 2]) + W[i - 7] +
133			Gamma0(W[i - 15]) + W[i - 16];
134	}
135
136	for (i = 0; i < 80; i += 8) {
137		RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0);
138		RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1);
139		RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2);
140		RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3);
141		RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4);
142		RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5);
143		RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6);
144		RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7);
145	}
146
147	 /* feedback */
148	for (i = 0; i < 8; i++) {
149		md->sha512.state[i] = md->sha512.state[i] + S[i];
150	}
151}
152
153static void sha512_init(struct hash_state * md)
154{
155	md->sha512.curlen = 0;
156	md->sha512.length = 0;
157	md->sha512.state[0] = CONST64(0x6a09e667f3bcc908);
158	md->sha512.state[1] = CONST64(0xbb67ae8584caa73b);
159	md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b);
160	md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1);
161	md->sha512.state[4] = CONST64(0x510e527fade682d1);
162	md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f);
163	md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b);
164	md->sha512.state[7] = CONST64(0x5be0cd19137e2179);
165}
166
167static void sha512_done(struct hash_state * md, unsigned char *out)
168{
169	int i;
170
171	/* increase the length of the message */
172	md->sha512.length += md->sha512.curlen * CONST64(8);
173
174	/* append the '1' bit */
175	md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80;
176
177	/* if the length is currently above 112 bytes we append zeros then
178	 * compress. Then we can fall back to padding zeros and length encoding
179	 * like normal. */
180	if (md->sha512.curlen > 112) {
181		while (md->sha512.curlen < 128) {
182			md->sha512.buf[md->sha512.curlen++] = (unsigned char)0;
183		}
184		sha512_compress(md, md->sha512.buf);
185		md->sha512.curlen = 0;
186	}
187
188	/* pad upto 120 bytes of zeroes note: that from 112 to 120 is the 64 MSB
189	 * of the length. We assume that you won't hash > 2^64 bits of data. */
190	while (md->sha512.curlen < 120) {
191		md->sha512.buf[md->sha512.curlen++] = (unsigned char)0;
192	}
193
194	/* store length */
195	STORE64H(md->sha512.length, md->sha512.buf + 120);
196	sha512_compress(md, md->sha512.buf);
197
198	/* copy output */
199	for (i = 0; i < 8; i++) {
200		STORE64H(md->sha512.state[i], out+(8 * i));
201	}
202}
203
204#define MIN(x, y) ( ((x)<(y))?(x):(y) )
205#define SHA512_BLOCKSIZE 128
206static void sha512_process(struct hash_state * md,
207			   const unsigned char *in,
208			   unsigned long inlen)
209{
210	unsigned long n;
211
212	while (inlen > 0) {
213		if (md->sha512.curlen == 0 && inlen >= SHA512_BLOCKSIZE) {
214			sha512_compress(md, in);
215			md->sha512.length += SHA512_BLOCKSIZE * 8;
216			in += SHA512_BLOCKSIZE;
217			inlen -= SHA512_BLOCKSIZE;
218		} else {
219			n = MIN(inlen, (SHA512_BLOCKSIZE - md->sha512.curlen));
220			memcpy(md->sha512.buf + md->sha512.curlen,
221			       in, (size_t)n);
222			md->sha512.curlen += n;
223			in += n;
224			inlen -= n;
225			if (md->sha512.curlen == SHA512_BLOCKSIZE) {
226				sha512_compress(md, md->sha512.buf);
227				md->sha512.length += SHA512_BLOCKSIZE * 8;
228				md->sha512.curlen = 0;
229			}
230		}
231	}
232}
233
234void ext2fs_sha512(const unsigned char *in, unsigned long in_size,
235		   unsigned char out[EXT2FS_SHA512_LENGTH])
236{
237	struct hash_state md;
238
239	sha512_init(&md);
240	sha512_process(&md, in, in_size);
241	sha512_done(&md, out);
242}
243
244#ifdef UNITTEST
245static const struct {
246	char *msg;
247	unsigned char hash[64];
248} tests[] = {
249	{ "",
250	  { 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd,
251	    0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07,
252	    0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc,
253	    0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce,
254	    0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0,
255	    0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f,
256	    0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81,
257	    0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e }
258	},
259	{ "abc",
260	  { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba,
261	    0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
262	    0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
263	    0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
264	    0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8,
265	    0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
266	    0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
267	    0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f }
268	},
269	{ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
270	  { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda,
271	    0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f,
272	    0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1,
273	    0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18,
274	    0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4,
275	    0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a,
276	    0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54,
277	    0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 }
278	},
279};
280
281int main(int argc, char **argv)
282{
283	int i;
284	int errors = 0;
285	unsigned char tmp[64];
286	struct hash_state md;
287
288	for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
289		unsigned char *msg = (unsigned char *) tests[i].msg;
290		int len = strlen(tests[i].msg);
291
292		ext2fs_sha512(msg, len, tmp);
293		printf("SHA512 test message %d: ", i);
294		if (memcmp(tmp, tests[i].hash, 64) != 0) {
295			printf("FAILED\n");
296			errors++;
297		} else
298			printf("OK\n");
299	}
300	return errors;
301}
302
303#endif /* UNITTEST */
304