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