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