package javax.crypto; import java.security.Provider; import java.security.Key; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.spec.AlgorithmParameterSpec; import java.security.InvalidAlgorithmParameterException; /** * This class provides the functionality of a "Message Authentication Code" * (MAC) algorithm. *

* A MAC provides a way to check the integrity of information transmitted over * or stored in an unreliable medium, based on a secret key. Typically, message * authentication codes are used between two parties that share a secret * key in order to validate information transmitted between these * parties. *

* A MAC mechanism that is based on cryptographic hash functions is * referred to as HMAC. HMAC can be used with any cryptographic hash function, * e.g., MD5 or SHA-1, in combination with a secret shared key. HMAC is * specified in RFC 2104. */ public class Mac implements Cloneable { MacSpi macSpi; Provider provider; String algorithm; private boolean initialised = false; /** * Creates a MAC object. * * @param macSpi the delegate * @param provider the provider * @param algorithm the algorithm */ protected Mac( MacSpi macSpi, Provider provider, String algorithm) { this.macSpi = macSpi; this.provider = provider; this.algorithm = algorithm; } /** * Returns the algorithm name of this Mac object. *

* This is the same name that was specified in one of the * getInstance calls that created this Mac object. * * @return the algorithm name of this Mac object. */ public final String getAlgorithm() { return algorithm; } /** * Generates an Mac object that implements the * specified MAC algorithm. * If the default provider package provides an implementation of the * requested MAC algorithm, an instance of * Mac containing that implementation is returned. * If the algorithm is not available in the default provider package, * other provider packages are searched. * * @param algorithm the standard name of the requested MAC algorithm. * See Appendix A in the Java Cryptography Extension API Specification & Reference * for information about standard algorithm names. * @return the new Mac object. * @exception NoSuchAlgorithmException if the specified algorithm is not * available in the default provider package or any of the other provider * packages that were searched. */ public static final Mac getInstance( String algorithm) throws NoSuchAlgorithmException { try { JCEUtil.Implementation imp = JCEUtil.getImplementation("Mac", algorithm, (String) null); if (imp == null) { throw new NoSuchAlgorithmException(algorithm + " not found"); } Mac mac = new Mac((MacSpi)imp.getEngine(), imp.getProvider(), algorithm); return mac; } catch (NoSuchProviderException e) { throw new NoSuchAlgorithmException(algorithm + " not found"); } } /** * Generates an Mac object for the specified MAC * algorithm from the specified provider. * * @param algorithm the standard name of the requested MAC algorithm. * See Appendix A in the Java Cryptography Extension API Specification & Reference * for information about standard algorithm names. * @param provider the name of the provider. * @return the new Mac object. * @exception NoSuchAlgorithmException if the specified algorithm is not available from the * specified provider. * @exception NoSuchProviderException if the specified provider has not been configured. */ public static final Mac getInstance( String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { if (provider == null) { throw new IllegalArgumentException("No provider specified to Mac.getInstance()"); } JCEUtil.Implementation imp = JCEUtil.getImplementation("Mac", algorithm, provider); if (imp == null) { throw new NoSuchAlgorithmException(algorithm + " not found"); } Mac mac = new Mac((MacSpi)imp.getEngine(), imp.getProvider(), algorithm); return mac; } /** * Generates an Mac object for the specified MAC * algorithm from the specified provider. * * @param algorithm the standard name of the requested MAC algorithm. * See Appendix A in the Java Cryptography Extension API Specification & Reference * for information about standard algorithm names. * @param provider the provider. * @return the new Mac object. * @exception NoSuchAlgorithmException if the specified algorithm is not available from the * specified provider. */ public static final Mac getInstance( String algorithm, Provider provider) throws NoSuchAlgorithmException { if (provider == null) { throw new IllegalArgumentException("No provider specified to Mac.getInstance()"); } JCEUtil.Implementation imp = JCEUtil.getImplementation("Mac", algorithm, provider); if (imp == null) { throw new NoSuchAlgorithmException(algorithm + " not found"); } Mac mac = new Mac((MacSpi)imp.getEngine(), imp.getProvider(), algorithm); return mac; } /** * Returns the provider of this Mac object. * * @return the provider of this Mac object. */ public final Provider getProvider() { return provider; } /** * Returns the length of the MAC in bytes. * * @return the MAC length in bytes. */ public final int getMacLength() { return macSpi.engineGetMacLength(); } /** * Initializes this Mac object with the given key. * * @param key the key. * @exception InvalidKeyException if the given key is inappropriate for initializing this MAC. */ public final void init( Key key) throws InvalidKeyException { try { macSpi.engineInit(key, null); initialised = true; } catch (InvalidAlgorithmParameterException e) { throw new IllegalArgumentException("underlying mac waon't work without an AlgorithmParameterSpec"); } } /** * Initializes this Mac object with the given key and * algorithm parameters. * * @param key the key. * @param params the algorithm parameters. * @exception InvalidKeyException if the given key is inappropriate for initializing this MAC. * @exception InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate * for this MAC. */ public final void init( Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { macSpi.engineInit(key, params); initialised = true; } /** * Processes the given byte. * * @param input the input byte to be processed. * @exception IllegalStateException if this Mac has not been initialized. */ public final void update( byte input) throws IllegalStateException { if (!initialised) { throw new IllegalStateException("MAC not initialised"); } macSpi.engineUpdate(input); } /** * Processes the given array of bytes. * * @param input the array of bytes to be processed. * @exception IllegalStateException if this Mac has not been initialized. */ public final void update( byte[] input) throws IllegalStateException { if (!initialised) { throw new IllegalStateException("MAC not initialised"); } if (input == null) { return; } macSpi.engineUpdate(input, 0, input.length); } /** * Processes the first len bytes in input, * starting at offset inclusive. * * @param input the input buffer. * @param offset the offset in input where the input starts. * @param len the number of bytes to process. * @exception IllegalStateException if this Mac has not been initialized. */ public final void update( byte[] input, int offset, int len) throws IllegalStateException { if (!initialised) { throw new IllegalStateException("MAC not initialised"); } if (input == null) { throw new IllegalArgumentException("Null input passed"); } if (len < 0 || offset < 0 || len > (input.length - offset)) { throw new IllegalArgumentException("Bad offset/len"); } if (input.length == 0) { return; } macSpi.engineUpdate(input, offset, len); } /** * Finishes the MAC operation. *

* A call to this method resets this Mac object to the * state it was in when previously initialized via a call to init(Key) or * init(Key, AlgorithmParameterSpec). * That is, the object is reset and available to generate another MAC from * the same key, if desired, via new calls to update and * doFinal. * (In order to reuse this Mac object with a different key, * it must be reinitialized via a call to init(Key) or * init(Key, AlgorithmParameterSpec). * * @return the MAC result. * @exception IllegalStateException if this Mac has not been initialized. */ public final byte[] doFinal() throws IllegalStateException { if (!initialised) { throw new IllegalStateException("MAC not initialised"); } return macSpi.engineDoFinal(); } /** * Finishes the MAC operation. * *

A call to this method resets this Mac object to the * state it was in when previously initialized via a call to * init(Key) or * init(Key, AlgorithmParameterSpec). * That is, the object is reset and available to generate another MAC from * the same key, if desired, via new calls to update and * doFinal. * (In order to reuse this Mac object with a different key, * it must be reinitialized via a call to init(Key) or * init(Key, AlgorithmParameterSpec). *

* The MAC result is stored in output, starting at * outOffset inclusive. * * @param output the buffer where the MAC result is stored * @param outOffset the offset in output where the MAC is stored * @exception ShortBufferException if the given output buffer is too small to hold the result * @exception IllegalStateException if this Mac has not been initialized. */ public final void doFinal( byte[] output, int outOffset) throws ShortBufferException, IllegalStateException { if (!initialised) { throw new IllegalStateException("MAC not initialised"); } if ((output.length - outOffset) < macSpi.engineGetMacLength()) { throw new ShortBufferException("buffer to short for MAC output"); } byte[] mac = macSpi.engineDoFinal(); System.arraycopy(mac, 0, output, outOffset, mac.length); } /** * Processes the given array of bytes and finishes the MAC operation. *

* A call to this method resets this Mac object to the * state it was in when previously initialized via a call to init(Key) or * init(Key, AlgorithmParameterSpec). That is, the object is reset and * available to generate another MAC from the same key, if desired, via new calls to * update and doFinal. * (In order to reuse this Mac object with a different key, * it must be reinitialized via a call to init(Key) or * init(Key, AlgorithmParameterSpec). * * @return the MAC result. * @exception IllegalStateException if this Mac has not been initialized. */ public final byte[] doFinal( byte[] input) throws IllegalStateException { if (!initialised) { throw new IllegalStateException("MAC not initialised"); } macSpi.engineUpdate(input, 0, input.length); return macSpi.engineDoFinal(); } /** * Resets this Mac object. *

* A call to this method resets this Mac object to the * state it was in when previously initialized via a call to * init(Key) or init(Key, AlgorithmParameterSpec). * That is, the object is reset and available to generate another MAC from * the same key, if desired, via new calls to update and * doFinal. * (In order to reuse this Mac object with a different key, * it must be reinitialized via a call to init(Key) or * init(Key, AlgorithmParameterSpec). */ public final void reset() { macSpi.engineReset(); } /** * Returns a clone if the provider implementation is cloneable. * * @return a clone if the provider implementation is cloneable. * @exception CloneNotSupportedException if this is called on a delegate that does * not support Cloneable. */ public final Object clone() throws CloneNotSupportedException { Mac result = new Mac((MacSpi)macSpi.clone(), provider, algorithm); result.initialised = initialised; return result; } }