2005-04-12 Dick Porter <dick@ximian.com>
[mono.git] / mcs / class / corlib / System.Security.Cryptography / HashAlgorithm.cs
1 //
2 // System.Security.Cryptography HashAlgorithm Class implementation
3 //
4 // Authors:
5 //      Matthew S. Ford (Matthew.S.Ford@Rose-Hulman.Edu)
6 //      Sebastien Pouliot (sebastien@ximian.com)
7 //
8 // Copyright 2001 by Matthew S. Ford.
9 // Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com)
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Globalization;
33 using System.IO;
34
35 namespace System.Security.Cryptography {
36
37         public abstract class HashAlgorithm : ICryptoTransform {
38
39                 protected byte[] HashValue;
40                 protected int HashSizeValue;
41                 protected int State;
42                 private bool disposed;
43
44                 protected HashAlgorithm () 
45                 {
46                         disposed = false;
47                 }
48
49                 public virtual bool CanTransformMultipleBlocks {
50                         get { return true; }
51                 }
52
53                 public virtual bool CanReuseTransform {
54                         get { return true; }
55                 }
56
57                 public void Clear () 
58                 {
59                         // same as System.IDisposable.Dispose() which is documented
60                         Dispose (true);
61                 }
62
63                 public byte[] ComputeHash (byte[] input) 
64                 {
65                         if (input == null)
66                                 throw new ArgumentNullException ("input");
67
68                         return ComputeHash (input, 0, input.Length);
69                 }
70
71                 public byte[] ComputeHash (byte[] buffer, int offset, int count) 
72                 {
73                         if (disposed)
74                                 throw new ObjectDisposedException ("HashAlgorithm");
75                         if (buffer == null)
76                                 throw new ArgumentNullException ("buffer");
77                         if (offset < 0)
78                                 throw new ArgumentOutOfRangeException ("offset", "< 0");
79                         if (count < 0)
80                                 throw new ArgumentException ("count", "< 0");
81                         // ordered to avoid possible integer overflow
82                         if (offset > buffer.Length - count) {
83                                 throw new ArgumentException ("offset + count", 
84                                         Locale.GetText ("Overflow"));
85                         }
86
87                         HashCore (buffer, offset, count);
88                         HashValue = HashFinal ();
89                         Initialize ();
90                         
91                         return HashValue;
92                 }
93
94                 public byte[] ComputeHash (Stream inputStream) 
95                 {
96                         // don't read stream unless object is ready to use
97                         if (disposed)
98                                 throw new ObjectDisposedException ("HashAlgorithm");
99
100                         byte[] buffer = new byte [4096];
101                         int len = inputStream.Read (buffer, 0, 4096);
102                         while (len > 0) {
103                                 HashCore (buffer, 0, len);
104                                 len = inputStream.Read (buffer, 0, 4096);
105                         }
106                         HashValue = HashFinal ();
107                         Initialize ();
108                         return HashValue;
109                 }
110         
111                 public static HashAlgorithm Create () 
112                 {
113                         return Create ("System.Security.Cryptography.HashAlgorithm");
114                 }
115         
116                 public static HashAlgorithm Create (string hashName)
117                 {
118                         return (HashAlgorithm) CryptoConfig.CreateFromName (hashName);
119                 }
120         
121                 public virtual byte[] Hash {
122                         get { 
123                                 if (HashValue == null) {
124                                         throw new CryptographicUnexpectedOperationException (
125                                                 Locale.GetText ("No hash value computed."));
126                                 }
127                                 return HashValue; 
128                         }
129                 }
130         
131                 protected abstract void HashCore (byte[] rgb, int start, int size);
132
133                 protected abstract byte[] HashFinal ();
134
135                 public virtual int HashSize {
136                         get { return HashSizeValue; }
137                 }
138         
139                 public abstract void Initialize ();
140
141                 protected virtual void Dispose (bool disposing)
142                 {
143                         disposed = true;
144                 }
145         
146                 public virtual int InputBlockSize {
147                         get { return 1; }
148                 }
149         
150                 public virtual int OutputBlockSize {
151                         get { return 1; }
152                 }
153
154                 void IDisposable.Dispose () 
155                 {
156                         Dispose (true);
157                         GC.SuppressFinalize (this);  // Finalization is now unnecessary
158                 }
159                 
160                 public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) 
161                 {
162                         if (inputBuffer == null)
163                                 throw new ArgumentNullException ("inputBuffer");
164                         if (outputBuffer == null)
165                                 throw new ArgumentNullException ("outputBuffer");
166
167                         if (inputOffset < 0)
168                                 throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
169                         if (inputCount < 0)
170                                 throw new ArgumentException ("inputCount");
171
172                         // ordered to avoid possible integer overflow
173                         if ((inputOffset < 0) || (inputOffset > inputBuffer.Length - inputCount))
174                                 throw new ArgumentException ("inputBuffer");
175                         if (outputOffset < 0) {
176 #if NET_2_0
177                                 throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
178 #else
179                                 throw new IndexOutOfRangeException ("outputBuffer");
180 #endif
181                         }
182                         if (outputOffset > outputBuffer.Length - inputCount) {
183 #if NET_2_0
184                                 throw new ArgumentException ("outputOffset + inputCount", 
185                                         Locale.GetText ("Overflow"));
186 #else
187                                 throw new IndexOutOfRangeException ("outputBuffer");
188 #endif
189                         }
190                         // ordered to avoid possible integer overflow
191
192                         // note: other exceptions are handled by Buffer.BlockCopy
193                         Buffer.BlockCopy (inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
194                         HashCore (inputBuffer, inputOffset, inputCount);
195
196                         return inputCount;
197                 }
198         
199                 public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount) 
200                 {
201                         if (inputBuffer == null)
202                                 throw new ArgumentNullException ("inputBuffer");
203                         if (inputCount < 0)
204                                 throw new ArgumentException ("inputCount");
205                         // ordered to avoid possible integer overflow
206                         if (inputOffset > inputBuffer.Length - inputCount) {
207                                 throw new ArgumentException ("inputOffset + inputCount", 
208                                         Locale.GetText ("Overflow"));
209                         }
210
211                         byte[] outputBuffer = new byte [inputCount];
212                         
213                         // note: other exceptions are handled by Buffer.BlockCopy
214                         Buffer.BlockCopy (inputBuffer, inputOffset, outputBuffer, 0, inputCount);
215                         
216                         HashCore (inputBuffer, inputOffset, inputCount);
217                         HashValue = HashFinal ();
218                         Initialize ();
219                         
220                         return outputBuffer;
221                 }
222         }
223 }