GNU Classpath (0.95) | |
Frames | No Frames |
1: /* Mac.java -- The message authentication code interface. 2: Copyright (C) 2004 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: 39: package javax.crypto; 40: 41: import gnu.java.security.Engine; 42: 43: import java.lang.reflect.InvocationTargetException; 44: import java.nio.ByteBuffer; 45: import java.security.InvalidAlgorithmParameterException; 46: import java.security.InvalidKeyException; 47: import java.security.Key; 48: import java.security.NoSuchAlgorithmException; 49: import java.security.NoSuchProviderException; 50: import java.security.Provider; 51: import java.security.Security; 52: import java.security.spec.AlgorithmParameterSpec; 53: 54: /** 55: * This class implements a "message authentication code" (MAC), a method 56: * to ensure the integrity of data transmitted between two parties who 57: * share a common secret key. 58: * 59: * <p>The best way to describe a MAC is as a <i>keyed one-way hash 60: * function</i>, which looks like: 61: * 62: * <blockquote><p><code>D = MAC(K, M)</code></blockquote> 63: * 64: * <p>where <code>K</code> is the key, <code>M</code> is the message, 65: * and <code>D</code> is the resulting digest. One party will usually 66: * send the concatenation <code>M || D</code> to the other party, who 67: * will then verify <code>D</code> by computing <code>D'</code> in a 68: * similar fashion. If <code>D == D'</code>, then the message is assumed 69: * to be authentic. 70: * 71: * @author Casey Marshall (csm@gnu.org) 72: */ 73: public class Mac implements Cloneable 74: { 75: 76: // Fields. 77: // ------------------------------------------------------------------------ 78: 79: private static final String SERVICE = "Mac"; 80: 81: /** The underlying MAC implementation. */ 82: private MacSpi macSpi; 83: 84: /** The provider we got our implementation from. */ 85: private Provider provider; 86: 87: /** The name of the algorithm. */ 88: private String algorithm; 89: 90: /** Whether or not we've been initialized. */ 91: private boolean virgin; 92: 93: // Constructor. 94: // ------------------------------------------------------------------------ 95: 96: /** 97: * Creates a new Mac instance. 98: * 99: * @param macSpi The underlying MAC implementation. 100: * @param provider The provider of this implementation. 101: * @param algorithm The name of this MAC algorithm. 102: */ 103: protected Mac(MacSpi macSpi, Provider provider, String algorithm) 104: { 105: this.macSpi = macSpi; 106: this.provider = provider; 107: this.algorithm = algorithm; 108: virgin = true; 109: } 110: 111: /** 112: * Create an instance of the named algorithm from the first provider with an 113: * appropriate implementation. 114: * 115: * @param algorithm The name of the algorithm. 116: * @return An appropriate Mac instance, if the specified algorithm is 117: * implemented by a provider. 118: * @throws NoSuchAlgorithmException If no implementation of the named 119: * algorithm is installed. 120: * @throws IllegalArgumentException if <code>algorithm</code> is 121: * <code>null</code> or is an empty string. 122: */ 123: public static final Mac getInstance(String algorithm) 124: throws NoSuchAlgorithmException 125: { 126: Provider[] p = Security.getProviders(); 127: NoSuchAlgorithmException lastException = null; 128: for (int i = 0; i < p.length; i++) 129: try 130: { 131: return getInstance(algorithm, p[i]); 132: } 133: catch (NoSuchAlgorithmException x) 134: { 135: lastException = x; 136: } 137: if (lastException != null) 138: throw lastException; 139: throw new NoSuchAlgorithmException(algorithm); 140: } 141: 142: /** 143: * Create an instance of the named algorithm from the named provider. 144: * 145: * @param algorithm The name of the algorithm. 146: * @param provider The name of the provider. 147: * @return An appropriate Mac instance, if the specified algorithm is 148: * implemented by the named provider. 149: * @throws NoSuchAlgorithmException If the named provider has no 150: * implementation of the algorithm. 151: * @throws NoSuchProviderException If the named provider does not exist. 152: * @throws IllegalArgumentException if either <code>algorithm</code> or 153: * <code>provider</code> is <code>null</code>, or if 154: * <code>algorithm</code> is an empty string. 155: */ 156: public static final Mac getInstance(String algorithm, String provider) 157: throws NoSuchAlgorithmException, NoSuchProviderException 158: { 159: if (provider == null) 160: throw new IllegalArgumentException("provider MUST NOT be null"); 161: Provider p = Security.getProvider(provider); 162: if (p == null) 163: throw new NoSuchProviderException(provider); 164: return getInstance(algorithm, p); 165: } 166: 167: /** 168: * Create an instance of the named algorithm from a provider. 169: * 170: * @param algorithm The name of the algorithm. 171: * @param provider The provider. 172: * @return An appropriate Mac instance, if the specified algorithm is 173: * implemented by the provider. 174: * @throws NoSuchAlgorithmException If the provider has no implementation of 175: * the algorithm. 176: * @throws IllegalArgumentException if either <code>algorithm</code> or 177: * <code>provider</code> is <code>null</code>, or if 178: * <code>algorithm</code> is an empty string. 179: */ 180: public static final Mac getInstance(String algorithm, Provider provider) 181: throws NoSuchAlgorithmException 182: { 183: StringBuilder sb = new StringBuilder("Mac algorithm [") 184: .append(algorithm).append("] from provider[") 185: .append(provider).append("] could not be created"); 186: Throwable cause; 187: try 188: { 189: Object spi = Engine.getInstance(SERVICE, algorithm, provider); 190: return new Mac((MacSpi) spi, provider, algorithm); 191: } 192: catch (InvocationTargetException x) 193: { 194: cause = x.getCause(); 195: if (cause instanceof NoSuchAlgorithmException) 196: throw (NoSuchAlgorithmException) cause; 197: if (cause == null) 198: cause = x; 199: } 200: catch (ClassCastException x) 201: { 202: cause = x; 203: } 204: NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString()); 205: x.initCause(cause); 206: throw x; 207: } 208: 209: /** 210: * Finishes the computation of a MAC and returns the digest. 211: * 212: * <p>After this method succeeds, it may be used again as just after a 213: * call to <code>init</code>, and can compute another MAC using the 214: * same key and parameters. 215: * 216: * @return The message authentication code. 217: * @throws java.lang.IllegalStateException If this instnace has not 218: * been initialized. 219: */ 220: public final byte[] doFinal() throws IllegalStateException 221: { 222: if (virgin) 223: { 224: throw new IllegalStateException("not initialized"); 225: } 226: byte[] digest = macSpi.engineDoFinal(); 227: reset(); 228: return digest; 229: } 230: 231: /** 232: * Finishes the computation of a MAC with a final byte array (or 233: * computes a MAC over those bytes only) and returns the digest. 234: * 235: * <p>After this method succeeds, it may be used again as just after a 236: * call to <code>init</code>, and can compute another MAC using the 237: * same key and parameters. 238: * 239: * @param input The bytes to add. 240: * @return The message authentication code. 241: * @throws java.lang.IllegalStateException If this instnace has not 242: * been initialized. 243: */ 244: public final byte[] doFinal(byte[] input) throws IllegalStateException 245: { 246: update(input); 247: byte[] digest = macSpi.engineDoFinal(); 248: reset(); 249: return digest; 250: } 251: 252: /** 253: * Finishes the computation of a MAC and places the result into the 254: * given array. 255: * 256: * <p>After this method succeeds, it may be used again as just after a 257: * call to <code>init</code>, and can compute another MAC using the 258: * same key and parameters. 259: * 260: * @param output The destination for the result. 261: * @param outOffset The index in the output array to start. 262: * @return The message authentication code. 263: * @throws java.lang.IllegalStateException If this instnace has not 264: * been initialized. 265: * @throws javax.crypto.ShortBufferException If <code>output</code> is 266: * not large enough to hold the result. 267: */ 268: public final void doFinal(byte[] output, int outOffset) 269: throws IllegalStateException, ShortBufferException 270: { 271: if (virgin) 272: { 273: throw new IllegalStateException("not initialized"); 274: } 275: if (output.length - outOffset < getMacLength()) 276: { 277: throw new ShortBufferException(); 278: } 279: byte[] mac = macSpi.engineDoFinal(); 280: System.arraycopy(mac, 0, output, outOffset, getMacLength()); 281: reset(); 282: } 283: 284: /** 285: * Returns the name of this MAC algorithm. 286: * 287: * @return The MAC name. 288: */ 289: public final String getAlgorithm() 290: { 291: return algorithm; 292: } 293: 294: /** 295: * Get the size of the MAC. This is the size of the array returned by 296: * {@link #doFinal()} and {@link #doFinal(byte[])}, and the minimum 297: * number of bytes that must be available in the byte array passed to 298: * {@link #doFinal(byte[],int)}. 299: * 300: * @return The MAC length. 301: */ 302: public final int getMacLength() 303: { 304: return macSpi.engineGetMacLength(); 305: } 306: 307: /** 308: * Get the provider of the underlying implementation. 309: * 310: * @return The provider. 311: */ 312: public final Provider getProvider() 313: { 314: return provider; 315: } 316: 317: /** 318: * Initialize this MAC with a key and no parameters. 319: * 320: * @param key The key to initialize this instance with. 321: * @throws java.security.InvalidKeyException If the key is 322: * unacceptable. 323: */ 324: public final void init(Key key) throws InvalidKeyException 325: { 326: try 327: { 328: init(key, null); 329: } 330: catch (InvalidAlgorithmParameterException iape) 331: { 332: throw new IllegalArgumentException(algorithm + " needs parameters"); 333: } 334: } 335: 336: /** 337: * Initialize this MAC with a key and parameters. 338: * 339: * @param key The key to initialize this instance with. 340: * @param params The algorithm-specific parameters. 341: * @throws java.security.InvalidAlgorithmParameterException If the 342: * algorithm parameters are unacceptable. 343: * @throws java.security.InvalidKeyException If the key is 344: * unacceptable. 345: */ 346: public final void init(Key key, AlgorithmParameterSpec params) 347: throws InvalidAlgorithmParameterException, InvalidKeyException 348: { 349: macSpi.engineInit(key, params); 350: virgin = false; // w00t! 351: } 352: 353: /** 354: * Reset this instance. A call to this method returns this instance 355: * back to the state it was in just after it was initialized. 356: */ 357: public final void reset() 358: { 359: macSpi.engineReset(); 360: } 361: 362: /** 363: * Update the computation with a single byte. 364: * 365: * @param input The next byte. 366: * @throws java.lang.IllegalStateException If this instance has not 367: * been initialized. 368: */ 369: public final void update(byte input) throws IllegalStateException 370: { 371: if (virgin) 372: { 373: throw new IllegalStateException("not initialized"); 374: } 375: macSpi.engineUpdate(input); 376: } 377: 378: /** 379: * Update the computation with a byte array. 380: * 381: * @param input The next bytes. 382: * @throws java.lang.IllegalStateException If this instance has not 383: * been initialized. 384: */ 385: public final void update(byte[] input) throws IllegalStateException 386: { 387: update(input, 0, input.length); 388: } 389: 390: /** 391: * Update the computation with a portion of a byte array. 392: * 393: * @param input The next bytes. 394: * @param offset The index in <code>input</code> to start. 395: * @param length The number of bytes to update. 396: * @throws java.lang.IllegalStateException If this instance has not 397: * been initialized. 398: */ 399: public final void update(byte[] input, int offset, int length) 400: throws IllegalStateException 401: { 402: if (virgin) 403: { 404: throw new IllegalStateException("not initialized"); 405: } 406: macSpi.engineUpdate(input, offset, length); 407: } 408: 409: /** 410: * Update this MAC with the remaining bytes in the given buffer 411: * @param buffer The input buffer. 412: * @since 1.5 413: */ 414: public final void update (final ByteBuffer buffer) 415: { 416: if (virgin) 417: throw new IllegalStateException ("not initialized"); 418: macSpi.engineUpdate(buffer); 419: } 420: 421: /** 422: * Clone this instance, if the underlying implementation supports it. 423: * 424: * @return A clone of this instance. 425: * @throws java.lang.CloneNotSupportedException If the underlying 426: * implementation is not cloneable. 427: */ 428: public final Object clone() throws CloneNotSupportedException 429: { 430: Mac result = new Mac((MacSpi) macSpi.clone(), provider, algorithm); 431: result.virgin = virgin; 432: return result; 433: } 434: }
GNU Classpath (0.95) |