1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2006 Tango. All rights reserved
4 
5         license:        BSD style: see doc/license.txt for details
6 
7         version:        Initial release: Feb 2006
8 
9         author:         Regan Heath, Oskar Linde
10 
11         This module implements the SHA-256 Algorithm described by Secure
12         Hash Standard, FIPS PUB 180-2
13 
14 *******************************************************************************/
15 
16 module tango.util.digest.Sha256;
17 
18 private import tango.core.ByteSwap;
19 
20 public  import tango.util.digest.Digest;
21 
22 private import tango.util.digest.MerkleDamgard;
23 
24 /*******************************************************************************
25 
26 *******************************************************************************/
27 
28 final class Sha256 : MerkleDamgard
29 {
30         private uint[8]         context;
31         private enum uint      padChar = 0x80;
32 
33         /***********************************************************************
34 
35                 Construct an Sha256
36 
37         ***********************************************************************/
38 
39         this() { }
40 
41         /***********************************************************************
42 
43                 Initialize the cipher
44 
45                 Remarks:
46                 Returns the cipher state to it's initial value
47 
48         ***********************************************************************/
49 
50         protected override void reset()
51         {
52                 super.reset();
53                 context[] = initial[];
54         }
55 
56         /***********************************************************************
57 
58                 Obtain the digest
59 
60                 Remarks:
61                 Returns a digest of the current cipher state, this may be the
62                 final digest, or a digest of the state between calls to update()
63 
64         ***********************************************************************/
65 
66         protected override void createDigest (ubyte[] buf)
67         {
68                 version (LittleEndian)
69                          ByteSwap.swap32 (context.ptr, context.length * uint.sizeof);
70 
71                 buf[] = (cast(ubyte[]) context)[];
72         }
73 
74         /***********************************************************************
75 
76                 The digest size of Sha-256 is 32 bytes
77 
78         ***********************************************************************/
79 
80         override uint digestSize() { return 32; }
81 
82         /***********************************************************************
83 
84                 Cipher block size
85 
86                 Returns:
87                 the block size
88 
89                 Remarks:
90                 Specifies the size (in bytes) of the block of data to pass to
91                 each call to transform(). For SHA256 the blockSize is 64.
92 
93         ***********************************************************************/
94 
95         protected override uint blockSize() { return 64; }
96 
97         /***********************************************************************
98 
99                 Length padding size
100 
101                 Returns:
102                 the length padding size
103 
104                 Remarks:
105                 Specifies the size (in bytes) of the padding which uses the
106                 length of the data which has been ciphered, this padding is
107                 carried out by the padLength method. For SHA256 the addSize is 8.
108 
109         ***********************************************************************/
110 
111         protected override uint addSize()   { return 8;  }
112 
113         /***********************************************************************
114 
115                 Pads the cipher data
116 
117                 Params:
118                 data = a slice of the cipher buffer to fill with padding
119 
120                 Remarks:
121                 Fills the passed buffer slice with the appropriate padding for
122                 the final call to transform(). This padding will fill the cipher
123                 buffer up to blockSize()-addSize().
124 
125         ***********************************************************************/
126 
127         protected override void padMessage(ubyte[] data)
128         {
129                 data[0] = padChar;
130                 data[1..$] = 0;
131         }
132 
133         /***********************************************************************
134 
135                 Performs the length padding
136 
137                 Params:
138                 data   = the slice of the cipher buffer to fill with padding
139                 length = the length of the data which has been ciphered
140 
141                 Remarks:
142                 Fills the passed buffer slice with addSize() bytes of padding
143                 based on the length in bytes of the input data which has been
144                 ciphered.
145 
146         ***********************************************************************/
147 
148         protected override void padLength(ubyte[] data, ulong length)
149         {
150                 length <<= 3;
151                 for(int j = cast(int)data.length-1; j >= 0; j--)
152                         data[$-j-1] = cast(ubyte) (length >> j*8);
153         }
154 
155         /***********************************************************************
156 
157                 Performs the cipher on a block of data
158 
159                 Params:
160                 data = the block of data to cipher
161 
162                 Remarks:
163                 The actual cipher algorithm is carried out by this method on
164                 the passed block of data. This method is called for every
165                 blockSize() bytes of input data and once more with the remaining
166                 data padded to blockSize().
167 
168         ***********************************************************************/
169 
170         protected override void transform(const(ubyte[]) input)
171         {
172                 uint[64] W;
173                 uint a,b,c,d,e,f,g,h;
174                 uint j,t1,t2;
175 
176                 a = context[0];
177                 b = context[1];
178                 c = context[2];
179                 d = context[3];
180                 e = context[4];
181                 f = context[5];
182                 g = context[6];
183                 h = context[7];
184 
185                 bigEndian32(input,W[0..16]);
186                 for(j = 16; j < 64; j++) {
187                         W[j] = mix1(W[j-2]) + W[j-7] + mix0(W[j-15]) + W[j-16];
188                 }
189 
190                 for(j = 0; j < 64; j++) {
191                         t1 = h + sum1(e) + Ch(e,f,g) + K[j] + W[j];
192                         t2 = sum0(a) + Maj(a,b,c);
193                         h = g;
194                         g = f;
195                         f = e;
196                         e = d + t1;
197                         d = c;
198                         c = b;
199                         b = a;
200                         a = t1 + t2;
201                 }
202 
203                 context[0] += a;
204                 context[1] += b;
205                 context[2] += c;
206                 context[3] += d;
207                 context[4] += e;
208                 context[5] += f;
209                 context[6] += g;
210                 context[7] += h;
211         }
212 
213         /***********************************************************************
214 
215         ***********************************************************************/
216 
217         private static uint Ch(uint x, uint y, uint z)
218         {
219                 return (x&y)^(~x&z);
220         }
221 
222         /***********************************************************************
223 
224         ***********************************************************************/
225 
226         private static uint Maj(uint x, uint y, uint z)
227         {
228                 return (x&y)^(x&z)^(y&z);
229         }
230 
231         /***********************************************************************
232 
233         ***********************************************************************/
234 
235         private static uint sum0(uint x)
236         {
237                 return rotateRight(x,2)^rotateRight(x,13)^rotateRight(x,22);
238         }
239 
240         /***********************************************************************
241 
242         ***********************************************************************/
243 
244         private static uint sum1(uint x)
245         {
246                 return rotateRight(x,6)^rotateRight(x,11)^rotateRight(x,25);
247         }
248 
249         /***********************************************************************
250 
251         ***********************************************************************/
252 
253         private static uint mix0(uint x)
254         {
255                 return rotateRight(x,7)^rotateRight(x,18)^shiftRight(x,3);
256         }
257 
258         /***********************************************************************
259 
260         ***********************************************************************/
261 
262         private static uint mix1(uint x)
263         {
264                 return rotateRight(x,17)^rotateRight(x,19)^shiftRight(x,10);
265         }
266 
267         /***********************************************************************
268 
269         ***********************************************************************/
270 
271         private static uint rotateRight(uint x, uint n)
272         {
273                 return (x >> n) | (x << (32-n));
274         }
275 
276         /***********************************************************************
277 
278         ***********************************************************************/
279 
280         private static uint shiftRight(uint x, uint n)
281         {
282                 return x >> n;
283         }
284 }
285 
286 
287 /*******************************************************************************
288 
289 *******************************************************************************/
290 
291 private __gshared immutable uint[] K =
292 [
293         0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
294         0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
295         0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
296         0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
297         0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
298         0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
299         0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
300         0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
301 ];
302 
303 /*******************************************************************************
304 
305 *******************************************************************************/
306 
307 private __gshared immutable uint[8] initial =
308 [
309         0x6a09e667,
310         0xbb67ae85,
311         0x3c6ef372,
312         0xa54ff53a,
313         0x510e527f,
314         0x9b05688c,
315         0x1f83d9ab,
316         0x5be0cd19
317 ];
318 
319 /*******************************************************************************
320 
321 *******************************************************************************/
322 
323 debug(UnitTest)
324 {
325         unittest
326         {
327         __gshared immutable immutable(char)[][] strings =
328         [
329                 "abc",
330                 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
331         ];
332 
333         __gshared immutable immutable(char)[][] results =
334         [
335                 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
336                 "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
337         ];
338 
339         Sha256 h = new Sha256();
340 
341         foreach (int i, immutable(char)[] s; strings)
342                 {
343                 h.update(s);
344                 char[] d = h.hexDigest();
345                 assert(d == results[i],"Cipher:("~s~")("~d~")!=("~results[i]~")");
346                 }
347         }
348 }
349