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;
}
}