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    }