open-keychain/libraries/spongycastle/jce/src/main/java/javax/crypto/Mac.java
2014-01-27 14:00:22 +01:00

444 lines
14 KiB
Java

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.
* <p>
* 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.
* <p>
* 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 <code>Mac</code> object.
* <p>
* This is the same name that was specified in one of the
* <code>getInstance</code> calls that created this <code>Mac</code> object.
*
* @return the algorithm name of this <code>Mac</code> object.
*/
public final String getAlgorithm()
{
return algorithm;
}
/**
* Generates an <code>Mac</code> object that implements the
* specified MAC algorithm.
* If the default provider package provides an implementation of the
* requested MAC algorithm, an instance of
* <code>Mac</code> 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 &amp; Reference
* for information about standard algorithm names.
* @return the new <code>Mac</code> 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 <code>Mac</code> 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 &amp; Reference
* for information about standard algorithm names.
* @param provider the name of the provider.
* @return the new <code>Mac</code> 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 <code>Mac</code> 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 &amp; Reference
* for information about standard algorithm names.
* @param provider the provider.
* @return the new <code>Mac</code> 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 <code>Mac</code> object.
*
* @return the provider of this <code>Mac</code> 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 <code>Mac</code> 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 <code>Mac</code> 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 <code>Mac</code> 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 <code>Mac</code> 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 <code>len</code> bytes in <code>input</code>,
* starting at <code>offset</code> inclusive.
*
* @param input the input buffer.
* @param offset the offset in <code>input</code> where the input starts.
* @param len the number of bytes to process.
* @exception IllegalStateException if this <code>Mac</code> 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.
* <p>
* A call to this method resets this <code>Mac</code> object to the
* state it was in when previously initialized via a call to <code>init(Key)</code> or
* <code>init(Key, AlgorithmParameterSpec)</code>.
* That is, the object is reset and available to generate another MAC from
* the same key, if desired, via new calls to <code>update</code> and
* <code>doFinal</code>.
* (In order to reuse this <code>Mac</code> object with a different key,
* it must be reinitialized via a call to <code>init(Key)</code> or
* <code>init(Key, AlgorithmParameterSpec)</code>.
*
* @return the MAC result.
* @exception IllegalStateException if this <code>Mac</code> 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.
*
* <p>A call to this method resets this <code>Mac</code> object to the
* state it was in when previously initialized via a call to
* <code>init(Key)</code> or
* <code>init(Key, AlgorithmParameterSpec)</code>.
* That is, the object is reset and available to generate another MAC from
* the same key, if desired, via new calls to <code>update</code> and
* <code>doFinal</code>.
* (In order to reuse this <code>Mac</code> object with a different key,
* it must be reinitialized via a call to <code>init(Key)</code> or
* <code>init(Key, AlgorithmParameterSpec)</code>.
* <p>
* The MAC result is stored in <code>output</code>, starting at
* <code>outOffset</code> inclusive.
*
* @param output the buffer where the MAC result is stored
* @param outOffset the offset in <code>output</code> where the MAC is stored
* @exception ShortBufferException if the given output buffer is too small to hold the result
* @exception IllegalStateException if this <code>Mac</code> 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.
* <p>
* A call to this method resets this <code>Mac</code> object to the
* state it was in when previously initialized via a call to <code>init(Key)</code> or
* <code>init(Key, AlgorithmParameterSpec)</code>. That is, the object is reset and
* available to generate another MAC from the same key, if desired, via new calls to
* <code>update</code> and <code>doFinal</code>.
* (In order to reuse this <code>Mac</code> object with a different key,
* it must be reinitialized via a call to <code>init(Key)</code> or
* <code>init(Key, AlgorithmParameterSpec)</code>.
*
* @return the MAC result.
* @exception IllegalStateException if this <code>Mac</code> 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 <code>Mac</code> object.
* <p>
* A call to this method resets this <code>Mac</code> object to the
* state it was in when previously initialized via a call to
* <code>init(Key)</code> or <code>init(Key, AlgorithmParameterSpec)</code>.
* That is, the object is reset and available to generate another MAC from
* the same key, if desired, via new calls to <code>update</code> and
* <code>doFinal</code>.
* (In order to reuse this <code>Mac</code> object with a different key,
* it must be reinitialized via a call to <code>init(Key)</code> or
* <code>init(Key, AlgorithmParameterSpec)</code>.
*/
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 <code>Cloneable</code>.
*/
public final Object clone()
throws CloneNotSupportedException
{
Mac result = new Mac((MacSpi)macSpi.clone(), provider, algorithm);
result.initialised = initialised;
return result;
}
}