Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / sha384managed.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>[....]</OWNER>
7 // 
8
9 //
10 // SHA384Managed.cs
11 //
12 // C# implementation of the proposed SHA-384 hash algorithm
13 //
14
15 namespace System.Security.Cryptography {
16     using System;
17     using System.Diagnostics.Contracts;
18
19     [System.Runtime.InteropServices.ComVisible(true)]
20     public class SHA384Managed : SHA384
21     {
22         private byte[]   _buffer;
23         private ulong    _count; // Number of bytes in the hashed message
24         private UInt64[] _stateSHA384;
25         private UInt64[] _W;
26
27         //
28         // public constructors
29         //
30
31         public SHA384Managed()
32         {
33             if (CryptoConfig.AllowOnlyFipsAlgorithms)
34                 throw new InvalidOperationException(Environment.GetResourceString("Cryptography_NonCompliantFIPSAlgorithm"));
35             Contract.EndContractBlock();
36
37             _stateSHA384 = new UInt64[8];
38             _buffer = new byte[128];
39             _W = new UInt64[80];
40
41             InitializeState();
42         }
43
44         //
45         // public methods
46         //
47
48         public override void Initialize() {
49             InitializeState();
50
51             // Zeroize potentially sensitive information.
52             Array.Clear(_buffer, 0, _buffer.Length);
53             Array.Clear(_W, 0, _W.Length);
54         }
55
56         [System.Security.SecuritySafeCritical]  // auto-generated
57         protected override void HashCore(byte[] rgb, int ibStart, int cbSize) {
58             _HashData(rgb, ibStart, cbSize);
59         }
60
61         [System.Security.SecuritySafeCritical]  // auto-generated
62         protected override byte[] HashFinal() {
63             return _EndHash();
64         }
65
66         //
67         // private methods
68         //
69
70         private void InitializeState() {
71             _count = 0;
72
73             _stateSHA384[0] = 0xcbbb9d5dc1059ed8;
74             _stateSHA384[1] = 0x629a292a367cd507;
75             _stateSHA384[2] = 0x9159015a3070dd17;
76             _stateSHA384[3] = 0x152fecd8f70e5939;
77             _stateSHA384[4] = 0x67332667ffc00b31;
78             _stateSHA384[5] = 0x8eb44a8768581511;
79             _stateSHA384[6] = 0xdb0c2e0d64f98fa7;
80             _stateSHA384[7] = 0x47b5481dbefa4fa4;
81         }
82
83         /* SHA384 block update operation. Continues an SHA message-digest
84            operation, processing another message block, and updating the
85            context.
86            */
87
88         [System.Security.SecurityCritical]  // auto-generated
89         private unsafe void _HashData(byte[] partIn, int ibStart, int cbSize)
90         {
91             int bufferLen;
92             int partInLen = cbSize;
93             int partInBase = ibStart;
94
95             /* Compute length of buffer */
96             bufferLen = (int) (_count & 0x7f);
97
98             /* Update number of bytes */
99             _count += (ulong) partInLen;
100
101             fixed (UInt64* stateSHA384 = _stateSHA384) {
102                 fixed (byte* buffer = _buffer) {
103                     fixed (UInt64* expandedBuffer = _W) {
104                         if ((bufferLen > 0) && (bufferLen + partInLen >= 128)) {
105                             Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, 128 - bufferLen);
106                             partInBase += (128 - bufferLen);
107                             partInLen -= (128 - bufferLen);
108                             SHATransform(expandedBuffer, stateSHA384, buffer);
109                             bufferLen = 0;
110                         }
111
112                         /* Copy input to temporary buffer and hash */
113                         while (partInLen >= 128) {
114                             Buffer.InternalBlockCopy(partIn, partInBase, _buffer, 0, 128);
115                             partInBase += 128;
116                             partInLen -= 128;
117                             SHATransform(expandedBuffer, stateSHA384, buffer);
118                         }
119
120                         if (partInLen > 0) {
121                             Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen);
122                         }
123                     }
124                 }
125             }
126         }
127
128         /* SHA384 finalization. Ends an SHA384 message-digest operation, writing
129            the message digest.
130            */
131
132         [System.Security.SecurityCritical]  // auto-generated
133         private byte[] _EndHash()
134         {
135             byte[]         pad;
136             int            padLen;
137             ulong          bitCount;
138             byte[]         hash = new byte[48]; // HashSizeValue = 384
139
140             /* Compute padding: 80 00 00 ... 00 00 <bit count>
141              */
142
143             padLen = 128 - (int)(_count & 0x7f);
144             if (padLen <= 16)
145                 padLen += 128;
146
147             pad = new byte[padLen];
148             pad[0] = 0x80;
149
150             //  Convert count to bit count
151             bitCount = _count * 8;
152
153             // bitCount is at most 8 * 128 = 1024. Its representation as a 128-bit number has all bits set to zero
154             // except eventually the 11 lower bits
155
156             //pad[padLen-16] = (byte) ((bitCount >> 120) & 0xff);
157             //pad[padLen-15] = (byte) ((bitCount >> 112) & 0xff);
158             //pad[padLen-14] = (byte) ((bitCount >> 104) & 0xff);
159             //pad[padLen-13] = (byte) ((bitCount >> 96) & 0xff);
160             //pad[padLen-12] = (byte) ((bitCount >> 88) & 0xff);
161             //pad[padLen-11] = (byte) ((bitCount >> 80) & 0xff);
162             //pad[padLen-10] = (byte) ((bitCount >> 72) & 0xff);
163             //pad[padLen-9] = (byte) ((bitCount >> 64) & 0xff);
164             pad[padLen-8] = (byte) ((bitCount >> 56) & 0xff);
165             pad[padLen-7] = (byte) ((bitCount >> 48) & 0xff);
166             pad[padLen-6] = (byte) ((bitCount >> 40) & 0xff);
167             pad[padLen-5] = (byte) ((bitCount >> 32) & 0xff);
168             pad[padLen-4] = (byte) ((bitCount >> 24) & 0xff);
169             pad[padLen-3] = (byte) ((bitCount >> 16) & 0xff);
170             pad[padLen-2] = (byte) ((bitCount >> 8) & 0xff);
171             pad[padLen-1] = (byte) ((bitCount >> 0) & 0xff);
172
173             /* Digest padding */
174             _HashData(pad, 0, pad.Length);
175
176             /* Store digest */
177             Utils.QuadWordToBigEndian (hash, _stateSHA384, 6);
178
179             HashValue = hash;
180             return hash;
181         }
182
183         private readonly static UInt64[] _K = {
184             0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
185             0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
186             0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
187             0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
188             0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
189             0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
190             0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
191             0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
192             0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
193             0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
194             0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
195             0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
196             0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
197             0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
198             0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
199             0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
200             0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
201             0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
202             0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
203             0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
204         };
205
206         [System.Security.SecurityCritical]  // auto-generated
207         private static unsafe void SHATransform (UInt64* expandedBuffer, UInt64* state, byte* block)
208         {
209             UInt64 a, b, c, d, e, f, g, h;
210             UInt64 aa, bb, cc, dd, ee, ff, hh, gg;
211             UInt64 T1;
212
213             a = state[0];
214             b = state[1];
215             c = state[2];
216             d = state[3];
217             e = state[4];
218             f = state[5];
219             g = state[6];
220             h = state[7];
221
222             // fill in the first 16 blocks of W.
223             Utils.QuadWordFromBigEndian (expandedBuffer, 16, block);
224             SHA384Expand (expandedBuffer);
225
226             /* Apply the SHA384 compression function */
227             // We are trying to be smart here and avoid as many copies as we can
228             // The perf gain with this method over the straightforward modify and shift 
229             // forward is >= 20%, so it's worth the pain
230             for (int j=0; j<80; ) {
231                 T1 = h + Sigma_1(e) + Ch(e,f,g) + _K[j] + expandedBuffer[j];
232                 ee = d + T1;
233                 aa = T1 + Sigma_0(a) + Maj(a,b,c);
234                 j++;
235
236                 T1 = g + Sigma_1(ee) + Ch(ee,e,f) + _K[j] + expandedBuffer[j];
237                 ff = c + T1;
238                 bb = T1 + Sigma_0(aa) + Maj(aa,a,b);
239                 j++;
240
241                 T1 = f + Sigma_1(ff) + Ch(ff,ee,e) + _K[j] + expandedBuffer[j];
242                 gg = b + T1;
243                 cc = T1 + Sigma_0(bb) + Maj(bb,aa,a);
244                 j++;
245
246                 T1 = e + Sigma_1(gg) + Ch(gg,ff,ee) + _K[j] + expandedBuffer[j];
247                 hh = a + T1;
248                 dd = T1 + Sigma_0(cc) + Maj(cc,bb,aa);
249                 j++;
250
251                 T1 = ee + Sigma_1(hh) + Ch(hh,gg,ff) + _K[j] + expandedBuffer[j];
252                 h = aa + T1;
253                 d = T1 + Sigma_0(dd) + Maj(dd,cc,bb);
254                 j++;
255
256                 T1 = ff + Sigma_1(h) + Ch(h,hh,gg) + _K[j] + expandedBuffer[j];
257                 g = bb + T1;
258                 c = T1 + Sigma_0(d) + Maj(d,dd,cc);
259                 j++;
260
261                 T1 = gg + Sigma_1(g) + Ch(g,h,hh) + _K[j] + expandedBuffer[j];
262                 f = cc + T1;
263                 b = T1 + Sigma_0(c) + Maj(c,d,dd);
264                 j++;
265
266                 T1 = hh + Sigma_1(f) + Ch(f,g,h) + _K[j] + expandedBuffer[j];
267                 e = dd + T1;
268                 a = T1 + Sigma_0(b) + Maj(b,c,d);
269                 j++;
270             }
271
272             state[0] += a;
273             state[1] += b;
274             state[2] += c;
275             state[3] += d;
276             state[4] += e;
277             state[5] += f;
278             state[6] += g;
279             state[7] += h;
280         }
281
282         private static UInt64 RotateRight(UInt64 x, int n) {
283             return (((x) >> (n)) | ((x) << (64-(n))));
284         }
285
286         private static UInt64 Ch(UInt64 x, UInt64 y, UInt64 z) {
287             return ((x & y) ^ ((x ^ 0xffffffffffffffff) & z));
288         }
289
290         private static UInt64 Maj(UInt64 x, UInt64 y, UInt64 z) {
291             return ((x & y) ^ (x & z) ^ (y & z));
292         }
293
294         private static UInt64 Sigma_0(UInt64 x) {
295             return (RotateRight(x,28) ^ RotateRight(x,34) ^ RotateRight(x,39));
296         }
297
298         private static UInt64 Sigma_1(UInt64 x) {
299             return (RotateRight(x,14) ^ RotateRight(x,18) ^ RotateRight(x,41));
300         }
301
302         private static UInt64 sigma_0(UInt64 x) {
303             return (RotateRight(x,1) ^ RotateRight(x,8) ^ (x >> 7));
304         }
305
306         private static UInt64 sigma_1(UInt64 x) {
307             return (RotateRight(x,19) ^ RotateRight(x,61) ^ (x >> 6));
308         }
309
310         /* This function creates W_16,...,W_79 according to the formula
311            W_j <- sigma_1(W_{j-2}) + W_{j-7} + sigma_0(W_{j-15}) + W_{j-16};
312         */
313
314         [System.Security.SecurityCritical]  // auto-generated
315         private static unsafe void SHA384Expand (UInt64* x)
316         {
317             for (int i = 16; i < 80; i++) {
318                 x[i] = sigma_1(x[i-2]) + x[i-7] + sigma_0(x[i-15]) + x[i-16];
319             }
320         }
321     }
322 }