1 module dcrypt.crypto.digests.sha1; 2 3 import dcrypt.crypto.digests.generaldigest; 4 import dcrypt.util.pack; 5 6 /** 7 * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349. 8 * 9 * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5 10 * is the "endianness" of the word processing! 11 */ 12 @safe 13 public class SHA1Digest: GeneralDigest 14 { 15 16 unittest { 17 // test vectors from http://www.di-mgt.com.au/sha_testvectors.html 18 19 immutable string[] plaintexts = [ 20 x"616263", 21 x"", 22 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" 23 ]; 24 25 immutable string[] hashes = [ 26 x"a9993e364706816aba3e25717850c26c9cd0d89d", 27 x"da39a3ee5e6b4b0d3255bfef95601890afd80709", 28 x"a49b2446a02c645bf419f995b67091253a04a259" 29 ]; 30 31 testDigest(new SHA1Digest(), plaintexts, hashes); 32 } 33 34 public: 35 /** 36 * Standard constructor 37 */ 38 this() nothrow 39 { 40 start(); 41 } 42 43 @property 44 override string name() pure nothrow @nogc 45 { 46 return "SHA-1"; 47 } 48 49 override uint getDigestSize() nothrow @nogc 50 { 51 return digestLength; 52 } 53 54 override uint doFinal(ubyte[] output) nothrow @nogc 55 { 56 finish(); 57 58 // pack the integers into a byte array 59 //toBigEndian!uint([H1,H2,H3,H4,H5], output); 60 61 toBigEndian!uint(H1, output[0..4]); 62 toBigEndian!uint(H2, output[4..8]); 63 toBigEndian!uint(H3, output[8..12]); 64 toBigEndian!uint(H4, output[12..16]); 65 toBigEndian!uint(H5, output[16..20]); 66 67 start(); 68 69 return 20; 70 } 71 72 /** 73 * reset the chaining variables 74 */ 75 override void start() nothrow @nogc 76 { 77 super.start(); 78 79 H1 = 0x67452301; 80 H2 = 0xefcdab89; 81 H3 = 0x98badcfe; 82 H4 = 0x10325476; 83 H5 = 0xc3d2e1f0; 84 85 xOff = 0; 86 X[] = 0; 87 } 88 89 protected override SHA1Digest dupImpl() nothrow { 90 SHA1Digest clone = new SHA1Digest(); 91 clone.H1 = H1; 92 clone.H2 = H2; 93 clone.H3 = H3; 94 clone.H4 = H4; 95 clone.H5 = H5; 96 clone.X = X; 97 clone.xOff = xOff; 98 return clone; 99 } 100 101 protected override void processWord(in ubyte[] input) nothrow @nogc 102 { 103 // Note: Inlined for performance 104 // X[xOff] = bigEndianToInt(in, inOff); 105 uint n = input[0] << 24; 106 n |= input[1] << 16; 107 n |= input[2] << 8; 108 n |= input[3]; 109 X[xOff] = n; 110 111 if (++xOff == 16) 112 { 113 processBlock(); 114 } 115 } 116 117 protected override void processLength(ulong bitLength) nothrow @nogc 118 { 119 if (xOff > 14) 120 { 121 processBlock(); 122 } 123 124 X[14] = cast(uint)(bitLength >>> 32); 125 X[15] = cast(uint) bitLength; 126 } 127 128 private: 129 // 130 // Additive constants 131 // 132 static { 133 enum uint Y1 = 0x5a827999; 134 enum uint Y2 = 0x6ed9eba1; 135 enum uint Y3 = 0x8f1bbcdc; 136 enum uint Y4 = 0xca62c1d6; 137 } 138 139 enum digestLength = 20; 140 141 uint H1, H2, H3, H4, H5; 142 143 uint[80] X; 144 uint xOff; 145 146 147 uint f(uint u, uint v, uint w) pure nothrow @nogc 148 { 149 return ((u & v) | ((~u) & w)); 150 } 151 152 uint g(uint u, uint v, uint w) pure nothrow @nogc 153 { 154 return ((u & v) | (u & w) | (v & w)); 155 } 156 157 uint h(uint u, uint v, uint w) pure nothrow @nogc 158 { 159 return (u ^ v ^ w); 160 } 161 162 protected override void processBlock() nothrow @nogc 163 { 164 // 165 // expand 16 word block into 80 word block. 166 // 167 foreach (uint i; 16 .. 80) 168 { 169 uint t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]; 170 X[i] = t << 1 | t >>> 31; 171 } 172 173 // 174 // set up working variables. 175 // 176 uint A = H1; 177 uint B = H2; 178 uint C = H3; 179 uint D = H4; 180 uint E = H5; 181 182 // 183 // round 1 184 // 185 uint idx = 0; 186 187 for (uint j = 0; j < 4; j++) 188 { 189 // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1 190 // B = rotateLeft(B, 30) 191 E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1; 192 B = B << 30 | B >>> 2; 193 194 D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1; 195 A = A << 30 | A >>> 2; 196 197 C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1; 198 E = E << 30 | E >>> 2; 199 200 B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1; 201 D = D << 30 | D >>> 2; 202 203 A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1; 204 C = C << 30 | C >>> 2; 205 } 206 207 // 208 // round 2 209 // 210 for (uint j = 0; j < 4; j++) 211 { 212 // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2 213 // B = rotateLeft(B, 30) 214 E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2; 215 B = B << 30 | B >>> 2; 216 217 D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2; 218 A = A << 30 | A >>> 2; 219 220 C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2; 221 E = E << 30 | E >>> 2; 222 223 B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2; 224 D = D << 30 | D >>> 2; 225 226 A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2; 227 C = C << 30 | C >>> 2; 228 } 229 230 // 231 // round 3 232 // 233 for (uint j = 0; j < 4; j++) 234 { 235 // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3 236 // B = rotateLeft(B, 30) 237 E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3; 238 B = B << 30 | B >>> 2; 239 240 D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3; 241 A = A << 30 | A >>> 2; 242 243 C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3; 244 E = E << 30 | E >>> 2; 245 246 B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3; 247 D = D << 30 | D >>> 2; 248 249 A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3; 250 C = C << 30 | C >>> 2; 251 } 252 253 // 254 // round 4 255 // 256 for (uint j = 0; j <= 3; j++) 257 { 258 // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4 259 // B = rotateLeft(B, 30) 260 E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4; 261 B = B << 30 | B >>> 2; 262 263 D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4; 264 A = A << 30 | A >>> 2; 265 266 C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4; 267 E = E << 30 | E >>> 2; 268 269 B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4; 270 D = D << 30 | D >>> 2; 271 272 A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4; 273 C = C << 30 | C >>> 2; 274 } 275 276 277 H1 += A; 278 H2 += B; 279 H3 += C; 280 H4 += D; 281 H5 += E; 282 283 // 284 // reset start of the buffer. 285 // 286 xOff = 0; 287 X[] = 0; 288 } 289 } 290 291 292