/* See LICENSE for licensing and NOTICE for copyright. */
package org.cryptacular.spec;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.bouncycastle.crypto.modes.CCMBlockCipher;
import org.bouncycastle.crypto.modes.EAXBlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.modes.OCBBlockCipher;
/**
* Describes an AEAD block cipher in terms of a (algorithm, mode) tuple and provides a facility to create a new instance
* of the cipher via the {@link #newInstance()} method.
*
* @author Middleware Services
* @version $Revision: 2744 $
*/
public class AEADBlockCipherSpec implements Spec<AEADBlockCipher>
{
/** String specification format, <code>algorithm/mode</code>. */
public static final Pattern FORMAT = Pattern.compile("(?<alg>[A-Za-z0-9_-]+)/(?<mode>\\w+)");
/** Cipher algorithm algorithm. */
private final String algorithm;
/** Cipher mode, e.g. GCM, CCM. */
private final String mode;
/**
* Creates a new instance from a cipher algorithm and mode.
*
* @param algName Cipher algorithm name.
* @param cipherMode Cipher mode, e.g. GCM, CCM.
*/
public AEADBlockCipherSpec(final String algName, final String cipherMode)
{
this.algorithm = algName;
this.mode = cipherMode;
}
@Override
public String getAlgorithm()
{
return algorithm;
}
/**
* Gets the cipher mode.
*
* @return Cipher mode, e.g. CBC, OFB.
*/
public String getMode()
{
return mode;
}
/**
* Creates a new AEAD block cipher from the specification in this instance.
*
* @return New AEAD block cipher instance.
*/
@Override
public AEADBlockCipher newInstance()
{
final BlockCipher blockCipher = new BlockCipherSpec(algorithm).newInstance();
AEADBlockCipher aeadBlockCipher;
switch (mode) {
case "GCM":
aeadBlockCipher = new GCMBlockCipher(blockCipher);
break;
case "CCM":
aeadBlockCipher = new CCMBlockCipher(blockCipher);
break;
case "OCB":
aeadBlockCipher = new OCBBlockCipher(blockCipher, new BlockCipherSpec(algorithm).newInstance());
break;
case "EAX":
aeadBlockCipher = new EAXBlockCipher(blockCipher);
break;
default:
throw new IllegalStateException("Unsupported mode " + mode);
}
return aeadBlockCipher;
}
@Override
public String toString()
{
return algorithm + '/' + mode;
}
/**
* Parses a string representation of a AEAD block cipher specification into an instance of this class.
*
* @param specification AEAD block cipher specification of the form <code>algorithm/mode</code>.
*
* @return Buffered block cipher specification instance.
*/
public static AEADBlockCipherSpec parse(final String specification)
{
final Matcher m = FORMAT.matcher(specification);
if (!m.matches()) {
throw new IllegalArgumentException("Invalid specification " + specification);
}
return new AEADBlockCipherSpec(m.group("alg"), m.group("mode"));
}
}