132
|
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
|