Source for java.security.MessageDigest

   1: /* MessageDigest.java --- The message digest interface.
   2:    Copyright (C) 1999, 2002, 2003, 2006 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package java.security;
  39: 
  40: import gnu.java.security.Engine;
  41: 
  42: /**
  43:  * Message digests are secure one-way hash functions that take arbitrary-sized
  44:  * data and output a fixed-length hash value.
  45:  *
  46:  * @see MessageDigestSpi
  47:  * @since JDK 1.1
  48:  */
  49: public abstract class MessageDigest extends MessageDigestSpi
  50: {
  51:   /** The service name for message digests. */
  52:   private static final String MESSAGE_DIGEST = "MessageDigest";
  53: 
  54:   private String algorithm;
  55:   Provider provider;
  56:   private byte[] lastDigest;
  57: 
  58:   /**
  59:    * Constructs a new instance of <code>MessageDigest</code> representing the
  60:    * specified algorithm.
  61:    * 
  62:    * @param algorithm
  63:    *          the name of the digest algorithm to use.
  64:    */
  65:   protected MessageDigest(String algorithm)
  66:   {
  67:     this.algorithm = algorithm;
  68:     provider = null;
  69:   }
  70: 
  71:   /**
  72:    * Returns a new instance of <code>MessageDigest</code> representing the
  73:    * specified algorithm.
  74:    * 
  75:    * @param algorithm
  76:    *          the name of the digest algorithm to use.
  77:    * @return a new instance representing the desired algorithm.
  78:    * @throws NoSuchAlgorithmException
  79:    *           if the algorithm is not implemented by any provider.
  80:    */
  81:   public static MessageDigest getInstance(String algorithm)
  82:     throws NoSuchAlgorithmException
  83:   {
  84:     Provider[] p = Security.getProviders();
  85:     for (int i = 0; i < p.length; i++)
  86:       {
  87:         try
  88:           {
  89:             return getInstance(algorithm, p[i]);
  90:           }
  91:         catch (NoSuchAlgorithmException ignored)
  92:       {
  93:         // Ignore.
  94:       }
  95:       }
  96: 
  97:     throw new NoSuchAlgorithmException(algorithm);
  98:   }
  99: 
 100:   /**
 101:    * Returns a new instance of <code>MessageDigest</code> representing the
 102:    * specified algorithm from a named provider.
 103:    * 
 104:    * @param algorithm
 105:    *          the name of the digest algorithm to use.
 106:    * @param provider
 107:    *          the name of the provider to use.
 108:    * @return a new instance representing the desired algorithm.
 109:    * @throws NoSuchAlgorithmException
 110:    *           if the algorithm is not implemented by the named provider.
 111:    * @throws NoSuchProviderException
 112:    *           if the named provider was not found.
 113:    */
 114:   public static MessageDigest getInstance(String algorithm, String provider)
 115:     throws NoSuchAlgorithmException, NoSuchProviderException
 116:   {
 117:     if (provider != null)
 118:       provider = provider.trim();
 119: 
 120:     if (provider == null || provider.length() == 0)
 121:       throw new IllegalArgumentException("Illegal provider");
 122: 
 123:     Provider p = Security.getProvider(provider);
 124:     if (p == null)
 125:       throw new NoSuchProviderException(provider);
 126: 
 127:     return getInstance(algorithm, p);
 128:   }
 129: 
 130:   /**
 131:    * Returns a new instance of <code>MessageDigest</code> representing the
 132:    * specified algorithm from a designated {@link Provider}.
 133:    * 
 134:    * @param algorithm
 135:    *          the name of the digest algorithm to use.
 136:    * @param provider
 137:    *          the {@link Provider} to use.
 138:    * @return a new instance representing the desired algorithm.
 139:    * @throws IllegalArgumentException
 140:    *           if <code>provider</code> is <code>null</code>.
 141:    * @throws NoSuchAlgorithmException
 142:    *           if the algorithm is not implemented by {@link Provider}.
 143:    * @since 1.4
 144:    * @see Provider
 145:    */
 146:   public static MessageDigest getInstance(String algorithm, Provider provider)
 147:     throws NoSuchAlgorithmException
 148:   {
 149:     if (provider == null)
 150:       throw new IllegalArgumentException("Illegal provider");
 151: 
 152:     MessageDigest result = null;
 153:     Object o = null;
 154:     try
 155:       {
 156:         o = Engine.getInstance(MESSAGE_DIGEST, algorithm, provider);
 157:       }
 158:     catch (java.lang.reflect.InvocationTargetException ite)
 159:       {
 160:         throw new NoSuchAlgorithmException(algorithm);
 161:       }
 162: 
 163:     if (o instanceof MessageDigestSpi)
 164:       {
 165:         result = new DummyMessageDigest((MessageDigestSpi) o, algorithm);
 166:       }
 167:     else if (o instanceof MessageDigest)
 168:       {
 169:         result = (MessageDigest) o;
 170:         result.algorithm = algorithm;
 171:       }
 172:     else
 173:       {
 174:         throw new NoSuchAlgorithmException(algorithm);
 175:       }
 176:     result.provider = provider;
 177:     return result;
 178:   }
 179: 
 180:   /**
 181:    * Returns the {@link Provider} of this instance.
 182:    * 
 183:    * @return the {@link Provider} of this instance.
 184:    */
 185:   public final Provider getProvider()
 186:   {
 187:     return provider;
 188:   }
 189: 
 190:   /**
 191:    * Updates the digest with the byte.
 192:    * 
 193:    * @param input byte to update the digest with.
 194:    */
 195:   public void update(byte input)
 196:   {
 197:     engineUpdate(input);
 198:   }
 199: 
 200:   /**
 201:    * Updates the digest with the bytes from the array starting from the
 202:    * specified offset and using the specified length of bytes.
 203:    * 
 204:    * @param input
 205:    *          bytes to update the digest with.
 206:    * @param offset
 207:    *          the offset to start at.
 208:    * @param len
 209:    *          length of the data to update with.
 210:    */
 211:   public void update(byte[] input, int offset, int len)
 212:   {
 213:     engineUpdate(input, offset, len);
 214:   }
 215: 
 216:   /**
 217:    * Updates the digest with the bytes of an array.
 218:    * 
 219:    * @param input bytes to update the digest with.
 220:    */
 221:   public void update(byte[] input)
 222:   {
 223:     engineUpdate(input, 0, input.length);
 224:   }
 225: 
 226:   /**
 227:    * Computes the final digest of the stored data.
 228:    * 
 229:    * @return a byte array representing the message digest.
 230:    */
 231:   public byte[] digest()
 232:   {
 233:     return lastDigest = engineDigest();
 234:   }
 235: 
 236:   /**
 237:    * Computes the final digest of the stored bytes and returns the result.
 238:    * 
 239:    * @param buf
 240:    *          an array of bytes to store the result in.
 241:    * @param offset
 242:    *          an offset to start storing the result at.
 243:    * @param len
 244:    *          the length of the buffer.
 245:    * @return Returns the length of the buffer.
 246:    */
 247:   public int digest(byte[] buf, int offset, int len) throws DigestException
 248:   {
 249:     return engineDigest(buf, offset, len);
 250:   }
 251: 
 252:   /**
 253:    * Computes a final update using the input array of bytes, then computes a
 254:    * final digest and returns it. It calls {@link #update(byte[])} and then
 255:    * {@link #digest(byte[])}.
 256:    * 
 257:    * @param input
 258:    *          an array of bytes to perform final update with.
 259:    * @return a byte array representing the message digest.
 260:    */
 261:   public byte[] digest(byte[] input)
 262:   {
 263:     update(input);
 264:     return digest();
 265:   }
 266: 
 267:   /**
 268:    * Returns a string representation of this instance.
 269:    * 
 270:    * @return a string representation of this instance.
 271:    */
 272:   public String toString()
 273:   {
 274:     return (getClass()).getName() + " Message Digest <" + digestToString() + ">";
 275:   }
 276: 
 277:   /**
 278:    * Does a simple byte comparison of the two digests.
 279:    * 
 280:    * @param digesta
 281:    *          first digest to compare.
 282:    * @param digestb
 283:    *          second digest to compare.
 284:    * @return <code>true</code> if both are equal, <code>false</code>
 285:    *         otherwise.
 286:    */
 287:   public static boolean isEqual(byte[] digesta, byte[] digestb)
 288:   {
 289:     if (digesta.length != digestb.length)
 290:       return false;
 291: 
 292:     for (int i = digesta.length - 1; i >= 0; --i)
 293:       if (digesta[i] != digestb[i])
 294:         return false;
 295: 
 296:     return true;
 297:   }
 298: 
 299:   /** Resets this instance. */
 300:   public void reset()
 301:   {
 302:     engineReset();
 303:   }
 304: 
 305:   /**
 306:    * Returns the name of message digest algorithm.
 307:    * 
 308:    * @return the name of message digest algorithm.
 309:    */
 310:   public final String getAlgorithm()
 311:   {
 312:     return algorithm;
 313:   }
 314: 
 315:   /**
 316:    * Returns the length of the message digest. The default is zero which means
 317:    * that the concrete implementation does not implement this method.
 318:    * 
 319:    * @return length of the message digest.
 320:    * @since 1.2
 321:    */
 322:   public final int getDigestLength()
 323:   {
 324:     return engineGetDigestLength();
 325:   }
 326: 
 327:   /**
 328:    * Returns a clone of this instance if cloning is supported. If it does not
 329:    * then a {@link CloneNotSupportedException} is thrown. Cloning depends on
 330:    * whether the subclass {@link MessageDigestSpi} implements {@link Cloneable}
 331:    * which contains the actual implementation of the appropriate algorithm.
 332:    * 
 333:    * @return a clone of this instance.
 334:    * @throws CloneNotSupportedException
 335:    *           the implementation does not support cloning.
 336:    */
 337:   public Object clone() throws CloneNotSupportedException
 338:   {
 339:     return super.clone();
 340:   }
 341: 
 342:   private String digestToString()
 343:   {
 344:     byte[] digest = lastDigest;
 345: 
 346:     if (digest == null)
 347:       return "incomplete";
 348: 
 349:     StringBuffer buf = new StringBuffer();
 350:     int len = digest.length;
 351:     for (int i = 0; i < len; ++i)
 352:       {
 353:         byte b = digest[i];
 354:         byte high = (byte) ((b & 0xff) >>> 4);
 355:         byte low = (byte) (b & 0xf);
 356: 
 357:         buf.append(high > 9 ? ('a' - 10) + high : '0' + high);
 358:         buf.append(low > 9 ? ('a' - 10) + low : '0' + low);
 359:       }
 360: 
 361:     return buf.toString();
 362:   }
 363: }