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