Merge pull request #2734 from nealef/master
[mono.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / hashalgorithm.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>[....]</OWNER>
7 // 
8
9 //
10 // HashAlgorithm.cs
11 //
12
13 namespace System.Security.Cryptography {
14     using System.IO;
15     using System.Diagnostics.Contracts;
16
17     [System.Runtime.InteropServices.ComVisible(true)]
18     public abstract class HashAlgorithm : IDisposable, ICryptoTransform {
19         protected int HashSizeValue;
20         protected internal byte[] HashValue;
21         protected int State = 0;
22
23         private bool m_bDisposed = false;
24
25         protected HashAlgorithm() {}
26
27         //
28         // public properties
29         //
30
31         public virtual int HashSize {
32             get { return HashSizeValue; }
33         }
34
35         public virtual byte[] Hash {
36             get {
37                 if (m_bDisposed) 
38                     throw new ObjectDisposedException(null);
39                 if (State != 0)
40                     throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_HashNotYetFinalized"));
41                 return (byte[]) HashValue.Clone();
42             }
43         }
44
45         //
46         // public methods
47         //
48
49         static public HashAlgorithm Create() {
50 #if FULL_AOT_RUNTIME
51             return new System.Security.Cryptography.SHA1CryptoServiceProvider ();
52 #else
53             return Create("System.Security.Cryptography.HashAlgorithm");
54 #endif
55         }
56
57         static public HashAlgorithm Create(String hashName) {
58             return (HashAlgorithm) CryptoConfig.CreateFromName(hashName);
59         }
60
61         public byte[] ComputeHash(Stream inputStream) {
62             if (m_bDisposed) 
63                 throw new ObjectDisposedException(null);
64
65             // Default the buffer size to 4K.
66             byte[] buffer = new byte[4096];
67             int bytesRead;
68             do {
69                 bytesRead = inputStream.Read(buffer, 0, 4096);
70                 if (bytesRead > 0) {
71                     HashCore(buffer, 0, bytesRead);
72                 }
73             } while (bytesRead > 0);
74
75             HashValue = HashFinal();
76             byte[] Tmp = (byte[]) HashValue.Clone();
77             Initialize();
78             return(Tmp);
79         }
80
81         public byte[] ComputeHash(byte[] buffer) {
82             if (m_bDisposed) 
83                 throw new ObjectDisposedException(null);
84
85             // Do some validation
86             if (buffer == null) throw new ArgumentNullException("buffer");
87
88             HashCore(buffer, 0, buffer.Length);
89             HashValue = HashFinal();
90             byte[] Tmp = (byte[]) HashValue.Clone();
91             Initialize();
92             return(Tmp);
93         }
94
95         public byte[] ComputeHash(byte[] buffer, int offset, int count) {
96             // Do some validation
97             if (buffer == null)
98                 throw new ArgumentNullException("buffer");
99             if (offset < 0)
100                 throw new ArgumentOutOfRangeException("offset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
101             if (count < 0 || (count > buffer.Length))
102                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
103             if ((buffer.Length - count) < offset)
104                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
105             Contract.EndContractBlock();
106
107             if (m_bDisposed)
108                 throw new ObjectDisposedException(null);
109
110             HashCore(buffer, offset, count);
111             HashValue = HashFinal();
112             byte[] Tmp = (byte[]) HashValue.Clone();
113             Initialize();
114             return(Tmp);
115         }
116
117         // ICryptoTransform methods
118
119         // we assume any HashAlgorithm can take input a byte at a time
120         public virtual int InputBlockSize { 
121             get { return(1); }
122         }
123
124         public virtual int OutputBlockSize {
125             get { return(1); }
126         }
127
128         public virtual bool CanTransformMultipleBlocks { 
129             get { return(true); }
130         }
131
132         public virtual bool CanReuseTransform { 
133             get { return(true); }
134         }
135
136         // We implement TransformBlock and TransformFinalBlock here
137         public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) {
138             // Do some validation, we let BlockCopy do the destination array validation
139             if (inputBuffer == null)
140                 throw new ArgumentNullException("inputBuffer");
141             if (inputOffset < 0)
142                 throw new ArgumentOutOfRangeException("inputOffset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
143             if (inputCount < 0 || (inputCount > inputBuffer.Length))
144                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
145             if ((inputBuffer.Length - inputCount) < inputOffset)
146                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
147             Contract.EndContractBlock();
148
149             if (m_bDisposed)
150                 throw new ObjectDisposedException(null);
151
152             // Change the State value
153             State = 1;
154             HashCore(inputBuffer, inputOffset, inputCount);
155             if ((outputBuffer != null) && ((inputBuffer != outputBuffer) || (inputOffset != outputOffset)))
156                 Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
157             return inputCount;
158         }
159
160         public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) {
161             // Do some validation
162             if (inputBuffer == null)
163                 throw new ArgumentNullException("inputBuffer");
164             if (inputOffset < 0)
165                 throw new ArgumentOutOfRangeException("inputOffset", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
166             if (inputCount < 0 || (inputCount > inputBuffer.Length))
167                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidValue"));
168             if ((inputBuffer.Length - inputCount) < inputOffset)
169                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
170             Contract.EndContractBlock();
171
172             if (m_bDisposed)
173                 throw new ObjectDisposedException(null);
174
175             HashCore(inputBuffer, inputOffset, inputCount);
176             HashValue = HashFinal();
177             byte[] outputBytes;
178             if (inputCount != 0)
179             {
180                 outputBytes = new byte[inputCount];
181                 Buffer.InternalBlockCopy(inputBuffer, inputOffset, outputBytes, 0, inputCount);
182             }
183             else
184             {
185                 outputBytes = EmptyArray<Byte>.Value;
186             }
187             // reset the State value
188             State = 0;
189             return outputBytes;
190         }
191
192         // IDisposable methods
193
194         // To keep mscorlib compatibility with Orcas, CoreCLR's HashAlgorithm has an explicit IDisposable
195         // implementation. Post-Orcas the desktop has an implicit IDispoable implementation.
196 #if FEATURE_CORECLR
197         void IDisposable.Dispose()
198         {
199             Dispose();
200         }
201 #endif // FEATURE_CORECLR
202
203         public void Dispose()
204         {
205             Dispose(true);
206             GC.SuppressFinalize(this);
207         }
208
209         public void Clear() {
210             (this as IDisposable).Dispose();
211         }
212
213         protected virtual void Dispose(bool disposing) {
214             if (disposing) {
215                 if (HashValue != null)
216                     Array.Clear(HashValue, 0, HashValue.Length);
217                 HashValue = null;
218                 m_bDisposed = true;
219             }
220         }
221
222         //
223         // abstract public methods
224         //
225
226         public abstract void Initialize();
227
228         protected abstract void HashCore(byte[] array, int ibStart, int cbSize);
229
230         protected abstract byte[] HashFinal();
231     }
232 }