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: import java.nio.ByteBuffer;
  42: 
  43: import java.lang.reflect.InvocationTargetException;
  44: 
  45: /**
  46:  * Message digests are secure one-way hash functions that take arbitrary-sized
  47:  * data and output a fixed-length hash value.
  48:  *
  49:  * @see MessageDigestSpi
  50:  * @since JDK 1.1
  51:  */
  52: public abstract class MessageDigest extends MessageDigestSpi
  53: {
  54:   /** The service name for message digests. */
  55:   private static final String MESSAGE_DIGEST = "MessageDigest";
  56: 
  57:   private String algorithm;
  58:   Provider provider;
  59:   private byte[] lastDigest;
  60: 
  61:   /**
  62:    * Constructs a new instance of <code>MessageDigest</code> representing the
  63:    * specified algorithm.
  64:    * 
  65:    * @param algorithm
  66:    *          the name of the digest algorithm to use.
  67:    */
  68:   protected MessageDigest(String algorithm)
  69:   {
  70:     this.algorithm = algorithm;
  71:     provider = null;
  72:   }
  73: 
  74:   /**
  75:    * Returns a new instance of <code>MessageDigest</code> representing the
  76:    * specified algorithm.
  77:    * 
  78:    * @param algorithm the name of the digest algorithm to use.
  79:    * @return a new instance representing the desired algorithm.
  80:    * @throws NoSuchAlgorithmException if the algorithm is not implemented by any
  81:    *           provider.
  82:    * @throws IllegalArgumentException if <code>algorithm</code> is
  83:    *           <code>null</code> or is an empty string.
  84:    */
  85:   public static MessageDigest getInstance(String algorithm)
  86:       throws NoSuchAlgorithmException
  87:   {
  88:     Provider[] p = Security.getProviders();
  89:     NoSuchAlgorithmException lastException = null;
  90:     for (int i = 0; i < p.length; i++)
  91:       try
  92:         {
  93:           return getInstance(algorithm, p[i]);
  94:         }
  95:       catch (NoSuchAlgorithmException x)
  96:         {
  97:           lastException = x;
  98:         }
  99:     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: }