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