/* Portable C implementation of SHA1 hashing. The implementation is part of the raaz cryptographic network library and is not meant to be used as a standalone sha1 function. Copyright (c) 2012, Piyush P Kurur All rights reserved. This software is distributed under the terms and conditions of the BSD3 license. See the accompanying file LICENSE for exact terms and condition. */ #include #include typedef uint32_t Word; /* basic unit of sha1 hash */ #define HASH_SIZE 5 /* Number of words in a Hash */ #define BLOCK_SIZE 16 /* Number of words in a block */ typedef Word Hash [ HASH_SIZE ]; typedef Word Block[ BLOCK_SIZE ]; void raazHashSha1PortableCompress(Block *mesg, int nblocks, Hash hash); /* WARNING: Macro variables not protected use only simple * expressions. * * Notes to Developers: Lot of the code is just repetative loop * unrollings. The comment after these blocks contain elisp macros * that generate them (with some tweaks). Preserve these of ease of * updating the code. * */ #define RotateL(x,n) ((x << n) | (x >> (32 - (n)))) #define RotL30(x) ((x << 30) | (x >> 2)) #define RotL1(x) ((x << 1) | (x >> 31)) #define RotL5(x) ((x << 5) | (x >> 27)) /* The round constants */ #define K0 0x5a827999 #define K20 0x6ed9eba1 #define K40 0x8f1bbcdc #define K60 0xca62c1d6 /* The round functions */ #define F0(x,y,z) CH(x,y,z) #define F20(x,y,z) PARITY(x,y,z) #define F40(x,y,z) MAJ(x,y,z) #define F60(x,y,z) PARITY(x,y,z) #define CH(x,y,z) ((x & y) ^ (~x & z)) #define PARITY(x,y,z) (x^y^z) #define MAJ(x,y,z) ((x & (y | z)) | (y & z)) /* One step in the hash function a' = (rotateL a 5 + (f t) b c d + e + k t + w0) b' = a c' = rotateL b 30 d' = c e' = d Notice the values of a,c,d are carried over but b and e gets updated. */ #define Step(a,b,c,d,e,w) \ { \ e += RotL5(a) + F(b,c,d) + K + w; \ b = RotL30(b); \ } \ /* Message scheduling is done as w16 = rotateL (w13 `xor` w8 `xor` w2 `xor` w0) 1 */ /* Message scheduling */ #define SCHEDULE \ { \ w0 ^= w13 ^ w8 ^ w2; w0 = RotL1(w0); \ w1 ^= w14 ^ w9 ^ w3; w1 = RotL1(w1); \ w2 ^= w15 ^ w10 ^ w4; w2 = RotL1(w2); \ w3 ^= w0 ^ w11 ^ w5; w3 = RotL1(w3); \ w4 ^= w1 ^ w12 ^ w6; w4 = RotL1(w4); \ w5 ^= w2 ^ w13 ^ w7; w5 = RotL1(w5); \ w6 ^= w3 ^ w14 ^ w8; w6 = RotL1(w6); \ w7 ^= w4 ^ w15 ^ w9; w7 = RotL1(w7); \ w8 ^= w5 ^ w0 ^ w10; w8 = RotL1(w8); \ w9 ^= w6 ^ w1 ^ w11; w9 = RotL1(w9); \ w10 ^= w7 ^ w2 ^ w12; w10 = RotL1(w10); \ w11 ^= w8 ^ w3 ^ w13; w11 = RotL1(w11); \ w12 ^= w9 ^ w4 ^ w14; w12 = RotL1(w12); \ w13 ^= w10 ^ w5 ^ w15; w13 = RotL1(w13); \ w14 ^= w11 ^ w6 ^ w0; w14 = RotL1(w14); \ w15 ^= w12 ^ w7 ^ w1; w15 = RotL1(w15); \ } /* (dotimes (i 16) (setq j (% (+ i 13) 16)) (setq k (% (+ i 8) 16)) (setq l (% (+ i 2) 16)) (insert (format "w%d ^= w%d ^ w%d ^ w%d; " i j k l)) (insert (format "w%d = RotL1(w%d);\\\n" i i))) */ /* This is the compress routine of sha1. It is safe in the sense that it does not overwrite the message. However, it does overwrite the hash array. */ void raazHashSha1PortableCompress(Block *mesg, int nblocks, Hash hash) { register Word a,b,c,d,e; /* Stores the hash state */ /* The message variables: (dotimes (i 16)(insert (format "Word w%d;\n" i))) Why not an array? Memory wise these two will be more or less same as local arrays will be allocated on stack. However in machines with a large number of general purpose registers the compiler has a chance of allocating all of them to registers making them faster. It might also improve cache hits. */ Word w0; Word w1; Word w2; Word w3; Word w4; Word w5; Word w6; Word w7; Word w8; Word w9; Word w10; Word w11; Word w12; Word w13; Word w14; Word w15; while (nblocks > 0) { /* initialisation of the hash state */ a = hash[0]; b = hash[1]; c = hash[2]; d = hash[3]; e = hash[4]; /* Reading in the message (dotimes (i 16) (insert (format "w%d = raazLoad32BE( (Word *) mesg, %d);\n" i i))) */ # define LOAD(i) raaz_tobe32((*mesg)[i]) w0 = LOAD(0); w1 = LOAD(1); w2 = LOAD(2); w3 = LOAD(3); w4 = LOAD(4); w5 = LOAD(5); w6 = LOAD(6); w7 = LOAD(7); w8 = LOAD(8); w9 = LOAD(9); w10 = LOAD(10); w11 = LOAD(11); w12 = LOAD(12); w13 = LOAD(13); w14 = LOAD(14); w15 = LOAD(15); #undef LOAD /* End of reading the message */ #undef K #undef F #define K K0 #define F F0 /* 0-4 */ Step(a,b,c,d,e,w0 ); Step(e,a,b,c,d,w1 ); Step(d,e,a,b,c,w2 ); Step(c,d,e,a,b,w3 ); Step(b,c,d,e,a,w4 ); /* 5-9 */ Step(a,b,c,d,e,w5 ); Step(e,a,b,c,d,w6 ); Step(d,e,a,b,c,w7 ); Step(c,d,e,a,b,w8 ); Step(b,c,d,e,a,w9 ); /* 10-14 */ Step(a,b,c,d,e,w10); Step(e,a,b,c,d,w11); Step(d,e,a,b,c,w12); Step(c,d,e,a,b,w13); Step(b,c,d,e,a,w14); /* 15-19 */ Step(a,b,c,d,e,w15); SCHEDULE; Step(e,a,b,c,d,w0 ); Step(d,e,a,b,c,w1 ); Step(c,d,e,a,b,w2 ); Step(b,c,d,e,a,w3 ); #undef K #undef F #define K K20 #define F F20 /* 20-24 */ Step(a,b,c,d,e,w4 ); Step(e,a,b,c,d,w5 ); Step(d,e,a,b,c,w6 ); Step(c,d,e,a,b,w7 ); Step(b,c,d,e,a,w8 ); /* 25-29 */ Step(a,b,c,d,e,w9 ); Step(e,a,b,c,d,w10); Step(d,e,a,b,c,w11); Step(c,d,e,a,b,w12); Step(b,c,d,e,a,w13); /* 30-34 */ Step(a,b,c,d,e,w14); Step(e,a,b,c,d,w15); SCHEDULE; Step(d,e,a,b,c,w0 ); Step(c,d,e,a,b,w1 ); Step(b,c,d,e,a,w2 ); /* 35-39 */ Step(a,b,c,d,e,w3 ); Step(e,a,b,c,d,w4 ); Step(d,e,a,b,c,w5 ); Step(c,d,e,a,b,w6 ); Step(b,c,d,e,a,w7 ); #undef K #undef F #define K K40 #define F F40 /* 40-44 */ Step(a,b,c,d,e,w8 ); Step(e,a,b,c,d,w9 ); Step(d,e,a,b,c,w10); Step(c,d,e,a,b,w11); Step(b,c,d,e,a,w12); /* 45-49 */ Step(a,b,c,d,e,w13); Step(e,a,b,c,d,w14); Step(d,e,a,b,c,w15); SCHEDULE; Step(c,d,e,a,b,w0 ); Step(b,c,d,e,a,w1 ); /* 50-54 */ Step(a,b,c,d,e,w2 ); Step(e,a,b,c,d,w3 ); Step(d,e,a,b,c,w4 ); Step(c,d,e,a,b,w5 ); Step(b,c,d,e,a,w6 ); /* 55-59 */ Step(a,b,c,d,e,w7 ); Step(e,a,b,c,d,w8 ); Step(d,e,a,b,c,w9 ); Step(c,d,e,a,b,w10); Step(b,c,d,e,a,w11); #undef K #undef F #define K K60 #define F F60 /* 60-64 */ Step(a,b,c,d,e,w12); Step(e,a,b,c,d,w13); Step(d,e,a,b,c,w14); Step(c,d,e,a,b,w15); SCHEDULE; Step(b,c,d,e,a,w0 ); /* 65-69 */ Step(a,b,c,d,e,w1 ); Step(e,a,b,c,d,w2 ); Step(d,e,a,b,c,w3 ); Step(c,d,e,a,b,w4 ); Step(b,c,d,e,a,w5 ); /* 70-74 */ Step(a,b,c,d,e,w6 ); Step(e,a,b,c,d,w7 ); Step(d,e,a,b,c,w8 ); Step(c,d,e,a,b,w9 ); Step(b,c,d,e,a,w10); /* 75-79 */ Step(a,b,c,d,e,w11); Step(e,a,b,c,d,w12); Step(d,e,a,b,c,w13); Step(c,d,e,a,b,w14); Step(b,c,d,e,a,w15); /* Update the hash */ hash[0] += a; hash[1] += b; hash[2] += c; hash[3] += d; hash[4] += e; /* Move to next block */ --nblocks; ++mesg; } return; }