Imported Upstream version 1.47.0
[platform/upstream/e2fsprogs.git] / lib / ext2fs / sha512.c
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
22 static 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
104 struct 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 */
111 struct hash_state {
112         struct sha512_state sha512;
113 };
114
115 static 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
153 static 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
167 static 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 up to 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
206 static 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
234 void 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
245 static 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
281 int main(int argc, char **argv)
282 {
283         int i;
284         int errors = 0;
285         unsigned char tmp[64];
286
287         for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
288                 unsigned char *msg = (unsigned char *) tests[i].msg;
289                 int len = strlen(tests[i].msg);
290
291                 ext2fs_sha512(msg, len, tmp);
292                 printf("SHA512 test message %d: ", i);
293                 if (memcmp(tmp, tests[i].hash, 64) != 0) {
294                         printf("FAILED\n");
295                         errors++;
296                 } else
297                         printf("OK\n");
298         }
299         return errors;
300 }
301
302 #endif /* UNITTEST */