Home | History | Annotate | Download | only in ext2fs
      1 /*
      2  * sha512.c --- The sha512 algorithm
      3  *
      4  * Copyright (C) 2004 Sam Hocevar <sam (at) 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 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
    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 	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