comparison tango/tango/io/digest/Sha256.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
comparison
equal deleted inserted replaced
131:5825d48b27d1 132:1700239cab2e
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.io.digest.Sha256;
17
18 private import tango.core.ByteSwap;
19
20 public import tango.io.digest.Digest;
21
22 private import tango.io.digest.MerkleDamgard;
23
24 /*******************************************************************************
25
26 *******************************************************************************/
27
28 final class Sha256 : MerkleDamgard
29 {
30 private uint[8] context;
31 private const 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 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 = 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(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 static 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 static const 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 version (UnitTest)
324 {
325 unittest
326 {
327 static char[][] strings =
328 [
329 "abc",
330 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
331 ];
332
333 static char[][] results =
334 [
335 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
336 "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
337 ];
338
339 Sha256 h = new Sha256();
340
341 foreach (int i, 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