863cea2e1839bed53f46589811dc402cb37c373a
[mono.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / sha1managed.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 // 
8
9 //
10 // SHA1Managed.cs
11 //
12
13 namespace System.Security.Cryptography {
14     using System;
15     using System.Security;
16     using System.Diagnostics.Contracts;
17
18     [System.Runtime.InteropServices.ComVisible(true)]
19     public class SHA1Managed : SHA1
20     {
21         private byte[] _buffer;
22         private long   _count; // Number of bytes in the hashed message
23         private uint[] _stateSHA1;
24         private uint[] _expandedBuffer;
25
26         //
27         // public constructors
28         //
29
30         public SHA1Managed()
31         {
32 #if FEATURE_CRYPTO
33             if (CryptoConfig.AllowOnlyFipsAlgorithms)
34                 throw new InvalidOperationException(Environment.GetResourceString("Cryptography_NonCompliantFIPSAlgorithm"));
35             Contract.EndContractBlock();
36 #endif // FEATURE_CRYPTO
37
38             _stateSHA1 = new uint[5];
39             _buffer = new byte[64];
40             _expandedBuffer = new uint[80];
41
42             InitializeState();
43         }
44
45         //
46         // public methods
47         //
48
49         public override void Initialize() {
50             InitializeState();
51
52             // Zeroize potentially sensitive information.
53             Array.Clear(_buffer, 0, _buffer.Length);
54             Array.Clear(_expandedBuffer, 0, _expandedBuffer.Length);
55         }
56
57         protected override void HashCore(byte[] rgb, int ibStart, int cbSize) {
58             _HashData(rgb, ibStart, cbSize);
59         }
60
61         protected override byte[] HashFinal() {
62             return _EndHash();
63         }
64
65         //
66         // private methods
67         //
68
69         private void InitializeState() {
70             _count = 0;
71
72             _stateSHA1[0] =  0x67452301;
73             _stateSHA1[1] =  0xefcdab89;
74             _stateSHA1[2] =  0x98badcfe;
75             _stateSHA1[3] =  0x10325476;
76             _stateSHA1[4] =  0xc3d2e1f0;
77         }
78
79         /* Copyright (C) RSA Data Security, Inc. created 1993.  This is an
80            unpublished work protected as such under copyright law.  This work
81            contains proprietary, confidential, and trade secret information of
82            RSA Data Security, Inc.  Use, disclosure or reproduction without the
83            express written authorization of RSA Data Security, Inc. is
84            prohibited.
85            */
86
87         /* SHA block update operation. Continues an SHA message-digest
88            operation, processing another message block, and updating the
89            context.
90            */
91         [System.Security.SecuritySafeCritical]  // auto-generated
92         private unsafe void _HashData(byte[] partIn, int ibStart, int cbSize)
93         {
94             int bufferLen;
95             int partInLen = cbSize;
96             int partInBase = ibStart;
97
98             /* Compute length of buffer */
99             bufferLen = (int) (_count & 0x3f);
100
101             /* Update number of bytes */
102             _count += partInLen;
103
104             fixed (uint* stateSHA1 = _stateSHA1) {
105                 fixed (byte* buffer = _buffer) {
106                     fixed (uint* expandedBuffer = _expandedBuffer) {
107                         if ((bufferLen > 0) && (bufferLen + partInLen >= 64)) {
108                             Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, 64 - bufferLen);
109                             partInBase += (64 - bufferLen);
110                             partInLen -= (64 - bufferLen);
111                             SHATransform(expandedBuffer, stateSHA1, buffer);
112                             bufferLen = 0;
113                         }
114
115                         /* Copy input to temporary buffer and hash */
116                         while (partInLen >= 64) {
117                             Buffer.InternalBlockCopy(partIn, partInBase, _buffer, 0, 64);
118                             partInBase += 64;
119                             partInLen -= 64;
120                             SHATransform(expandedBuffer, stateSHA1, buffer);
121                         }
122
123                         if (partInLen > 0) {
124                             Buffer.InternalBlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen);
125                         }
126                     }
127                 }
128             }
129         }
130
131         /* SHA finalization. Ends an SHA message-digest operation, writing
132            the message digest.
133             */
134
135         private byte[] _EndHash()
136         {
137             byte[]          pad;
138             int             padLen;
139             long            bitCount;
140             byte[]          hash = new byte[20];
141
142             /* Compute padding: 80 00 00 ... 00 00 <bit count>
143              */
144
145             padLen = 64 - (int)(_count & 0x3f);
146             if (padLen <= 8)
147                 padLen += 64;
148
149             pad = new byte[padLen];
150             pad[0] = 0x80;
151
152             //  Convert count to bit count
153             bitCount = _count * 8;
154
155             pad[padLen-8] = (byte) ((bitCount >> 56) & 0xff);
156             pad[padLen-7] = (byte) ((bitCount >> 48) & 0xff);
157             pad[padLen-6] = (byte) ((bitCount >> 40) & 0xff);
158             pad[padLen-5] = (byte) ((bitCount >> 32) & 0xff);
159             pad[padLen-4] = (byte) ((bitCount >> 24) & 0xff);
160             pad[padLen-3] = (byte) ((bitCount >> 16) & 0xff);
161             pad[padLen-2] = (byte) ((bitCount >> 8) & 0xff);
162             pad[padLen-1] = (byte) ((bitCount >> 0) & 0xff);
163
164             /* Digest padding */
165             _HashData(pad, 0, pad.Length);
166
167             /* Store digest */
168             Utils.DWORDToBigEndian (hash, _stateSHA1, 5);
169
170             HashValue = hash;
171             return hash;
172         }
173
174         [System.Security.SecurityCritical]  // auto-generated
175         private static unsafe void SHATransform (uint* expandedBuffer, uint* state, byte* block)
176         {
177             uint a = state[0];
178             uint b = state[1];
179             uint c = state[2];
180             uint d = state[3];
181             uint e = state[4];
182
183             int i;
184
185             Utils.DWORDFromBigEndian(expandedBuffer, 16, block);
186             SHAExpand(expandedBuffer);
187
188             /* Round 1 */
189             for (i=0; i<20; i+= 5) {
190                 { (e) +=  (((((a)) << (5)) | (((a)) >> (32-(5)))) + ( (d) ^ ( (b) & ( (c) ^ (d) ) ) ) + (expandedBuffer[i]) + 0x5a827999); (b) =  ((((b)) << (30)) | (((b)) >> (32-(30)))); }
191                 { (d) +=  (((((e)) << (5)) | (((e)) >> (32-(5)))) + ( (c) ^ ( (a) & ( (b) ^ (c) ) ) ) + (expandedBuffer[i+1]) + 0x5a827999); (a) =  ((((a)) << (30)) | (((a)) >> (32-(30)))); }
192                 { (c) +=  (((((d)) << (5)) | (((d)) >> (32-(5)))) + ( (b) ^ ( (e) & ( (a) ^ (b) ) ) ) + (expandedBuffer[i+2]) + 0x5a827999); (e) =  ((((e)) << (30)) | (((e)) >> (32-(30)))); };;
193                 { (b) +=  (((((c)) << (5)) | (((c)) >> (32-(5)))) + ( (a) ^ ( (d) & ( (e) ^ (a) ) ) ) + (expandedBuffer[i+3]) + 0x5a827999); (d) =  ((((d)) << (30)) | (((d)) >> (32-(30)))); };;
194                 { (a) +=  (((((b)) << (5)) | (((b)) >> (32-(5)))) + ( (e) ^ ( (c) & ( (d) ^ (e) ) ) ) + (expandedBuffer[i+4]) + 0x5a827999); (c) =  ((((c)) << (30)) | (((c)) >> (32-(30)))); };;
195             }
196
197             /* Round 2 */
198             for (; i<40; i+= 5) {
199                 { (e) +=  (((((a)) << (5)) | (((a)) >> (32-(5)))) + ((b) ^ (c) ^ (d)) + (expandedBuffer[i]) + 0x6ed9eba1); (b) =  ((((b)) << (30)) | (((b)) >> (32-(30)))); };;
200                 { (d) +=  (((((e)) << (5)) | (((e)) >> (32-(5)))) + ((a) ^ (b) ^ (c)) + (expandedBuffer[i+1]) + 0x6ed9eba1); (a) =  ((((a)) << (30)) | (((a)) >> (32-(30)))); };;
201                 { (c) +=  (((((d)) << (5)) | (((d)) >> (32-(5)))) + ((e) ^ (a) ^ (b)) + (expandedBuffer[i+2]) + 0x6ed9eba1); (e) =  ((((e)) << (30)) | (((e)) >> (32-(30)))); };;
202                 { (b) +=  (((((c)) << (5)) | (((c)) >> (32-(5)))) + ((d) ^ (e) ^ (a)) + (expandedBuffer[i+3]) + 0x6ed9eba1); (d) =  ((((d)) << (30)) | (((d)) >> (32-(30)))); };;
203                 { (a) +=  (((((b)) << (5)) | (((b)) >> (32-(5)))) + ((c) ^ (d) ^ (e)) + (expandedBuffer[i+4]) + 0x6ed9eba1); (c) =  ((((c)) << (30)) | (((c)) >> (32-(30)))); };;
204             }
205
206             /* Round 3 */
207             for (; i<60; i+=5) {
208                 { (e) +=  (((((a)) << (5)) | (((a)) >> (32-(5)))) + ( ( (b) & (c) ) | ( (d) & ( (b) | (c) ) ) ) + (expandedBuffer[i]) + 0x8f1bbcdc); (b) =  ((((b)) << (30)) | (((b)) >> (32-(30)))); };;
209                 { (d) +=  (((((e)) << (5)) | (((e)) >> (32-(5)))) + ( ( (a) & (b) ) | ( (c) & ( (a) | (b) ) ) ) + (expandedBuffer[i+1]) + 0x8f1bbcdc); (a) =  ((((a)) << (30)) | (((a)) >> (32-(30)))); };;
210                 { (c) +=  (((((d)) << (5)) | (((d)) >> (32-(5)))) + ( ( (e) & (a) ) | ( (b) & ( (e) | (a) ) ) ) + (expandedBuffer[i+2]) + 0x8f1bbcdc); (e) =  ((((e)) << (30)) | (((e)) >> (32-(30)))); };;
211                 { (b) +=  (((((c)) << (5)) | (((c)) >> (32-(5)))) + ( ( (d) & (e) ) | ( (a) & ( (d) | (e) ) ) ) + (expandedBuffer[i+3]) + 0x8f1bbcdc); (d) =  ((((d)) << (30)) | (((d)) >> (32-(30)))); };;
212                 { (a) +=  (((((b)) << (5)) | (((b)) >> (32-(5)))) + ( ( (c) & (d) ) | ( (e) & ( (c) | (d) ) ) ) + (expandedBuffer[i+4]) + 0x8f1bbcdc); (c) =  ((((c)) << (30)) | (((c)) >> (32-(30)))); };;
213             }
214
215             /* Round 4 */
216             for (; i<80; i+=5) {
217                 { (e) +=  (((((a)) << (5)) | (((a)) >> (32-(5)))) + ((b) ^ (c) ^ (d)) + (expandedBuffer[i]) + 0xca62c1d6); (b) =  ((((b)) << (30)) | (((b)) >> (32-(30)))); };;
218                 { (d) +=  (((((e)) << (5)) | (((e)) >> (32-(5)))) + ((a) ^ (b) ^ (c)) + (expandedBuffer[i+1]) + 0xca62c1d6); (a) =  ((((a)) << (30)) | (((a)) >> (32-(30)))); };;
219                 { (c) +=  (((((d)) << (5)) | (((d)) >> (32-(5)))) + ((e) ^ (a) ^ (b)) + (expandedBuffer[i+2]) + 0xca62c1d6); (e) =  ((((e)) << (30)) | (((e)) >> (32-(30)))); };;
220                 { (b) +=  (((((c)) << (5)) | (((c)) >> (32-(5)))) + ((d) ^ (e) ^ (a)) + (expandedBuffer[i+3]) + 0xca62c1d6); (d) =  ((((d)) << (30)) | (((d)) >> (32-(30)))); };;
221                 { (a) +=  (((((b)) << (5)) | (((b)) >> (32-(5)))) + ((c) ^ (d) ^ (e)) + (expandedBuffer[i+4]) + 0xca62c1d6); (c) =  ((((c)) << (30)) | (((c)) >> (32-(30)))); };;
222             }
223
224             state[0] += a;
225             state[1] += b;
226             state[2] += c;
227             state[3] += d;
228             state[4] += e;
229         }
230
231         /* Expands x[0..15] into x[16..79], according to the recurrence
232            x[i] = x[i-3] ^ x[i-8] ^ x[i-14] ^ x[i-16].
233            */
234
235         [System.Security.SecurityCritical]  // auto-generated
236         private static unsafe void SHAExpand (uint* x)
237         {
238             int  i;
239             uint tmp;
240
241             for (i = 16; i < 80; i++) {
242                 tmp =  (x[i-3] ^ x[i-8] ^ x[i-14] ^ x[i-16]);
243                 x[i] =  ((tmp << 1) | (tmp >> 31));
244             }
245         }
246     }
247 }