2002-12-27 Sebastien Pouliot <spouliot@videotron.ca>
[mono.git] / mcs / class / corlib / System.Security.Cryptography / SHA512Managed.cs
1 //
2 // System.Security.Cryptography.SHA512Managed.cs
3 //
4 // Authors:
5 //      Dan Lewis (dihlewis@yahoo.co.uk)
6 //      Sébastien Pouliot (spouliot@motus.com)
7 //
8 // (C) 2002
9 // Implementation translated from Bouncy Castle JCE (http://www.bouncycastle.org/)
10 // See bouncycastle.txt for license.
11 //
12
13 using System;
14
15 namespace System.Security.Cryptography {
16         
17 public class SHA512Managed : SHA512 {
18
19         private byte[] xBuf;
20         private int xBufOff;
21
22         private ulong byteCount1;
23         private ulong byteCount2;
24
25         private ulong H1, H2, H3, H4, H5, H6, H7, H8;
26
27         private ulong[] W = new ulong [80];
28         private int wOff;
29
30         public SHA512Managed () 
31         {
32                 xBuf = new byte [8];
33                 xBufOff = 0;
34                 Initialize ();
35         }
36
37         public override void Initialize () 
38         {
39                 // SHA-512 initial hash value
40                 // The first 64 bits of the fractional parts of the square roots
41                 // of the first eight prime numbers
42                 H1 = 0x6a09e667f3bcc908L;
43                 H2 = 0xbb67ae8584caa73bL;
44                 H3 = 0x3c6ef372fe94f82bL;
45                 H4 = 0xa54ff53a5f1d36f1L;
46                 H5 = 0x510e527fade682d1L;
47                 H6 = 0x9b05688c2b3e6c1fL;
48                 H7 = 0x1f83d9abfb41bd6bL;
49                 H8 = 0x5be0cd19137e2179L;
50
51                 byteCount1 = 0;
52                 byteCount2 = 0;
53
54                 xBufOff = 0;
55                 for (int i = 0; i < xBuf.Length; i++) 
56                         xBuf [i] = 0;
57
58                 wOff = 0;
59                 for (int i = 0; i != W.Length; i++)
60                         W [i] = 0;
61         }
62
63         // protected
64
65         protected override void HashCore (byte[] rgb, int start, int count) 
66         {
67                 // fill the current word
68                 while ((xBufOff != 0) && (count > 0)) {
69                         update( rgb [start]);
70                         start++;
71                         count--;
72                 }
73
74                 // process whole words.
75                 while (count > xBuf.Length) {
76                         processWord(rgb, start);
77                         start += xBuf.Length;
78                         count -= xBuf.Length;
79                         byteCount1 += (ulong) xBuf.Length;
80                 }
81
82                 // load in the remainder.
83                 while (count > 0) {
84                         update( rgb [start]);
85                         start++;
86                         count--;
87                 }
88         }
89
90         protected override byte[] HashFinal () 
91         {
92                 adjustByteCounts();
93
94                 ulong lowBitLength = byteCount1 << 3;
95                 ulong hiBitLength = byteCount2;
96
97                 // add the pad bytes.
98                 update ( (byte) 128);
99                 while (xBufOff != 0)
100                         update ( (byte)0);
101
102                 processLength (lowBitLength, hiBitLength);
103                 processBlock ();
104         
105                 byte[] output = new byte [64];
106                 unpackWord(H1, output, 0);
107                 unpackWord(H2, output, 8);
108                 unpackWord(H3, output, 16);
109                 unpackWord(H4, output, 24);
110                 unpackWord(H5, output, 32);
111                 unpackWord(H6, output, 40);
112                 unpackWord(H7, output, 48);
113                 unpackWord(H8, output, 56);
114
115                 Initialize ();
116                 return output;
117         }
118
119         private void update (byte input) 
120         {
121                 xBuf [xBufOff++] = input;
122                 if (xBufOff == xBuf.Length) {
123                         processWord(xBuf, 0);
124                         xBufOff = 0;
125                 }
126                 byteCount1++;
127         }
128
129         private void processWord (byte[] input, int inOff) 
130         {
131                 W [wOff++] = ( (ulong) input [inOff] << 56)
132                         | ( (ulong) input [inOff + 1] << 48)
133                         | ( (ulong) input [inOff + 2] << 40)
134                         | ( (ulong) input [inOff + 3] << 32)
135                         | ( (ulong) input [inOff + 4] << 24)
136                         | ( (ulong) input [inOff + 5] << 16)
137                         | ( (ulong) input [inOff + 6] << 8)
138                         | ( (ulong) input [inOff + 7]); 
139                 if (wOff == 16)
140                         processBlock ();
141         }
142
143         private void unpackWord (ulong word, byte[] output, int outOff) 
144         {
145                 output[outOff]     = (byte) (word >> 56);
146                 output[outOff + 1] = (byte) (word >> 48);
147                 output[outOff + 2] = (byte) (word >> 40);
148                 output[outOff + 3] = (byte) (word >> 32);
149                 output[outOff + 4] = (byte) (word >> 24);
150                 output[outOff + 5] = (byte) (word >> 16);
151                 output[outOff + 6] = (byte) (word >> 8);
152                 output[outOff + 7] = (byte) word;
153         }
154
155         // adjust the byte counts so that byteCount2 represents the
156         // upper long (less 3 bits) word of the byte count.
157         private void adjustByteCounts () 
158         {
159                 if (byteCount1 > 0x1fffffffffffffffL) {
160                         byteCount2 += (byteCount1 >> 61);
161                         byteCount1 &= 0x1fffffffffffffffL;
162                 }
163         }
164
165         private void processLength (ulong lowW, ulong hiW) 
166         {
167                 if (wOff > 14)
168                         processBlock();
169                 W[14] = hiW;
170                 W[15] = lowW;
171         }
172
173         private void processBlock () 
174         {
175                 adjustByteCounts ();
176                 // expand 16 word block into 80 word blocks.
177                 for (int t = 16; t <= 79; t++)
178                         W[t] = Sigma1 (W [t - 2]) + W [t - 7] + Sigma0 (W [t - 15]) + W [t - 16];
179
180                 // set up working variables.
181                 ulong a = H1;
182                 ulong b = H2;
183                 ulong c = H3;
184                 ulong d = H4;
185                 ulong e = H5;
186                 ulong f = H6;
187                 ulong g = H7;
188                 ulong h = H8;
189
190                 for (int t = 0; t <= 79; t++) {
191                         ulong T1 = h + Sum1 (e) + Ch (e, f, g) + K [t] + W [t];
192                         ulong 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                 H1 += a;
204                 H2 += b;
205                 H3 += c;
206                 H4 += d;
207                 H5 += e;
208                 H6 += f;
209                 H7 += g;
210                 H8 += h;
211                 // reset the offset and clean out the word buffer.
212                 wOff = 0;
213                 for (int i = 0; i != W.Length; i++)
214                         W[i] = 0;
215         }
216
217         private ulong rotateRight (ulong x, int n) 
218         {
219                 return (x >> n) | (x << (64 - n));
220         }
221
222         /* SHA-512 and SHA-512 functions (as for SHA-256 but for longs) */
223         private ulong Ch (ulong x, ulong y, ulong z) 
224         {
225                 return ((x & y) ^ ((~x) & z));
226         }
227
228         private ulong Maj (ulong x, ulong y, ulong z) 
229         {
230                 return ((x & y) ^ (x & z) ^ (y & z));
231         }
232
233         private ulong Sum0 (ulong x) 
234         {
235                 return rotateRight (x, 28) ^ rotateRight (x, 34) ^ rotateRight (x, 39);
236         }
237
238         private ulong Sum1 (ulong x) 
239         {
240                 return rotateRight (x, 14) ^ rotateRight (x, 18) ^ rotateRight (x, 41);
241         }
242
243         private ulong Sigma0 (ulong x) 
244         {
245                 return rotateRight (x, 1) ^ rotateRight(x, 8) ^ (x >> 7);
246         }
247
248         private ulong Sigma1 (ulong x) 
249         {
250                 return rotateRight (x, 19) ^ rotateRight (x, 61) ^ (x >> 6);
251         }
252
253         // SHA-384 and SHA-512 Constants
254         // Rrepresent the first 64 bits of the fractional parts of the
255         // cube roots of the first sixty-four prime numbers
256         static ulong[] K = {
257                 0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL,
258                 0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L,
259                 0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
260                 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L,
261                 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L,
262                 0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
263                 0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L,
264                 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L,
265                 0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
266                 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL,
267                 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L,
268                 0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
269                 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L,
270                 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L,
271                 0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
272                 0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL,
273                 0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L,
274                 0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
275                 0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
276                 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
277         };
278 }
279
280 }