Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2013-05-20 05:24:54 +0400
committerDavid Hook <dgh@cryptoworkshop.com>2013-05-20 05:24:54 +0400
commitb1bbd3b14d495baee344b263020b338c07419980 (patch)
tree1c4cb243ee2148d2df6dd37f6f11b5e6e4851983
parentecc849da20a41aee8b4c6451015eca26dc3f1fb8 (diff)
BJA-451 first cut of GMAC.
-rw-r--r--src/main/java/org/bouncycastle/crypto/macs/GMac.java108
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java17
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java17
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java16
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java21
-rw-r--r--src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java16
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/GMacTest.java170
-rw-r--r--src/test/java/org/bouncycastle/crypto/test/RegressionTest.java1
-rw-r--r--src/test/java/org/bouncycastle/jce/provider/test/GMacTest.java145
-rw-r--r--src/test/java/org/bouncycastle/jce/provider/test/JceTestUtil.java49
-rw-r--r--src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java1
15 files changed, 608 insertions, 17 deletions
diff --git a/src/main/java/org/bouncycastle/crypto/macs/GMac.java b/src/main/java/org/bouncycastle/crypto/macs/GMac.java
new file mode 100644
index 00000000..91bfe13d
--- /dev/null
+++ b/src/main/java/org/bouncycastle/crypto/macs/GMac.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.crypto.macs;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
+import org.bouncycastle.crypto.params.AEADParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * The GMAC specialisation of Galois/Counter mode (GCM) detailed in NIST Special Publication
+ * 800-38D.
+ * <p>
+ * GMac is an invocation of the GCM mode where no data is encrypted (i.e. all input data to the Mac
+ * is processed as additional authenticated data with the underlying GCM block cipher).
+ */
+public class GMac implements Mac
+{
+ private final GCMBlockCipher cipher;
+ private final int macSizeBits;
+
+ /**
+ * Creates a GMAC based on the operation of a block cipher in GCM mode.
+ * <p/>
+ * This will produce an authentication code the length of the block size of the cipher.
+ *
+ * @param cipher
+ * the cipher to be used in GCM mode to generate the MAC.
+ */
+ public GMac(final GCMBlockCipher cipher)
+ {
+ this(cipher, 128);
+ }
+
+ /**
+ * Creates a GMAC based on the operation of a 128 bit block cipher in GCM mode.
+ *
+ * @param macSizeBits
+ * the mac size to generate, in bits. Must be a multiple of 8 and >= 96 and <= 128.
+ * @param cipher
+ * the cipher to be used in GCM mode to generate the MAC.
+ */
+ public GMac(final GCMBlockCipher cipher, final int macSizeBits)
+ {
+ this.cipher = cipher;
+ this.macSizeBits = macSizeBits;
+ }
+
+ /**
+ * Initialises the GMAC - requires a {@link ParametersWithIV} providing a {@link KeyParameter}
+ * and a nonce.
+ */
+ public void init(final CipherParameters params) throws IllegalArgumentException
+ {
+ if (params instanceof ParametersWithIV)
+ {
+ final ParametersWithIV param = (ParametersWithIV)params;
+
+ final byte[] iv = param.getIV();
+ final KeyParameter keyParam = (KeyParameter)param.getParameters();
+
+ // GCM is always operated in encrypt mode to calculate MAC
+ cipher.init(true, new AEADParameters(keyParam, macSizeBits, iv));
+ } else
+ {
+ throw new IllegalArgumentException("GMAC requires ParametersWithIV");
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName() + "-GMAC";
+ }
+
+ public int getMacSize()
+ {
+ return macSizeBits / 8;
+ }
+
+ public void update(byte in) throws IllegalStateException
+ {
+ cipher.processAADByte(in);
+ }
+
+ public void update(byte[] in, int inOff, int len) throws DataLengthException, IllegalStateException
+ {
+ cipher.processAADBytes(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws DataLengthException, IllegalStateException
+ {
+ try
+ {
+ return cipher.doFinal(out, outOff);
+ } catch (InvalidCipherTextException e)
+ {
+ // Impossible in encrypt mode
+ throw new IllegalStateException(e);
+ }
+ }
+
+ public void reset()
+ {
+ cipher.reset();
+ }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
index 07f47ead..7a6f7b04 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -16,8 +16,10 @@ import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.engines.AESWrapEngine;
import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
import org.bouncycastle.crypto.macs.CMac;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.modes.OFBBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
@@ -28,7 +30,6 @@ import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class AES
@@ -88,6 +89,15 @@ public final class AES
}
}
+ public static class AESGMAC
+ extends BaseMac
+ {
+ public AESGMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new AESFastEngine())));
+ }
+ }
+
static public class Wrap
extends BaseWrapCipher
{
@@ -159,7 +169,6 @@ public final class AES
super(256);
}
}
-
/**
* PBEWithSHA1And128BitAES-BC
@@ -317,7 +326,7 @@ public final class AES
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = AES.class.getName();
@@ -473,6 +482,8 @@ public final class AES
provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
+
+ addGMacAlgorithm(provider, "AES", PREFIX + "$AESGMAC", PREFIX + "$KeyGen128");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java
index 9ac54e73..68605f45 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java
@@ -2,10 +2,12 @@ package org.bouncycastle.jcajce.provider.symmetric;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.CAST6Engine;
+import org.bouncycastle.crypto.macs.GMac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
public final class CAST6
{
@@ -31,8 +33,17 @@ public final class CAST6
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new CAST6Engine())));
+ }
+ }
+
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = CAST6.class.getName();
@@ -44,6 +55,8 @@ public final class CAST6
{
provider.addAlgorithm("Cipher.CAST6", PREFIX + "$ECB");
provider.addAlgorithm("KeyGenerator.CAST6", PREFIX + "$KeyGen");
+
+ addGMacAlgorithm(provider, "CAST6", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java
index 5c98e961..38b5ca7b 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java
@@ -13,15 +13,17 @@ import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.CamelliaEngine;
import org.bouncycastle.crypto.engines.CamelliaWrapEngine;
import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class Camellia
@@ -72,6 +74,15 @@ public final class Camellia
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new CamelliaEngine())));
+ }
+ }
+
public static class KeyGen
extends BaseKeyGenerator
{
@@ -161,7 +172,7 @@ public final class Camellia
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = Camellia.class.getName();
@@ -201,6 +212,7 @@ public final class Camellia
provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia192_cbc, PREFIX + "$KeyGen192");
provider.addAlgorithm("KeyGenerator." + NTTObjectIdentifiers.id_camellia256_cbc, PREFIX + "$KeyGen256");
+ addGMacAlgorithm(provider, "CAMELLIA", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java
index d488ac2c..2d089cc7 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java
@@ -9,12 +9,14 @@ import javax.crypto.spec.IvParameterSpec;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.NoekeonEngine;
+import org.bouncycastle.crypto.macs.GMac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class Noekeon
@@ -41,6 +43,15 @@ public final class Noekeon
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new NoekeonEngine())));
+ }
+ }
+
public static class AlgParamGen
extends BaseAlgorithmParameterGenerator
{
@@ -89,7 +100,7 @@ public final class Noekeon
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = Noekeon.class.getName();
@@ -108,6 +119,7 @@ public final class Noekeon
provider.addAlgorithm("KeyGenerator.NOEKEON", PREFIX + "$KeyGen");
+ addGMacAlgorithm(provider, "NOEKEON", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java
index 0861f13b..a29e717c 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java
@@ -11,16 +11,18 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.RC6Engine;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.modes.OFBBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class RC6
@@ -71,6 +73,15 @@ public final class RC6
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new RC6Engine())));
+ }
+ }
+
public static class KeyGen
extends BaseKeyGenerator
{
@@ -128,7 +139,7 @@ public final class RC6
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = RC6.class.getName();
@@ -143,6 +154,7 @@ public final class RC6
provider.addAlgorithm("KeyGenerator.RC6", PREFIX + "$KeyGen");
provider.addAlgorithm("AlgorithmParameters.RC6", PREFIX + "$AlgParams");
+ addGMacAlgorithm(provider, "RC6", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java
index e4cffe30..2ad41bff 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java
@@ -12,15 +12,17 @@ import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.SEEDEngine;
import org.bouncycastle.crypto.engines.SEEDWrapEngine;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public final class SEED
@@ -71,6 +73,15 @@ public final class SEED
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new SEEDEngine())));
+ }
+ }
+
public static class AlgParamGen
extends BaseAlgorithmParameterGenerator
{
@@ -119,7 +130,7 @@ public final class SEED
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = SEED.class.getName();
@@ -146,6 +157,7 @@ public final class SEED
provider.addAlgorithm("KeyGenerator." + KISAObjectIdentifiers.id_seedCBC, PREFIX + "$KeyGen");
provider.addAlgorithm("KeyGenerator." + KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, PREFIX + "$KeyGen");
+ addGMacAlgorithm(provider, "SEED", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java
index 02959ec4..578de32d 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java
@@ -3,12 +3,14 @@ package org.bouncycastle.jcajce.provider.symmetric;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.SerpentEngine;
+import org.bouncycastle.crypto.macs.GMac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
public final class Serpent
{
@@ -40,6 +42,15 @@ public final class Serpent
}
}
+ public static class SerpentGMAC
+ extends BaseMac
+ {
+ public SerpentGMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new SerpentEngine())));
+ }
+ }
+
public static class AlgParams
extends IvAlgorithmParameters
{
@@ -50,7 +61,7 @@ public final class Serpent
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = Serpent.class.getName();
@@ -65,6 +76,7 @@ public final class Serpent
provider.addAlgorithm("KeyGenerator.Serpent", PREFIX + "$KeyGen");
provider.addAlgorithm("AlgorithmParameters.Serpent", PREFIX + "$AlgParams");
+ addGMacAlgorithm(provider, "SERPENT", PREFIX + "$SerpentGMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
new file mode 100644
index 00000000..49656c27
--- /dev/null
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+abstract class SymmetricAlgorithmProvider
+ extends AlgorithmProvider
+{
+ protected void addGMacAlgorithm(
+ ConfigurableProvider provider,
+ String algorithm,
+ String algorithmClassName,
+ String keyGeneratorClassName)
+ {
+ provider.addAlgorithm("Mac." + algorithm + "-GMAC", algorithmClassName);
+ provider.addAlgorithm("Alg.Alias.Mac." + algorithm + "GMAC", algorithm + "-GMAC");
+
+ provider.addAlgorithm("KeyGenerator." + algorithm + "-GMAC", keyGeneratorClassName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "GMAC", algorithm + "-GMAC");
+ }
+}
diff --git a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
index 604e7663..67b9f663 100644
--- a/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
+++ b/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
@@ -3,14 +3,16 @@ package org.bouncycastle.jcajce.provider.symmetric;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.TwofishEngine;
+import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
-import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
public final class Twofish
{
@@ -42,6 +44,14 @@ public final class Twofish
}
}
+ public static class GMAC
+ extends BaseMac
+ {
+ public GMAC()
+ {
+ super(new GMac(new GCMBlockCipher(new TwofishEngine())));
+ }
+ }
/**
* PBEWithSHAAndTwofish-CBC
@@ -77,7 +87,7 @@ public final class Twofish
}
public static class Mappings
- extends AlgorithmProvider
+ extends SymmetricAlgorithmProvider
{
private static final String PREFIX = Twofish.class.getName();
@@ -95,6 +105,8 @@ public final class Twofish
provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH-CBC", "PKCS12PBE");
provider.addAlgorithm("Cipher.PBEWITHSHAANDTWOFISH-CBC", PREFIX + "$PBEWithSHA");
provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", PREFIX + "$PBEWithSHAKeyFactory");
+
+ addGMacAlgorithm(provider, "Twofish", PREFIX + "$GMAC", PREFIX + "$KeyGen");
}
}
}
diff --git a/src/test/java/org/bouncycastle/crypto/test/GMacTest.java b/src/test/java/org/bouncycastle/crypto/test/GMacTest.java
new file mode 100644
index 00000000..d8196f96
--- /dev/null
+++ b/src/test/java/org/bouncycastle/crypto/test/GMacTest.java
@@ -0,0 +1,170 @@
+package org.bouncycastle.crypto.test;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.macs.GMac;
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTest;
+
+/**
+ * Test vectors for AES-GMAC, extracted from <a
+ * href="http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip">NIST CAVP GCM test
+ * vectors</a>.
+ *
+ */
+public class GMacTest extends SimpleTest
+{
+ private static class TestCase
+ {
+ private byte[] key;
+ private byte[] iv;
+ private byte[] ad;
+ private byte[] tag;
+ private String name;
+
+ private TestCase(final String name, final String key, final String iv, final String ad, final String tag)
+ {
+ this.name = name;
+ this.key = Hex.decode(key);
+ this.iv = Hex.decode(iv);
+ this.ad = Hex.decode(ad);
+ this.tag = Hex.decode(tag);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public byte[] getKey()
+ {
+ return key;
+ }
+
+ public byte[] getIv()
+ {
+ return iv;
+ }
+
+ public byte[] getAd()
+ {
+ return ad;
+ }
+
+ public byte[] getTag()
+ {
+ return tag;
+ }
+ }
+
+ private static TestCase[] TEST_VECTORS = new TestCase[] {
+ // Count = 0, from each of the PTlen = 0 test vector sequences
+ new TestCase("128/96/0/128", "11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "",
+ "250327c674aaf477aef2675748cf6971"),
+ new TestCase("128/96/0/120", "272f16edb81a7abbea887357a58c1917", "794ec588176c703d3d2a7a07", "",
+ "b6e6f197168f5049aeda32dafbdaeb"),
+ new TestCase("128/96/0/112", "81b6844aab6a568c4556a2eb7eae752f", "ce600f59618315a6829bef4d", "",
+ "89b43e9dbc1b4f597dbbc7655bb5"),
+ new TestCase("128/96/0/104", "cde2f9a9b1a004165ef9dc981f18651b", "29512c29566c7322e1e33e8e", "",
+ "2e58ce7dabd107c82759c66a75"),
+ new TestCase("128/96/0/96", "b01e45cc3088aaba9fa43d81d481823f", "5a2c4a66468713456a4bd5e1", "",
+ "014280f944f53c681164b2ff"),
+
+ new TestCase("128/96/128/128", "77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3",
+ "7a43ec1d9c0a5a78a0b16533a6213cab", "209fcc8d3675ed938e9c7166709dd946"),
+ new TestCase("128/96/128/96", "bea48ae4980d27f357611014d4486625", "32bddb5c3aa998a08556454c",
+ "8a50b0b8c7654bced884f7f3afda2ead", "8e0f6d8bf05ffebe6f500eb1"),
+
+ new TestCase("128/96/384/128", "99e3e8793e686e571d8285c564f75e2b", "c2dd0ab868da6aa8ad9c0d23",
+ "b668e42d4e444ca8b23cfdd95a9fedd5178aa521144890b093733cf5cf22526c5917ee476541809ac6867a8c399309fc",
+ "3f4fba100eaf1f34b0baadaae9995d85"),
+ new TestCase("128/96/384/96", "c77acd1b0918e87053cb3e51651e7013", "39ff857a81745d10f718ac00",
+ "407992f82ea23b56875d9a3cb843ceb83fd27cb954f7c5534d58539fe96fb534502a1b38ea4fac134db0a42de4be1137",
+ "2a5dc173285375dc82835876"),
+
+ new TestCase(
+ "128/1024/0/128",
+ "d0f1f4defa1e8c08b4b26d576392027c",
+ "42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac",
+ "", "7ab49b57ddf5f62c427950111c5c4f0d"),
+ new TestCase(
+ "128/1024/384/96",
+ "3cce72d37933394a8cac8a82deada8f0",
+ "aa2f0d676d705d9733c434e481972d4888129cf7ea55c66511b9c0d25a92a174b1e28aa072f27d4de82302828955aadcb817c4907361869bd657b45ff4a6f323871987fcf9413b0702d46667380cd493ed24331a28b9ce5bbfa82d3a6e7679fcce81254ba64abcad14fd18b22c560a9d2c1cd1d3c42dac44c683edf92aced894",
+ "5686b458e9c176f4de8428d9ebd8e12f569d1c7595cf49a4b0654ab194409f86c0dd3fdb8eb18033bb4338c70f0b97d1",
+ "a3a9444b21f330c3df64c8b6"), };
+
+ public void performTest()
+ {
+ for (int i = 0; i < TEST_VECTORS.length; i++)
+ {
+ TestCase testCase = TEST_VECTORS[i];
+
+ Mac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), testCase.getTag().length * 8);
+ CipherParameters key = new KeyParameter(testCase.getKey());
+ mac.init(new ParametersWithIV(key, testCase.getIv()));
+
+ testSingleByte(mac, testCase);
+ testMultibyte(mac, testCase);
+ }
+
+ // Invalid mac size
+ testInvalidMacSize(97);
+ testInvalidMacSize(136);
+ testInvalidMacSize(88);
+ testInvalidMacSize(64);
+ }
+
+ private void testInvalidMacSize(int size)
+ {
+ try
+ {
+ GMac mac = new GMac(new GCMBlockCipher(new AESFastEngine()), size);
+ mac.init(new ParametersWithIV(null, new byte[16]));
+ fail("Expected failure for illegal mac size " + size);
+ } catch (IllegalArgumentException e)
+ {
+ }
+ }
+
+ private void testMultibyte(Mac mac, TestCase testCase)
+ {
+ mac.update(testCase.getAd(), 0, testCase.getAd().length);
+ checkMac(mac, testCase);
+ }
+
+ private void testSingleByte(Mac mac, TestCase testCase)
+ {
+ final byte[] ad = testCase.getAd();
+ for (int i = 0; i < ad.length; i++)
+ {
+ mac.update(ad[i]);
+ }
+ checkMac(mac, testCase);
+ }
+
+ private void checkMac(Mac mac, TestCase testCase)
+ {
+ final byte[] generatedMac = new byte[mac.getMacSize()];
+ mac.doFinal(generatedMac, 0);
+ if (!areEqual(testCase.getTag(), generatedMac))
+ {
+ fail("Failed " + testCase.getName() + " - expected " + new String(Hex.encode(testCase.getTag())) + " got "
+ + new String(Hex.encode(generatedMac)));
+ }
+ }
+
+ public String getName()
+ {
+ return "GMac";
+ }
+
+ public static void main(String[] args)
+ {
+ runTest(new GMacTest());
+ }
+}
diff --git a/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java b/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
index 3c3fa8bb..906eb910 100644
--- a/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
+++ b/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java
@@ -96,6 +96,7 @@ public class RegressionTest
new CMacTest(),
new EAXTest(),
new GCMTest(),
+ new GMacTest(),
new HCFamilyTest(),
new HCFamilyVecTest(),
new ISAACTest(),
diff --git a/src/test/java/org/bouncycastle/jce/provider/test/GMacTest.java b/src/test/java/org/bouncycastle/jce/provider/test/GMacTest.java
new file mode 100644
index 00000000..72a4888a
--- /dev/null
+++ b/src/test/java/org/bouncycastle/jce/provider/test/GMacTest.java
@@ -0,0 +1,145 @@
+package org.bouncycastle.jce.provider.test;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestFailedException;
+
+public class GMacTest
+ extends SimpleTest
+{
+ public String getName()
+ {
+ return "GMac";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ checkRegistrations();
+ }
+
+ private void checkRegistrations()
+ throws Exception
+ {
+ List<String> missingMacs = new ArrayList<String>();
+ List<String> missingKeyGens = new ArrayList<String>();
+
+ String[] ciphers = new String[] { "AES", "NOEKEON", "Twofish", "CAST6", "SEED", "Serpent", "RC6", "CAMELLIA" };
+ String[] macs = new String[]
+ {
+ "a52308801b32d4770c701ace9b826f12",
+ "cf11dacaf6024a78dba76b256e23caab",
+ "13db7c428e5a7128149b5ec782d07fac",
+ "d13a33e78e48b274bf7d64bf9aecdb82",
+ "d05d550054735c6e7e01b6981fc14b4e",
+ "4a34dfe4f5410afd7c40b1e110377a73",
+ "d9f597c96b41f641da6c83d4760f543b",
+ "371ad8cc920c6bda2a26d8f237bd446b"
+ };
+
+ for (int i = 0; i < ciphers.length; i++)
+ {
+ String cipherName = ciphers[i];
+ Cipher cipher;
+ try
+ {
+ cipher = Cipher.getInstance(cipherName, "BC");
+ }
+ catch (Exception e)
+ {
+ System.err.println(cipherName + ": " + e.getMessage());
+ continue;
+ }
+ int blocksize;
+ try
+ {
+ blocksize = cipher.getBlockSize();
+ }
+ catch (Exception e)
+ {
+ System.err.println(cipherName + ": " + e.getMessage());
+ continue;
+ }
+ // GCM is defined over 128 bit block ciphers
+ if (blocksize == 16)
+ {
+ String macName = cipherName + "-GMAC";
+ String macNameAlt = cipherName + "GMAC";
+
+ // Check we have a GMAC registered for each name
+ checkMac(macName, missingMacs, missingKeyGens, macs[i]);
+ checkMac(macNameAlt, missingMacs, missingKeyGens, macs[i]);
+ }
+ }
+ if (missingMacs.size() != 0)
+ {
+ fail("Did not find GMAC registrations for the following ciphers: " + missingMacs);
+ }
+ if (missingKeyGens.size() != 0)
+ {
+ Collections.sort(missingKeyGens);
+ fail("Did not find GMAC KeyGenerator registrations for the following macs: " + missingKeyGens);
+ }
+ }
+
+ private void checkMac(String name, List<String> missingMacs, List<String> missingKeyGens, String macOutput)
+ {
+ try
+ {
+ Mac mac = Mac.getInstance(name);
+
+ mac.init(new SecretKeySpec(new byte[mac.getMacLength()], mac.getAlgorithm()), new IvParameterSpec(
+ new byte[16]));
+ mac.update(new byte[128]);
+ byte[] bytes = mac.doFinal();
+
+ if (!Arrays.areEqual(bytes, Hex.decode(macOutput)))
+ {
+ fail("wrong mac value computed for " + name);
+ }
+
+ try
+ {
+ KeyGenerator kg = KeyGenerator.getInstance(name);
+ kg.generateKey();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ missingKeyGens.add(name);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ missingMacs.add(name);
+ }
+ catch (TestFailedException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ fail("Unexpected error", e);
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new GMacTest());
+ }
+} \ No newline at end of file
diff --git a/src/test/java/org/bouncycastle/jce/provider/test/JceTestUtil.java b/src/test/java/org/bouncycastle/jce/provider/test/JceTestUtil.java
new file mode 100644
index 00000000..9c0805a8
--- /dev/null
+++ b/src/test/java/org/bouncycastle/jce/provider/test/JceTestUtil.java
@@ -0,0 +1,49 @@
+package org.bouncycastle.jce.provider.test;
+
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+abstract class JceTestUtil
+{
+ private JceTestUtil()
+ {
+ }
+
+ static String[] getRegisteredAlgorithms(String prefix, String[] exclusionPatterns)
+ {
+ final BouncyCastleProvider prov = (BouncyCastleProvider)Security.getProvider("BC");
+
+ List matches = new ArrayList();
+ Enumeration algos = prov.keys();
+ while (algos.hasMoreElements())
+ {
+ String algo = (String)algos.nextElement();
+ if (!algo.startsWith(prefix))
+ {
+ continue;
+ }
+ String algoName = algo.substring(prefix.length());
+ if (!isExcluded(algoName, exclusionPatterns))
+ {
+ matches.add(algoName);
+ }
+ }
+ return (String[])matches.toArray(new String[matches.size()]);
+ }
+
+ private static boolean isExcluded(String algoName, String[] exclusionPatterns)
+ {
+ for (int i = 0; i < exclusionPatterns.length; i++)
+ {
+ if (algoName.contains(exclusionPatterns[i]))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java b/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java
index 52026bdb..85972a05 100644
--- a/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java
+++ b/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java
@@ -67,6 +67,7 @@ public class RegressionTest
new SigNameTest(),
new MQVTest(),
new CMacTest(),
+ new GMacTest(),
new DSTU4145Test(),
new CRL5Test(),
new SipHashTest(),