1 /*******************************************************************************
2 
3         This module implements the SHA-512 Algorithm described by Secure Hash
4         Standard, FIPS PUB 180-2
5 
6         Copyright:
7             Copyright (c) 2006 Tango contributors.
8             Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
9             All rights reserved.
10 
11         License:
12             Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
13             See LICENSE_TANGO.txt for details.
14 
15         Version: Initial release: Feb 2006
16 
17         Authors: Regan Heath, Oskar Linde
18 
19 *******************************************************************************/
20 
21 module ocean.util.digest.Sha512;
22 
23 import ocean.meta.types.Qualifiers;
24 
25 import ocean.core.ByteSwap;
26 
27 import ocean.util.digest.MerkleDamgard;
28 
29 public  import ocean.util.digest.Digest;
30 
31 version (unittest) import ocean.core.Test;
32 
33 /*******************************************************************************
34 
35 *******************************************************************************/
36 
37 final class Sha512 : MerkleDamgard
38 {
39         private ulong[8]        context;
40         private static immutable uint      padChar = 0x80;
41 
42         /***********************************************************************
43 
44                 Construct a Sha512 hash algorithm context
45 
46         ***********************************************************************/
47 
48         this() { }
49 
50         /***********************************************************************
51 
52         ***********************************************************************/
53 
54         protected override void createDigest(ubyte[] buf)
55         {
56                 version (LittleEndian)
57                          ByteSwap.swap64(context.ptr, context.length * ulong.sizeof);
58 
59                 buf[] = cast(ubyte[]) context[];
60         }
61 
62         /***********************************************************************
63 
64                 The digest size of Sha-512 is 64 bytes
65 
66         ***********************************************************************/
67 
68         override uint digestSize() {return 64;}
69 
70         /***********************************************************************
71 
72                 Initialize the cipher
73 
74                 Remarks:
75                 Returns the cipher state to it's initial value
76 
77         ***********************************************************************/
78 
79         protected override void reset()
80         {
81                 super.reset();
82                 context[] = initial[];
83         }
84 
85         /***********************************************************************
86 
87                 Cipher block size
88 
89                 Returns:
90                 the block size
91 
92                 Remarks:
93                 Specifies the size (in bytes) of the block of data to pass to
94                 each call to transform(). For SHA512 the blockSize is 128.
95 
96         ***********************************************************************/
97 
98         protected override uint blockSize() { return 128; }
99 
100         /***********************************************************************
101 
102                 Length padding size
103 
104                 Returns:
105                 the length padding size
106 
107                 Remarks:
108                 Specifies the size (in bytes) of the padding which uses the
109                 length of the data which has been ciphered, this padding is
110                 carried out by the padLength method. For SHA512 the addSize is 16.
111 
112         ***********************************************************************/
113 
114         protected override uint addSize()   { return 16;  }
115 
116         /***********************************************************************
117 
118                 Pads the cipher data
119 
120                 Params:
121                 data = a slice of the cipher buffer to fill with padding
122 
123                 Remarks:
124                 Fills the passed buffer slice with the appropriate padding for
125                 the final call to transform(). This padding will fill the cipher
126                 buffer up to blockSize()-addSize().
127 
128         ***********************************************************************/
129 
130         protected override void padMessage(ubyte[] data)
131         {
132                 data[0] = padChar;
133                 data[1..$] = 0;
134         }
135 
136         /***********************************************************************
137 
138                 Performs the length padding
139 
140                 Params:
141                 data   = the slice of the cipher buffer to fill with padding
142                 length = the length of the data which has been ciphered
143 
144                 Remarks:
145                 Fills the passed buffer slice with addSize() bytes of padding
146                 based on the length in bytes of the input data which has been
147                 ciphered.
148 
149         ***********************************************************************/
150 
151         protected override void padLength(ubyte[] data, ulong length)
152         {
153                 length <<= 3;
154                 for(auto j = data.length; j > 0;) {
155                         j--;
156                         data[data.length-j-1] = cast(ubyte) (length >> j*8);
157                 }
158                 data[0..8] = 0;
159         }
160 
161         /***********************************************************************
162 
163                 Performs the cipher on a block of data
164 
165                 Params:
166                 input = the block of data to cipher
167 
168                 Remarks:
169                 The actual cipher algorithm is carried out by this method on
170                 the passed block of data. This method is called for every
171                 blockSize() bytes of input data and once more with the remaining
172                 data padded to blockSize().
173 
174         ***********************************************************************/
175 
176         protected override void transform(ubyte[] input)
177         {
178                 ulong[80] W;
179                 ulong a,b,c,d,e,f,g,h;
180                 ulong t1,t2;
181                 uint j;
182 
183                 a = context[0];
184                 b = context[1];
185                 c = context[2];
186                 d = context[3];
187                 e = context[4];
188                 f = context[5];
189                 g = context[6];
190                 h = context[7];
191 
192                 bigEndian64(input,W[0..16]);
193                 for(j = 16; j < 80; j++) {
194                         W[j] = mix1(W[j-2]) + W[j-7] + mix0(W[j-15]) + W[j-16];
195                 }
196 
197                 for(j = 0; j < 80; j++) {
198                         t1 = h + sum1(e) + Ch(e,f,g) + K[j] + W[j];
199                         t2 = sum0(a) + Maj(a,b,c);
200                         h = g;
201                         g = f;
202                         f = e;
203                         e = d + t1;
204                         d = c;
205                         c = b;
206                         b = a;
207                         a = t1 + t2;
208                 }
209 
210                 context[0] += a;
211                 context[1] += b;
212                 context[2] += c;
213                 context[3] += d;
214                 context[4] += e;
215                 context[5] += f;
216                 context[6] += g;
217                 context[7] += h;
218         }
219 
220         /***********************************************************************
221 
222         ***********************************************************************/
223 
224         private static ulong Ch(ulong x, ulong y, ulong z)
225         {
226                 return (x&y)^(~x&z);
227         }
228 
229         /***********************************************************************
230 
231         ***********************************************************************/
232 
233         private static ulong Maj(ulong x, ulong y, ulong z)
234         {
235                 return (x&y)^(x&z)^(y&z);
236         }
237 
238         /***********************************************************************
239 
240         ***********************************************************************/
241 
242         private static ulong sum0(ulong x)
243         {
244                 return rotateRight(x,28)^rotateRight(x,34)^rotateRight(x,39);
245         }
246 
247         /***********************************************************************
248 
249         ***********************************************************************/
250 
251         private static ulong sum1(ulong x)
252         {
253                 return rotateRight(x,14)^rotateRight(x,18)^rotateRight(x,41);
254         }
255 
256         /***********************************************************************
257 
258         ***********************************************************************/
259 
260         private static ulong mix0(ulong x)
261         {
262                 return rotateRight(x,1)^rotateRight(x,8)^shiftRight(x,7);
263         }
264 
265         /***********************************************************************
266 
267         ***********************************************************************/
268 
269         private static ulong mix1(ulong x)
270         {
271                 return rotateRight(x,19)^rotateRight(x,61)^shiftRight(x,6);
272         }
273 
274         /***********************************************************************
275 
276         ***********************************************************************/
277 
278         private static ulong rotateRight(ulong x, uint n)
279         {
280                 return (x >> n) | (x << (64-n));
281         }
282 
283         /***********************************************************************
284 
285         ***********************************************************************/
286 
287         private static ulong shiftRight(ulong x, uint n)
288         {
289                 return x >> n;
290         }
291 
292 }
293 
294 /*******************************************************************************
295 
296 *******************************************************************************/
297 
298 private static const(ulong[]) K =
299 [
300         0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
301         0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
302         0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
303         0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
304         0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
305         0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
306         0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
307         0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
308         0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
309         0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
310         0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
311         0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
312         0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
313         0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
314         0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
315         0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
316         0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
317         0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
318         0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
319         0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
320 ];
321 
322 /*******************************************************************************
323 
324 *******************************************************************************/
325 
326 private static const(ulong[8]) initial =
327 [
328         0x6a09e667f3bcc908,
329         0xbb67ae8584caa73b,
330         0x3c6ef372fe94f82b,
331         0xa54ff53a5f1d36f1,
332         0x510e527fade682d1,
333         0x9b05688c2b3e6c1f,
334         0x1f83d9abfb41bd6b,
335         0x5be0cd19137e2179
336 ];
337 
338 
339 /*******************************************************************************
340 
341 *******************************************************************************/
342 
343 unittest
344 {
345     static istring[] strings = [
346         "",
347         "abc",
348         "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
349     ];
350 
351     static istring[] results = [
352         "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
353         "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
354         "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909"
355     ];
356 
357     Sha512 h = new Sha512;
358 
359     foreach (i, s; strings)
360     {
361         h.update(cast(ubyte[])s);
362         char[] d = h.hexDigest();
363         test(d == results[i],"DigestTransform:("~s~")("~d~")!=("~results[i]~")");
364     }
365 }