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