001 /* MessageDigest.java --- The message digest interface.
002 Copyright (C) 1999, 2002, 2003, 2006 Free Software Foundation, Inc.
003
004 This file is part of GNU Classpath.
005
006 GNU Classpath is free software; you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation; either version 2, or (at your option)
009 any later version.
010
011 GNU Classpath is distributed in the hope that it will be useful, but
012 WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with GNU Classpath; see the file COPYING. If not, write to the
018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019 02110-1301 USA.
020
021 Linking this library statically or dynamically with other modules is
022 making a combined work based on this library. Thus, the terms and
023 conditions of the GNU General Public License cover the whole
024 combination.
025
026 As a special exception, the copyright holders of this library give you
027 permission to link this library with independent modules to produce an
028 executable, regardless of the license terms of these independent
029 modules, and to copy and distribute the resulting executable under
030 terms of your choice, provided that you also meet, for each linked
031 independent module, the terms and conditions of the license of that
032 module. An independent module is a module which is not derived from
033 or based on this library. If you modify this library, you may extend
034 this exception to your version of the library, but you are not
035 obligated to do so. If you do not wish to do so, delete this
036 exception statement from your version. */
037
038 package java.security;
039
040 import gnu.java.security.Engine;
041 import java.nio.ByteBuffer;
042
043 import java.lang.reflect.InvocationTargetException;
044
045 /**
046 * Message digests are secure one-way hash functions that take arbitrary-sized
047 * data and output a fixed-length hash value.
048 *
049 * @see MessageDigestSpi
050 * @since JDK 1.1
051 */
052 public abstract class MessageDigest extends MessageDigestSpi
053 {
054 /** The service name for message digests. */
055 private static final String MESSAGE_DIGEST = "MessageDigest";
056
057 private String algorithm;
058 Provider provider;
059 private byte[] lastDigest;
060
061 /**
062 * Constructs a new instance of <code>MessageDigest</code> representing the
063 * specified algorithm.
064 *
065 * @param algorithm
066 * the name of the digest algorithm to use.
067 */
068 protected MessageDigest(String algorithm)
069 {
070 this.algorithm = algorithm;
071 provider = null;
072 }
073
074 /**
075 * Returns a new instance of <code>MessageDigest</code> representing the
076 * specified algorithm.
077 *
078 * @param algorithm the name of the digest algorithm to use.
079 * @return a new instance representing the desired algorithm.
080 * @throws NoSuchAlgorithmException if the algorithm is not implemented by any
081 * provider.
082 * @throws IllegalArgumentException if <code>algorithm</code> is
083 * <code>null</code> or is an empty string.
084 */
085 public static MessageDigest getInstance(String algorithm)
086 throws NoSuchAlgorithmException
087 {
088 Provider[] p = Security.getProviders();
089 NoSuchAlgorithmException lastException = null;
090 for (int i = 0; i < p.length; i++)
091 try
092 {
093 return getInstance(algorithm, p[i]);
094 }
095 catch (NoSuchAlgorithmException x)
096 {
097 lastException = x;
098 }
099 if (lastException != null)
100 throw lastException;
101 throw new NoSuchAlgorithmException(algorithm);
102 }
103
104 /**
105 * Returns a new instance of <code>MessageDigest</code> representing the
106 * specified algorithm from a named provider.
107 *
108 * @param algorithm the name of the digest algorithm to use.
109 * @param provider the name of the provider to use.
110 * @return a new instance representing the desired algorithm.
111 * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
112 * named provider.
113 * @throws NoSuchProviderException if the named provider was not found.
114 * @throws IllegalArgumentException if either <code>algorithm</code> or
115 * <code>provider</code> is <code>null</code> or empty.
116 */
117 public static MessageDigest getInstance(String algorithm, String provider)
118 throws NoSuchAlgorithmException, NoSuchProviderException
119 {
120 if (provider == null)
121 throw new IllegalArgumentException("provider MUST NOT be null");
122 provider = provider.trim();
123 if (provider.length() == 0)
124 throw new IllegalArgumentException("provider MUST NOT be empty");
125 Provider p = Security.getProvider(provider);
126 if (p == null)
127 throw new NoSuchProviderException(provider);
128 return getInstance(algorithm, p);
129 }
130
131 /**
132 * Returns a new instance of <code>MessageDigest</code> representing the
133 * specified algorithm from a designated {@link Provider}.
134 *
135 * @param algorithm the name of the digest algorithm to use.
136 * @param provider the {@link Provider} to use.
137 * @return a new instance representing the desired algorithm.
138 * @throws NoSuchAlgorithmException if the algorithm is not implemented by
139 * {@link Provider}.
140 * @throws IllegalArgumentException if either <code>algorithm</code> or
141 * <code>provider</code> is <code>null</code>, or if
142 * <code>algorithm</code> is an empty string.
143 * @since 1.4
144 * @see Provider
145 */
146 public static MessageDigest getInstance(String algorithm, Provider provider)
147 throws NoSuchAlgorithmException
148 {
149 StringBuilder sb = new StringBuilder("MessageDigest for algorithm [")
150 .append(algorithm).append("] from provider[")
151 .append(provider).append("] ");
152 Object o;
153 try
154 {
155 o = Engine.getInstance(MESSAGE_DIGEST, algorithm, provider);
156 }
157 catch (InvocationTargetException x)
158 {
159 Throwable cause = x.getCause();
160 if (cause instanceof NoSuchAlgorithmException)
161 throw (NoSuchAlgorithmException) cause;
162 if (cause == null)
163 cause = x;
164 sb.append("could not be created");
165 NoSuchAlgorithmException y = new NoSuchAlgorithmException(sb.toString());
166 y.initCause(cause);
167 throw y;
168 }
169 MessageDigest result;
170 if (o instanceof MessageDigestSpi)
171 result = new DummyMessageDigest((MessageDigestSpi) o, algorithm);
172 else if (o instanceof MessageDigest)
173 {
174 result = (MessageDigest) o;
175 result.algorithm = algorithm;
176 }
177 else
178 {
179 sb.append("is of an unexpected Type: ").append(o.getClass().getName());
180 throw new NoSuchAlgorithmException(sb.toString());
181 }
182 result.provider = provider;
183 return result;
184 }
185
186 /**
187 * Returns the {@link Provider} of this instance.
188 *
189 * @return the {@link Provider} of this instance.
190 */
191 public final Provider getProvider()
192 {
193 return provider;
194 }
195
196 /**
197 * Updates the digest with the byte.
198 *
199 * @param input byte to update the digest with.
200 */
201 public void update(byte input)
202 {
203 engineUpdate(input);
204 }
205
206 /**
207 * Updates the digest with the bytes from the array starting from the
208 * specified offset and using the specified length of bytes.
209 *
210 * @param input
211 * bytes to update the digest with.
212 * @param offset
213 * the offset to start at.
214 * @param len
215 * length of the data to update with.
216 */
217 public void update(byte[] input, int offset, int len)
218 {
219 engineUpdate(input, offset, len);
220 }
221
222 /**
223 * Updates the digest with the bytes of an array.
224 *
225 * @param input bytes to update the digest with.
226 */
227 public void update(byte[] input)
228 {
229 engineUpdate(input, 0, input.length);
230 }
231
232 /**
233 * Updates the digest with the remaining bytes of a buffer.
234 *
235 * @param input The input byte buffer.
236 * @since 1.5
237 */
238 public void update (ByteBuffer input)
239 {
240 engineUpdate (input);
241 }
242
243 /**
244 * Computes the final digest of the stored data.
245 *
246 * @return a byte array representing the message digest.
247 */
248 public byte[] digest()
249 {
250 return lastDigest = engineDigest();
251 }
252
253 /**
254 * Computes the final digest of the stored bytes and returns the result.
255 *
256 * @param buf
257 * an array of bytes to store the result in.
258 * @param offset
259 * an offset to start storing the result at.
260 * @param len
261 * the length of the buffer.
262 * @return Returns the length of the buffer.
263 */
264 public int digest(byte[] buf, int offset, int len) throws DigestException
265 {
266 return engineDigest(buf, offset, len);
267 }
268
269 /**
270 * Computes a final update using the input array of bytes, then computes a
271 * final digest and returns it. It calls {@link #update(byte[])} and then
272 * {@link #digest(byte[])}.
273 *
274 * @param input
275 * an array of bytes to perform final update with.
276 * @return a byte array representing the message digest.
277 */
278 public byte[] digest(byte[] input)
279 {
280 update(input);
281 return digest();
282 }
283
284 /**
285 * Returns a string representation of this instance.
286 *
287 * @return a string representation of this instance.
288 */
289 public String toString()
290 {
291 return (getClass()).getName() + " Message Digest <" + digestToString() + ">";
292 }
293
294 /**
295 * Does a simple byte comparison of the two digests.
296 *
297 * @param digesta
298 * first digest to compare.
299 * @param digestb
300 * second digest to compare.
301 * @return <code>true</code> if both are equal, <code>false</code>
302 * otherwise.
303 */
304 public static boolean isEqual(byte[] digesta, byte[] digestb)
305 {
306 if (digesta.length != digestb.length)
307 return false;
308
309 for (int i = digesta.length - 1; i >= 0; --i)
310 if (digesta[i] != digestb[i])
311 return false;
312
313 return true;
314 }
315
316 /** Resets this instance. */
317 public void reset()
318 {
319 engineReset();
320 }
321
322 /**
323 * Returns the name of message digest algorithm.
324 *
325 * @return the name of message digest algorithm.
326 */
327 public final String getAlgorithm()
328 {
329 return algorithm;
330 }
331
332 /**
333 * Returns the length of the message digest. The default is zero which means
334 * that the concrete implementation does not implement this method.
335 *
336 * @return length of the message digest.
337 * @since 1.2
338 */
339 public final int getDigestLength()
340 {
341 return engineGetDigestLength();
342 }
343
344 /**
345 * Returns a clone of this instance if cloning is supported. If it does not
346 * then a {@link CloneNotSupportedException} is thrown. Cloning depends on
347 * whether the subclass {@link MessageDigestSpi} implements {@link Cloneable}
348 * which contains the actual implementation of the appropriate algorithm.
349 *
350 * @return a clone of this instance.
351 * @throws CloneNotSupportedException
352 * the implementation does not support cloning.
353 */
354 public Object clone() throws CloneNotSupportedException
355 {
356 return super.clone();
357 }
358
359 private String digestToString()
360 {
361 byte[] digest = lastDigest;
362
363 if (digest == null)
364 return "incomplete";
365
366 StringBuffer buf = new StringBuffer();
367 int len = digest.length;
368 for (int i = 0; i < len; ++i)
369 {
370 byte b = digest[i];
371 byte high = (byte) ((b & 0xff) >>> 4);
372 byte low = (byte) (b & 0xf);
373
374 buf.append(high > 9 ? ('a' - 10) + high : '0' + high);
375 buf.append(low > 9 ? ('a' - 10) + low : '0' + low);
376 }
377
378 return buf.toString();
379 }
380 }