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.lang.CPStringBuilder;
041    
042    import gnu.java.security.Engine;
043    import java.nio.ByteBuffer;
044    
045    import 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     */
054    public 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    }