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:
Diffstat (limited to 'prov/src/main/java/org/spongycastle/pqc/jcajce/provider')
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java157
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/McEliece.java62
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/Rainbow.java36
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java131
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java307
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java227
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java334
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java231
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java346
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java47
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java131
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java253
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java343
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java146
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java47
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java307
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java171
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java247
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java243
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java170
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java236
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java72
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeysToParams.java49
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java164
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java522
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricHybridCipher.java397
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/CipherSpiExt.java635
-rw-r--r--prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/KeyUtil.java72
28 files changed, 6083 insertions, 0 deletions
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
new file mode 100644
index 00000000..b237aee4
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java
@@ -0,0 +1,157 @@
+package org.spongycastle.pqc.jcajce.provider;
+
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivateKey;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.config.ProviderConfiguration;
+import org.spongycastle.jcajce.provider.util.AlgorithmProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class BouncyCastlePQCProvider
+ extends Provider
+ implements ConfigurableProvider
+{
+ private static String info = "BouncyCastle Post-Quantum Security Provider v1.50";
+
+ public static String PROVIDER_NAME = "BCPQC";
+
+ public static final ProviderConfiguration CONFIGURATION = null;
+
+
+ private static final Map keyInfoConverters = new HashMap();
+
+ /*
+ * Configurable symmetric ciphers
+ */
+ private static final String ALGORITHM_PACKAGE = "org.spongycastle.pqc.jcajce.provider.";
+ private static final String[] ALGORITHMS =
+ {
+ "Rainbow", "McEliece"
+ };
+
+ /**
+ * Construct a new provider. This should only be required when
+ * using runtime registration of the provider using the
+ * <code>Security.addProvider()</code> mechanism.
+ */
+ public BouncyCastlePQCProvider()
+ {
+ super(PROVIDER_NAME, 1.50, info);
+
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ setup();
+ return null;
+ }
+ });
+ }
+
+ private void setup()
+ {
+ loadAlgorithms(ALGORITHM_PACKAGE, ALGORITHMS);
+ }
+
+ private void loadAlgorithms(String packageName, String[] names)
+ {
+ for (int i = 0; i != names.length; i++)
+ {
+ Class clazz = null;
+ try
+ {
+ ClassLoader loader = this.getClass().getClassLoader();
+
+ if (loader != null)
+ {
+ clazz = loader.loadClass(packageName + names[i] + "$Mappings");
+ }
+ else
+ {
+ clazz = Class.forName(packageName + names[i] + "$Mappings");
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ // ignore
+ }
+
+ if (clazz != null)
+ {
+ try
+ {
+ ((AlgorithmProvider)clazz.newInstance()).configure(this);
+ }
+ catch (Exception e)
+ { // this should never ever happen!!
+ throw new InternalError("cannot create instance of "
+ + packageName + names[i] + "$Mappings : " + e);
+ }
+ }
+ }
+ }
+
+ public void setParameter(String parameterName, Object parameter)
+ {
+ synchronized (CONFIGURATION)
+ {
+ //((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter);
+ }
+ }
+
+ public boolean hasAlgorithm(String type, String name)
+ {
+ return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name);
+ }
+
+ public void addAlgorithm(String key, String value)
+ {
+ if (containsKey(key))
+ {
+ throw new IllegalStateException("duplicate provider key (" + key + ") found");
+ }
+
+ put(key, value);
+ }
+
+ public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
+ {
+ keyInfoConverters.put(oid, keyInfoConverter);
+ }
+
+ public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePublic(publicKeyInfo);
+ }
+
+ public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePrivate(privateKeyInfo);
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/McEliece.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/McEliece.java
new file mode 100644
index 00000000..06f16f85
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/McEliece.java
@@ -0,0 +1,62 @@
+package org.spongycastle.pqc.jcajce.provider;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+
+public class McEliece
+{
+ private static final String PREFIX = "org.spongycastle.pqc.jcajce.provider" + ".mceliece.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ // McElieceKobaraImai
+ provider.addAlgorithm("KeyPairGenerator.McElieceKobaraImai", PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
+ // McEliecePointcheval
+ provider.addAlgorithm("KeyPairGenerator.McEliecePointcheval", PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
+ // McElieceFujisaki
+ provider.addAlgorithm("KeyPairGenerator.McElieceFujisaki", PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
+ // McEliecePKCS
+ provider.addAlgorithm("KeyPairGenerator.McEliecePKCS", PREFIX + "McElieceKeyPairGeneratorSpi$McEliece");
+
+ provider.addAlgorithm("KeyPairGenerator." + PQCObjectIdentifiers.mcEliece, PREFIX + "McElieceKeyPairGeneratorSpi$McEliece");
+ provider.addAlgorithm("KeyPairGenerator." + PQCObjectIdentifiers.mcElieceCca2, PREFIX + "McElieceKeyPairGeneratorSpi$McElieceCCA2");
+
+ provider.addAlgorithm("Cipher.McEliecePointcheval", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA1", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA224", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval224");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA256", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval256");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA384", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval384");
+ provider.addAlgorithm("Cipher.McEliecePointchevalWithSHA512", PREFIX + "McEliecePointchevalCipherSpi$McEliecePointcheval512");
+
+ provider.addAlgorithm("Cipher.McEliecePKCS", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA1", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA224", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS224");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA256", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS256");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA384", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS384");
+ provider.addAlgorithm("Cipher.McEliecePKCSWithSHA512", PREFIX + "McEliecePKCSCipherSpi$McEliecePKCS512");
+
+ provider.addAlgorithm("Cipher.McElieceKobaraImai", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA1", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA224", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai224");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA256", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai256");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA384", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai384");
+ provider.addAlgorithm("Cipher.McElieceKobaraImaiWithSHA512", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai512");
+
+ provider.addAlgorithm("Cipher.McElieceFujisaki", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA1", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA224", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki224");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA256", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki256");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA384", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki384");
+ provider.addAlgorithm("Cipher.McElieceFujisakiWithSHA512", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki512");
+
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/Rainbow.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/Rainbow.java
new file mode 100644
index 00000000..7752c4bf
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/Rainbow.java
@@ -0,0 +1,36 @@
+package org.spongycastle.pqc.jcajce.provider;
+
+import org.spongycastle.jcajce.provider.config.ConfigurableProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.spongycastle.pqc.jcajce.provider.rainbow.RainbowKeyFactorySpi;
+
+public class Rainbow
+{
+ private static final String PREFIX = "org.spongycastle.pqc.jcajce.provider" + ".rainbow.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyFactory.Rainbow", PREFIX + "RainbowKeyFactorySpi");
+ provider.addAlgorithm("KeyPairGenerator.Rainbow", PREFIX + "RainbowKeyPairGeneratorSpi");
+
+ addSignatureAlgorithm(provider, "SHA224", "Rainbow", PREFIX + "SignatureSpi$withSha224", PQCObjectIdentifiers.rainbowWithSha224);
+ addSignatureAlgorithm(provider, "SHA256", "Rainbow", PREFIX + "SignatureSpi$withSha256", PQCObjectIdentifiers.rainbowWithSha256);
+ addSignatureAlgorithm(provider, "SHA384", "Rainbow", PREFIX + "SignatureSpi$withSha384", PQCObjectIdentifiers.rainbowWithSha384);
+ addSignatureAlgorithm(provider, "SHA512", "Rainbow", PREFIX + "SignatureSpi$withSha512", PQCObjectIdentifiers.rainbowWithSha512);
+
+ AsymmetricKeyInfoConverter keyFact = new RainbowKeyFactorySpi();
+
+ registerOid(provider, PQCObjectIdentifiers.rainbow, "Rainbow", keyFact);
+ registerOidAlgorithmParameters(provider, PQCObjectIdentifiers.rainbow, "Rainbow");
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java
new file mode 100644
index 00000000..b3253160
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java
@@ -0,0 +1,131 @@
+package org.spongycastle.pqc.jcajce.provider.gmss;
+
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.GMSSPublicKey;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.spongycastle.pqc.asn1.ParSet;
+import org.spongycastle.pqc.crypto.gmss.GMSSParameters;
+import org.spongycastle.pqc.crypto.gmss.GMSSPublicKeyParameters;
+import org.spongycastle.pqc.jcajce.provider.util.KeyUtil;
+import org.spongycastle.pqc.jcajce.spec.GMSSPublicKeySpec;
+import org.spongycastle.util.encoders.Hex;
+
+/**
+ * This class implements the GMSS public key and is usually initiated by the <a
+ * href="GMSSKeyPairGenerator">GMSSKeyPairGenerator</a>.
+ *
+ * @see org.spongycastle.pqc.crypto.gmss.GMSSKeyPairGenerator
+ * @see org.spongycastle.pqc.jcajce.spec.GMSSPublicKeySpec
+ */
+public class BCGMSSPublicKey
+ implements CipherParameters, PublicKey
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * The GMSS public key
+ */
+ private byte[] publicKeyBytes;
+
+ /**
+ * The GMSSParameterSet
+ */
+ private GMSSParameters gmssParameterSet;
+
+
+ private GMSSParameters gmssParams;
+
+ /**
+ * The constructor
+ *
+ * @param pub a raw GMSS public key
+ * @param gmssParameterSet an instance of GMSS Parameterset
+ * @see org.spongycastle.pqc.crypto.gmss.GMSSKeyPairGenerator
+ */
+ public BCGMSSPublicKey(byte[] pub, GMSSParameters gmssParameterSet)
+ {
+ this.gmssParameterSet = gmssParameterSet;
+ this.publicKeyBytes = pub;
+ }
+
+ /**
+ * The constructor
+ *
+ * @param keySpec a GMSS key specification
+ */
+ protected BCGMSSPublicKey(GMSSPublicKeySpec keySpec)
+ {
+ this(keySpec.getPublicKey(), keySpec.getParameters());
+ }
+
+ public BCGMSSPublicKey(
+ GMSSPublicKeyParameters params)
+ {
+ this(params.getPublicKey(), params.getParameters());
+ }
+
+ /**
+ * Returns the name of the algorithm
+ *
+ * @return "GMSS"
+ */
+ public String getAlgorithm()
+ {
+ return "GMSS";
+ }
+
+ /**
+ * @return The GMSS public key byte array
+ */
+ public byte[] getPublicKeyBytes()
+ {
+ return publicKeyBytes;
+ }
+
+ /**
+ * @return The GMSS Parameterset
+ */
+ public GMSSParameters getParameterSet()
+ {
+ return gmssParameterSet;
+ }
+
+ /**
+ * Returns a human readable form of the GMSS public key
+ *
+ * @return A human readable form of the GMSS public key
+ */
+ public String toString()
+ {
+ String out = "GMSS public key : "
+ + new String(Hex.encode(publicKeyBytes)) + "\n"
+ + "Height of Trees: \n";
+
+ for (int i = 0; i < gmssParameterSet.getHeightOfTrees().length; i++)
+ {
+ out = out + "Layer " + i + " : "
+ + gmssParameterSet.getHeightOfTrees()[i]
+ + " WinternitzParameter: "
+ + gmssParameterSet.getWinternitzParameter()[i] + " K: "
+ + gmssParameterSet.getK()[i] + "\n";
+ }
+ return out;
+ }
+
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PQCObjectIdentifiers.gmss, new ParSet(gmssParameterSet.getNumOfLayers(), gmssParameterSet.getHeightOfTrees(), gmssParameterSet.getWinternitzParameter(), gmssParameterSet.getK()).toASN1Primitive()), new GMSSPublicKey(publicKeyBytes));
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java
new file mode 100644
index 00000000..0a22dd6f
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java
@@ -0,0 +1,307 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.McElieceCCA2PrivateKey;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2PrivateKeySpec;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+import org.spongycastle.pqc.math.linearalgebra.GF2mField;
+import org.spongycastle.pqc.math.linearalgebra.Permutation;
+import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+
+/**
+ * This class implements a McEliece CCA2 private key and is usually instantiated
+ * by the {@link McElieceCCA2KeyPairGenerator} or {@link McElieceCCA2KeyFactorySpi}.
+ *
+ * @see McElieceCCA2KeyPairGenerator
+ */
+public class BCMcElieceCCA2PrivateKey
+ implements CipherParameters, PrivateKey
+{
+
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the dimension of the code, k>=n-mt
+ private int k;
+
+ // the finte field GF(2^m)
+ private GF2mField field;
+
+ // the irreducible Goppa polynomial
+ private PolynomialGF2mSmallM goppaPoly;
+
+ // the permutation
+ private Permutation p;
+
+ // the canonical check matrix
+ private GF2Matrix h;
+
+ // the matrix used to compute square roots in (GF(2^m))^t
+ private PolynomialGF2mSmallM[] qInv;
+
+ private McElieceCCA2Parameters mcElieceCCA2Params;
+
+ /**
+ * Constructor (used by the {@link McElieceCCA2KeyPairGenerator}).
+ *
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param field the field polynomial
+ * @param gp the irreducible Goppa polynomial
+ * @param p the permutation
+ * @param h the canonical check matrix
+ * @param qInv the matrix used to compute square roots in
+ * <tt>(GF(2^m))^t</tt>
+ */
+ public BCMcElieceCCA2PrivateKey(String oid, int n, int k, GF2mField field,
+ PolynomialGF2mSmallM gp, Permutation p, GF2Matrix h,
+ PolynomialGF2mSmallM[] qInv)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ this.field = field;
+ this.goppaPoly = gp;
+ this.p = p;
+ this.h = h;
+ this.qInv = qInv;
+ }
+
+ /**
+ * Constructor (used by the {@link McElieceCCA2KeyFactorySpi}).
+ *
+ * @param keySpec a {@link McElieceCCA2PrivateKeySpec}
+ */
+ public BCMcElieceCCA2PrivateKey(McElieceCCA2PrivateKeySpec keySpec)
+ {
+ this(keySpec.getOIDString(), keySpec.getN(), keySpec.getK(), keySpec.getField(), keySpec
+ .getGoppaPoly(), keySpec.getP(), keySpec.getH(), keySpec
+ .getQInv());
+ }
+
+ public BCMcElieceCCA2PrivateKey(McElieceCCA2PrivateKeyParameters params)
+ {
+ this(params.getOIDString(), params.getN(), params.getK(), params.getField(), params.getGoppaPoly(),
+ params.getP(), params.getH(), params.getQInv());
+ this.mcElieceCCA2Params = params.getParameters();
+ }
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return "McEliece"
+ */
+ public String getAlgorithm()
+ {
+ return "McEliece";
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return k;
+ }
+
+ /**
+ * @return the degree of the Goppa polynomial (error correcting capability)
+ */
+ public int getT()
+ {
+ return goppaPoly.getDegree();
+ }
+
+ /**
+ * @return the finite field
+ */
+ public GF2mField getField()
+ {
+ return field;
+ }
+
+ /**
+ * @return the irreducible Goppa polynomial
+ */
+ public PolynomialGF2mSmallM getGoppaPoly()
+ {
+ return goppaPoly;
+ }
+
+ /**
+ * @return the permutation vector
+ */
+ public Permutation getP()
+ {
+ return p;
+ }
+
+ /**
+ * @return the canonical check matrix
+ */
+ public GF2Matrix getH()
+ {
+ return h;
+ }
+
+ /**
+ * @return the matrix used to compute square roots in <tt>(GF(2^m))^t</tt>
+ */
+ public PolynomialGF2mSmallM[] getQInv()
+ {
+ return qInv;
+ }
+
+ /**
+ * @return a human readable form of the key
+ */
+ public String toString()
+ {
+ String result = "";
+ result += " extension degree of the field : " + n + "\n";
+ result += " dimension of the code : " + k + "\n";
+ result += " irreducible Goppa polynomial : " + goppaPoly + "\n";
+ return result;
+ }
+
+ /**
+ * Compare this key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof BCMcElieceCCA2PrivateKey))
+ {
+ return false;
+ }
+
+ BCMcElieceCCA2PrivateKey otherKey = (BCMcElieceCCA2PrivateKey)other;
+
+ return (n == otherKey.n) && (k == otherKey.k)
+ && field.equals(otherKey.field)
+ && goppaPoly.equals(otherKey.goppaPoly) && p.equals(otherKey.p)
+ && h.equals(otherKey.h);
+ }
+
+ /**
+ * @return the hash code of this key
+ */
+ public int hashCode()
+ {
+ return k + n + field.hashCode() + goppaPoly.hashCode() + p.hashCode()
+ + h.hashCode();
+ }
+
+ /**
+ * @return the OID of the algorithm
+ */
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+ /**
+ * @return the OID to encode in the SubjectPublicKeyInfo structure
+ */
+ protected ASN1ObjectIdentifier getOID()
+ {
+ return new ASN1ObjectIdentifier(McElieceCCA2KeyFactorySpi.OID);
+ }
+
+ /**
+ * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
+ * structure
+ */
+ protected ASN1Primitive getAlgParams()
+ {
+ return null; // FIXME: needed at all?
+ }
+
+
+ /**
+ * Return the keyData to encode in the SubjectPublicKeyInfo structure.
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * McEliecePrivateKey ::= SEQUENCE {
+ * m INTEGER -- extension degree of the field
+ * k INTEGER -- dimension of the code
+ * field OCTET STRING -- field polynomial
+ * goppaPoly OCTET STRING -- irreducible Goppa polynomial
+ * p OCTET STRING -- permutation vector
+ * matrixH OCTET STRING -- canonical check matrix
+ * sqRootMatrix SEQUENCE OF OCTET STRING -- square root matrix
+ * }
+ * </pre>
+ *
+ * @return the keyData to encode in the SubjectPublicKeyInfo structure
+ */
+ public byte[] getEncoded()
+ {
+ McElieceCCA2PrivateKey privateKey = new McElieceCCA2PrivateKey(new ASN1ObjectIdentifier(oid), n, k, field, goppaPoly, p, h, qInv);
+ PrivateKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+ pki = new PrivateKeyInfo(algorithmIdentifier, privateKey);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ try
+ {
+ byte[] encoded = pki.getEncoded();
+ return encoded;
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public McElieceCCA2Parameters getMcElieceCCA2Parameters()
+ {
+ return mcElieceCCA2Params;
+ }
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java
new file mode 100644
index 00000000..9c3361bc
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java
@@ -0,0 +1,227 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+
+import java.io.IOException;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.McElieceCCA2PublicKey;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2PublicKeySpec;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+
+/**
+ * This class implements a McEliece CCA2 public key and is usually instantiated
+ * by the {@link McElieceCCA2KeyPairGenerator} or {@link McElieceCCA2KeyFactorySpi}.
+ */
+public class BCMcElieceCCA2PublicKey
+ implements CipherParameters, PublicKey
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the error correction capability of the code
+ private int t;
+
+ // the generator matrix
+ private GF2Matrix g;
+
+ private McElieceCCA2Parameters McElieceCCA2Params;
+
+ /**
+ * Constructor (used by the {@link McElieceCCA2KeyPairGenerator}).
+ *
+ * @param n the length of the code
+ * @param t the error correction capability of the code
+ * @param g the generator matrix
+ */
+ public BCMcElieceCCA2PublicKey(String oid, int n, int t, GF2Matrix g)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.g = g;
+ }
+
+ /**
+ * Constructor (used by the {@link McElieceCCA2KeyFactorySpi}).
+ *
+ * @param keySpec a {@link McElieceCCA2PublicKeySpec}
+ */
+ public BCMcElieceCCA2PublicKey(McElieceCCA2PublicKeySpec keySpec)
+ {
+ this(keySpec.getOIDString(), keySpec.getN(), keySpec.getT(), keySpec.getMatrixG());
+ }
+
+ public BCMcElieceCCA2PublicKey(McElieceCCA2PublicKeyParameters params)
+ {
+ this(params.getOIDString(), params.getN(), params.getT(), params.getMatrixG());
+ this.McElieceCCA2Params = params.getParameters();
+ }
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return "McEliece"
+ */
+ public String getAlgorithm()
+ {
+ return "McEliece";
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return g.getNumRows();
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the generator matrix
+ */
+ public GF2Matrix getG()
+ {
+ return g;
+ }
+
+ /**
+ * @return a human readable form of the key
+ */
+ public String toString()
+ {
+ String result = "McEliecePublicKey:\n";
+ result += " length of the code : " + n + "\n";
+ result += " error correction capability: " + t + "\n";
+ result += " generator matrix : " + g.toString();
+ return result;
+ }
+
+ /**
+ * Compare this key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof BCMcElieceCCA2PublicKey))
+ {
+ return false;
+ }
+
+ BCMcElieceCCA2PublicKey otherKey = (BCMcElieceCCA2PublicKey)other;
+
+ return (n == otherKey.n) && (t == otherKey.t) && (g.equals(otherKey.g));
+ }
+
+ /**
+ * @return the hash code of this key
+ */
+ public int hashCode()
+ {
+ return n + t + g.hashCode();
+ }
+
+ /**
+ * @return the OID of the algorithm
+ */
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+ /**
+ * @return the OID to encode in the SubjectPublicKeyInfo structure
+ */
+ protected ASN1ObjectIdentifier getOID()
+ {
+ return new ASN1ObjectIdentifier(McElieceCCA2KeyFactorySpi.OID);
+ }
+
+ /**
+ * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
+ * structure
+ */
+ protected ASN1Primitive getAlgParams()
+ {
+ return null; // FIXME: needed at all?
+ }
+
+ /**
+ * Return the keyData to encode in the SubjectPublicKeyInfo structure.
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * McEliecePublicKey ::= SEQUENCE {
+ * n Integer -- length of the code
+ * t Integer -- error correcting capability
+ * matrixG OctetString -- generator matrix as octet string
+ * }
+ * </pre>
+ *
+ * @return the keyData to encode in the SubjectPublicKeyInfo structure
+ */
+ public byte[] getEncoded()
+ {
+ McElieceCCA2PublicKey key = new McElieceCCA2PublicKey(new ASN1ObjectIdentifier(oid), n, t, g);
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+
+ try
+ {
+ SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(algorithmIdentifier, key);
+
+ return subjectPublicKeyInfo.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+
+ }
+
+ public String getFormat()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public McElieceCCA2Parameters getMcElieceCCA2Parameters()
+ {
+ return McElieceCCA2Params;
+ }
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java
new file mode 100644
index 00000000..21e778a4
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java
@@ -0,0 +1,334 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.McEliecePrivateKey;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.McEliecePrivateKeySpec;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+import org.spongycastle.pqc.math.linearalgebra.GF2mField;
+import org.spongycastle.pqc.math.linearalgebra.Permutation;
+import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+
+/**
+ * This class implements a McEliece private key and is usually instantiated by
+ * the {@link McElieceKeyPairGenerator} or {@link McElieceKeyFactorySpi}.
+ */
+public class BCMcEliecePrivateKey
+ implements CipherParameters, PrivateKey
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ // the OID of the algorithm
+ private String oid;
+
+ // the length of the code
+ private int n;
+
+ // the dimension of the code, where <tt>k &gt;= n - mt</tt>
+ private int k;
+
+ // the underlying finite field
+ private GF2mField field;
+
+ // the irreducible Goppa polynomial
+ private PolynomialGF2mSmallM goppaPoly;
+
+ // the matrix S^-1
+ private GF2Matrix sInv;
+
+ // the permutation P1 used to generate the systematic check matrix
+ private Permutation p1;
+
+ // the permutation P2 used to compute the public generator matrix
+ private Permutation p2;
+
+ // the canonical check matrix of the code
+ private GF2Matrix h;
+
+ // the matrix used to compute square roots in <tt>(GF(2^m))^t</tt>
+ private PolynomialGF2mSmallM[] qInv;
+
+ private McElieceParameters mcElieceParams;
+
+
+ /**
+ * Constructor (used by the {@link McElieceKeyPairGenerator}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param k the dimension of the code
+ * @param field the field polynomial defining the finite field
+ * <tt>GF(2<sup>m</sup>)</tt>
+ * @param goppaPoly the irreducible Goppa polynomial
+ * @param sInv the matrix <tt>S<sup>-1</sup></tt>
+ * @param p1 the permutation used to generate the systematic check
+ * matrix
+ * @param p2 the permutation used to compute the public generator
+ * matrix
+ * @param h the canonical check matrix
+ * @param qInv the matrix used to compute square roots in
+ * <tt>(GF(2<sup>m</sup>))<sup>t</sup></tt>
+ */
+ public BCMcEliecePrivateKey(String oid, int n, int k, GF2mField field,
+ PolynomialGF2mSmallM goppaPoly, GF2Matrix sInv, Permutation p1,
+ Permutation p2, GF2Matrix h, PolynomialGF2mSmallM[] qInv)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.k = k;
+ this.field = field;
+ this.goppaPoly = goppaPoly;
+ this.sInv = sInv;
+ this.p1 = p1;
+ this.p2 = p2;
+ this.h = h;
+ this.qInv = qInv;
+ }
+
+ /**
+ * Constructor (used by the {@link McElieceKeyFactorySpi}).
+ *
+ * @param keySpec a {@link McEliecePrivateKeySpec}
+ */
+ public BCMcEliecePrivateKey(McEliecePrivateKeySpec keySpec)
+ {
+ this(keySpec.getOIDString(), keySpec.getN(), keySpec.getK(), keySpec.getField(), keySpec
+ .getGoppaPoly(), keySpec.getSInv(), keySpec.getP1(), keySpec
+ .getP2(), keySpec.getH(), keySpec.getQInv());
+ }
+
+ public BCMcEliecePrivateKey(McEliecePrivateKeyParameters params)
+ {
+ this(params.getOIDString(), params.getN(), params.getK(), params.getField(), params.getGoppaPoly(),
+ params.getSInv(), params.getP1(), params.getP2(), params.getH(), params.getQInv());
+
+ this.mcElieceParams = params.getParameters();
+ }
+
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return "McEliece"
+ */
+ public String getAlgorithm()
+ {
+ return "McEliece";
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return k;
+ }
+
+ /**
+ * @return the finite field
+ */
+ public GF2mField getField()
+ {
+ return field;
+ }
+
+ /**
+ * @return the irreducible Goppa polynomial
+ */
+ public PolynomialGF2mSmallM getGoppaPoly()
+ {
+ return goppaPoly;
+ }
+
+ /**
+ * @return the k x k random binary non-singular matrix S
+ */
+ public GF2Matrix getSInv()
+ {
+ return sInv;
+ }
+
+ /**
+ * @return the permutation used to generate the systematic check matrix
+ */
+ public Permutation getP1()
+ {
+ return p1;
+ }
+
+ /**
+ * @return the permutation used to compute the public generator matrix
+ */
+ public Permutation getP2()
+ {
+ return p2;
+ }
+
+ /**
+ * @return the canonical check matrix
+ */
+ public GF2Matrix getH()
+ {
+ return h;
+ }
+
+ /**
+ * @return the matrix for computing square roots in <tt>(GF(2^m))^t</tt>
+ */
+ public PolynomialGF2mSmallM[] getQInv()
+ {
+ return qInv;
+ }
+
+ /**
+ * @return the OID of the algorithm
+ */
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+ /**
+ * @return a human readable form of the key
+ */
+ public String toString()
+ {
+ String result = " length of the code : " + n + "\n";
+ result += " dimension of the code : " + k + "\n";
+ result += " irreducible Goppa polynomial: " + goppaPoly + "\n";
+ result += " (k x k)-matrix S^-1 : " + sInv + "\n";
+ result += " permutation P1 : " + p1 + "\n";
+ result += " permutation P2 : " + p2;
+ return result;
+ }
+
+ /**
+ * Compare this key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (!(other instanceof BCMcEliecePrivateKey))
+ {
+ return false;
+ }
+ BCMcEliecePrivateKey otherKey = (BCMcEliecePrivateKey)other;
+
+ return (n == otherKey.n) && (k == otherKey.k)
+ && field.equals(otherKey.field)
+ && goppaPoly.equals(otherKey.goppaPoly)
+ && sInv.equals(otherKey.sInv) && p1.equals(otherKey.p1)
+ && p2.equals(otherKey.p2) && h.equals(otherKey.h);
+ }
+
+ /**
+ * @return the hash code of this key
+ */
+ public int hashCode()
+ {
+ return k + n + field.hashCode() + goppaPoly.hashCode()
+ + sInv.hashCode() + p1.hashCode() + p2.hashCode()
+ + h.hashCode();
+ }
+
+ /**
+ * @return the OID to encode in the SubjectPublicKeyInfo structure
+ */
+ protected ASN1ObjectIdentifier getOID()
+ {
+ return new ASN1ObjectIdentifier(McElieceKeyFactorySpi.OID);
+ }
+
+ /**
+ * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
+ * structure
+ */
+ protected ASN1Primitive getAlgParams()
+ {
+ return null; // FIXME: needed at all?
+ }
+
+ /**
+ * Return the key data to encode in the SubjectPublicKeyInfo structure.
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * McEliecePrivateKey ::= SEQUENCE {
+ * n INTEGER -- length of the code
+ * k INTEGER -- dimension of the code
+ * fieldPoly OCTET STRING -- field polynomial defining GF(2&circ;m)
+ * goppaPoly OCTET STRING -- irreducible Goppa polynomial
+ * sInv OCTET STRING -- matrix S&circ;-1
+ * p1 OCTET STRING -- permutation P1
+ * p2 OCTET STRING -- permutation P2
+ * h OCTET STRING -- canonical check matrix
+ * qInv SEQUENCE OF OCTET STRING -- matrix used to compute square roots
+ * }
+ * </pre>
+ *
+ * @return the key data to encode in the SubjectPublicKeyInfo structure
+ */
+ public byte[] getEncoded()
+ {
+ McEliecePrivateKey privateKey = new McEliecePrivateKey(new ASN1ObjectIdentifier(oid), n, k, field, goppaPoly, sInv, p1, p2, h, qInv);
+ PrivateKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+ pki = new PrivateKeyInfo(algorithmIdentifier, privateKey);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ try
+ {
+ byte[] encoded = pki.getEncoded();
+ return encoded;
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public McElieceParameters getMcElieceParameters()
+ {
+ return mcElieceParams;
+ }
+
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java
new file mode 100644
index 00000000..25c6fd14
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java
@@ -0,0 +1,231 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.pqc.asn1.McEliecePublicKey;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.McEliecePublicKeySpec;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+
+/**
+ * This class implements a McEliece public key and is usually instantiated by
+ * the {@link McElieceKeyPairGenerator} or {@link McElieceKeyFactorySpi}.
+ */
+public class BCMcEliecePublicKey
+ implements CipherParameters, PublicKey
+{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ // the OID of the algorithm
+ private String oid;
+
+ /**
+ * the length of the code
+ */
+ private int n;
+
+ /**
+ * the error correction capability of the code
+ */
+ private int t;
+
+ /**
+ * the generator matrix
+ */
+ private GF2Matrix g;
+
+ private McElieceParameters McElieceParams;
+
+ /**
+ * Constructor (used by the {@link McElieceKeyPairGenerator}).
+ *
+ * @param oid
+ * @param n the length of the code
+ * @param t the error correction capability of the code
+ * @param g the generator matrix
+ */
+ public BCMcEliecePublicKey(String oid, int n, int t, GF2Matrix g)
+ {
+ this.oid = oid;
+ this.n = n;
+ this.t = t;
+ this.g = g;
+ }
+
+ /**
+ * Constructor (used by the {@link McElieceKeyFactorySpi}).
+ *
+ * @param keySpec a {@link McEliecePublicKeySpec}
+ */
+ public BCMcEliecePublicKey(McEliecePublicKeySpec keySpec)
+ {
+ this(keySpec.getOIDString(), keySpec.getN(), keySpec.getT(), keySpec.getG());
+ }
+
+ public BCMcEliecePublicKey(McEliecePublicKeyParameters params)
+ {
+ this(params.getOIDString(), params.getN(), params.getT(), params.getG());
+ this.McElieceParams = params.getParameters();
+ }
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return "McEliece"
+ */
+ public String getAlgorithm()
+ {
+ return "McEliece";
+ }
+
+ /**
+ * @return the length of the code
+ */
+ public int getN()
+ {
+ return n;
+ }
+
+ /**
+ * @return the dimension of the code
+ */
+ public int getK()
+ {
+ return g.getNumRows();
+ }
+
+ /**
+ * @return the error correction capability of the code
+ */
+ public int getT()
+ {
+ return t;
+ }
+
+ /**
+ * @return the generator matrix
+ */
+ public GF2Matrix getG()
+ {
+ return g;
+ }
+
+ /**
+ * @return a human readable form of the key
+ */
+ public String toString()
+ {
+ String result = "McEliecePublicKey:\n";
+ result += " length of the code : " + n + "\n";
+ result += " error correction capability: " + t + "\n";
+ result += " generator matrix : " + g.toString();
+ return result;
+ }
+
+ /**
+ * Compare this key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (!(other instanceof BCMcEliecePublicKey))
+ {
+ return false;
+ }
+ BCMcEliecePublicKey otherKey = (BCMcEliecePublicKey)other;
+
+ return (n == otherKey.n) && (t == otherKey.t) && g.equals(otherKey.g);
+ }
+
+ /**
+ * @return the hash code of this key
+ */
+ public int hashCode()
+ {
+ return n + t + g.hashCode();
+ }
+
+
+ /**
+ * @return the OID of the algorithm
+ */
+ public String getOIDString()
+ {
+ return oid;
+ }
+
+ /**
+ * @return the OID to encode in the SubjectPublicKeyInfo structure
+ */
+ protected ASN1ObjectIdentifier getOID()
+ {
+ return new ASN1ObjectIdentifier(McElieceKeyFactorySpi.OID);
+ }
+
+ /**
+ * @return the algorithm parameters to encode in the SubjectPublicKeyInfo
+ * structure
+ */
+ protected ASN1Primitive getAlgParams()
+ {
+ return null; // FIXME: needed at all?
+ }
+
+
+ /**
+ * Return the keyData to encode in the SubjectPublicKeyInfo structure.
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * McEliecePublicKey ::= SEQUENCE {
+ * n Integer -- length of the code
+ * t Integer -- error correcting capability
+ * matrixG OctetString -- generator matrix as octet string
+ * }
+ * </pre>
+ *
+ * @return the keyData to encode in the SubjectPublicKeyInfo structure
+ */
+ public byte[] getEncoded()
+ {
+ McEliecePublicKey key = new McEliecePublicKey(new ASN1ObjectIdentifier(oid), n, t, g);
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(this.getOID(), DERNull.INSTANCE);
+
+ try
+ {
+ SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(algorithmIdentifier, key);
+
+ return subjectPublicKeyInfo.getEncoded();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public McElieceParameters getMcElieceParameters()
+ {
+ return McElieceParams;
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java
new file mode 100644
index 00000000..d3de79bf
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java
@@ -0,0 +1,346 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.pqc.asn1.McElieceCCA2PrivateKey;
+import org.spongycastle.pqc.asn1.McElieceCCA2PublicKey;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2PrivateKeySpec;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2PublicKeySpec;
+
+/**
+ * This class is used to translate between McEliece CCA2 keys and key
+ * specifications.
+ *
+ * @see BCMcElieceCCA2PrivateKey
+ * @see McElieceCCA2PrivateKeySpec
+ * @see BCMcElieceCCA2PublicKey
+ * @see McElieceCCA2PublicKeySpec
+ */
+public class McElieceCCA2KeyFactorySpi
+ extends KeyFactorySpi
+{
+
+ /**
+ * The OID of the algorithm.
+ */
+ public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2";
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCMcElieceCCA2PublicKey}. Currently, the following key
+ * specifications are supported: {@link McElieceCCA2PublicKeySpec},
+ * {@link X509EncodedKeySpec}.
+ *
+ * @param keySpec the key specification
+ * @return the McEliece CCA2 public key
+ * @throws InvalidKeySpecException if the key specification is not supported.
+ */
+ public PublicKey generatePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof McElieceCCA2PublicKeySpec)
+ {
+ return new BCMcElieceCCA2PublicKey(
+ (McElieceCCA2PublicKeySpec)keySpec);
+ }
+ else if (keySpec instanceof X509EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to X.509 from the spec
+ byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the SubjectPublicKeyInfo data structure to the pki object
+ SubjectPublicKeyInfo pki;
+ try
+ {
+ pki = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+
+
+ try
+ {
+ // --- Build and return the actual key.
+ ASN1Primitive innerType = pki.parsePublicKey();
+ ASN1Sequence publicKey = (ASN1Sequence)innerType;
+
+ // decode oidString (but we don't need it right now)
+ String oidString = ((ASN1ObjectIdentifier)publicKey.getObjectAt(0))
+ .toString();
+
+ // decode <n>
+ BigInteger bigN = ((ASN1Integer)publicKey.getObjectAt(1)).getValue();
+ int n = bigN.intValue();
+
+ // decode <t>
+ BigInteger bigT = ((ASN1Integer)publicKey.getObjectAt(2)).getValue();
+ int t = bigT.intValue();
+
+ // decode <matrixG>
+ byte[] matrixG = ((ASN1OctetString)publicKey.getObjectAt(3)).getOctets();
+
+ return new BCMcElieceCCA2PublicKey(new McElieceCCA2PublicKeySpec(
+ OID, n, t, matrixG));
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException(
+ "Unable to decode X509EncodedKeySpec: "
+ + cce.getMessage());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCMcElieceCCA2PrivateKey}. Currently, the following key
+ * specifications are supported: {@link McElieceCCA2PrivateKeySpec},
+ * {@link PKCS8EncodedKeySpec}.
+ *
+ * @param keySpec the key specification
+ * @return the McEliece CCA2 private key
+ * @throws InvalidKeySpecException if the KeySpec is not supported.
+ */
+ public PrivateKey generatePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof McElieceCCA2PrivateKeySpec)
+ {
+ return new BCMcElieceCCA2PrivateKey(
+ (McElieceCCA2PrivateKeySpec)keySpec);
+ }
+ else if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to PKCS#8 from the spec
+ byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the PKCS#8 data structure to the pki object
+ PrivateKeyInfo pki;
+
+ try
+ {
+ pki = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec: " + e);
+ }
+
+ try
+ {
+ // get the inner type inside the BIT STRING
+ ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
+
+ // build and return the actual key
+ ASN1Sequence privKey = (ASN1Sequence)innerType;
+
+ // decode oidString (but we don't need it right now)
+ String oidString = ((ASN1ObjectIdentifier)privKey.getObjectAt(0))
+ .toString();
+
+ // decode <n>
+ BigInteger bigN = ((ASN1Integer)privKey.getObjectAt(1)).getValue();
+ int n = bigN.intValue();
+
+ // decode <k>
+ BigInteger bigK = ((ASN1Integer)privKey.getObjectAt(2)).getValue();
+ int k = bigK.intValue();
+
+
+ // decode <fieldPoly>
+ byte[] encFieldPoly = ((ASN1OctetString)privKey.getObjectAt(3))
+ .getOctets();
+ // decode <goppaPoly>
+ byte[] encGoppaPoly = ((ASN1OctetString)privKey.getObjectAt(4))
+ .getOctets();
+ // decode <p>
+ byte[] encP = ((ASN1OctetString)privKey.getObjectAt(5)).getOctets();
+ // decode <h>
+ byte[] encH = ((ASN1OctetString)privKey.getObjectAt(6)).getOctets();
+ // decode <qInv>
+ ASN1Sequence qSeq = (ASN1Sequence)privKey.getObjectAt(7);
+ byte[][] encQInv = new byte[qSeq.size()][];
+ for (int i = 0; i < qSeq.size(); i++)
+ {
+ encQInv[i] = ((ASN1OctetString)qSeq.getObjectAt(i)).getOctets();
+ }
+
+ return new BCMcElieceCCA2PrivateKey(
+ new McElieceCCA2PrivateKeySpec(OID, n, k, encFieldPoly,
+ encGoppaPoly, encP, encH, encQInv));
+
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException(
+ "Unable to decode PKCS8EncodedKeySpec.");
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a given key into a key specification. Currently,
+ * the following key specifications are supported:
+ * <ul>
+ * <li>for McElieceCCA2PublicKey: {@link X509EncodedKeySpec},
+ * {@link McElieceCCA2PublicKeySpec}</li>
+ * <li>for McElieceCCA2PrivateKey: {@link PKCS8EncodedKeySpec},
+ * {@link McElieceCCA2PrivateKeySpec}</li>.
+ * </ul>
+ *
+ * @param key the key
+ * @param keySpec the key specification
+ * @return the specification of the McEliece CCA2 key
+ * @throws InvalidKeySpecException if the key type or the key specification is not
+ * supported.
+ * @see BCMcElieceCCA2PrivateKey
+ * @see McElieceCCA2PrivateKeySpec
+ * @see BCMcElieceCCA2PublicKey
+ * @see McElieceCCA2PublicKeySpec
+ */
+ public KeySpec getKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (key instanceof BCMcElieceCCA2PrivateKey)
+ {
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (McElieceCCA2PrivateKeySpec.class
+ .isAssignableFrom(keySpec))
+ {
+ BCMcElieceCCA2PrivateKey privKey = (BCMcElieceCCA2PrivateKey)key;
+ return new McElieceCCA2PrivateKeySpec(OID, privKey.getN(), privKey
+ .getK(), privKey.getField(), privKey.getGoppaPoly(),
+ privKey.getP(), privKey.getH(), privKey.getQInv());
+ }
+ }
+ else if (key instanceof BCMcElieceCCA2PublicKey)
+ {
+ if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ else if (McElieceCCA2PublicKeySpec.class
+ .isAssignableFrom(keySpec))
+ {
+ BCMcElieceCCA2PublicKey pubKey = (BCMcElieceCCA2PublicKey)key;
+ return new McElieceCCA2PublicKeySpec(OID, pubKey.getN(), pubKey
+ .getT(), pubKey.getG());
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unsupported key type: "
+ + key.getClass() + ".");
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: "
+ + keySpec + ".");
+ }
+
+ /**
+ * Translates a key into a form known by the FlexiProvider. Currently, only
+ * the following "source" keys are supported: {@link BCMcElieceCCA2PrivateKey},
+ * {@link BCMcElieceCCA2PublicKey}.
+ *
+ * @param key the key
+ * @return a key of a known key type
+ * @throws InvalidKeyException if the key type is not supported.
+ */
+ public Key translateKey(Key key)
+ throws InvalidKeyException
+ {
+ if ((key instanceof BCMcElieceCCA2PrivateKey)
+ || (key instanceof BCMcElieceCCA2PublicKey))
+ {
+ return key;
+ }
+ throw new InvalidKeyException("Unsupported key type.");
+
+ }
+
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo pki)
+ throws InvalidKeySpecException
+ {
+ // get the inner type inside the BIT STRING
+ try
+ {
+ ASN1Primitive innerType = pki.parsePublicKey();
+ McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance((ASN1Sequence)innerType);
+ return new BCMcElieceCCA2PublicKey(key.getOID().getId(), key.getN(), key.getT(), key.getG());
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException("Unable to decode X509EncodedKeySpec");
+ }
+ }
+
+
+ public PrivateKey generatePrivate(PrivateKeyInfo pki)
+ throws InvalidKeySpecException
+ {
+ // get the inner type inside the BIT STRING
+ try
+ {
+ ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
+ McElieceCCA2PrivateKey key = McElieceCCA2PrivateKey.getInstance(innerType);
+ return new BCMcElieceCCA2PrivateKey(key.getOID().getId(), key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), key.getH(), key.getQInv());
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec");
+ }
+ }
+
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected KeySpec engineGetKeySpec(Key key, Class tClass)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java
new file mode 100644
index 00000000..a733d2a0
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java
@@ -0,0 +1,47 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca McElieceCCA2 objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class McElieceCCA2KeysToParams
+{
+
+
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCMcElieceCCA2PublicKey)
+ {
+ BCMcElieceCCA2PublicKey k = (BCMcElieceCCA2PublicKey)key;
+
+ return new McElieceCCA2PublicKeyParameters(k.getOIDString(), k.getN(), k.getT(), k.getG(), k.getMcElieceCCA2Parameters());
+ }
+
+ throw new InvalidKeyException("can't identify McElieceCCA2 public key: " + key.getClass().getName());
+ }
+
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCMcElieceCCA2PrivateKey)
+ {
+ BCMcElieceCCA2PrivateKey k = (BCMcElieceCCA2PrivateKey)key;
+ return new McElieceCCA2PrivateKeyParameters(k.getOIDString(), k.getN(), k.getK(), k.getField(), k.getGoppaPoly(),
+ k.getP(), k.getH(), k.getQInv(), k.getMcElieceCCA2Parameters());
+ }
+
+ throw new InvalidKeyException("can't identify McElieceCCA2 private key.");
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java
new file mode 100644
index 00000000..a63c1852
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java
@@ -0,0 +1,131 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
+import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
+import org.spongycastle.pqc.math.linearalgebra.GF2Vector;
+import org.spongycastle.pqc.math.linearalgebra.GF2mField;
+import org.spongycastle.pqc.math.linearalgebra.GoppaCode;
+import org.spongycastle.pqc.math.linearalgebra.Permutation;
+import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
+import org.spongycastle.pqc.math.linearalgebra.Vector;
+
+/**
+ * Core operations for the CCA-secure variants of McEliece.
+ */
+public final class McElieceCCA2Primitives
+{
+
+ /**
+ * Default constructor (private).
+ */
+ private McElieceCCA2Primitives()
+ {
+ }
+
+ /**
+ * The McEliece encryption primitive.
+ *
+ * @param pubKey the public key
+ * @param m the message vector
+ * @param z the error vector
+ * @return <tt>m*G + z</tt>
+ */
+ public static GF2Vector encryptionPrimitive(BCMcElieceCCA2PublicKey pubKey,
+ GF2Vector m, GF2Vector z)
+ {
+
+ GF2Matrix matrixG = pubKey.getG();
+ Vector mG = matrixG.leftMultiplyLeftCompactForm(m);
+ return (GF2Vector)mG.add(z);
+ }
+
+ public static GF2Vector encryptionPrimitive(McElieceCCA2PublicKeyParameters pubKey,
+ GF2Vector m, GF2Vector z)
+ {
+
+ GF2Matrix matrixG = pubKey.getMatrixG();
+ Vector mG = matrixG.leftMultiplyLeftCompactForm(m);
+ return (GF2Vector)mG.add(z);
+ }
+
+ /**
+ * The McEliece decryption primitive.
+ *
+ * @param privKey the private key
+ * @param c the ciphertext vector <tt>c = m*G + z</tt>
+ * @return the message vector <tt>m</tt> and the error vector <tt>z</tt>
+ */
+ public static GF2Vector[] decryptionPrimitive(
+ BCMcElieceCCA2PrivateKey privKey, GF2Vector c)
+ {
+
+ // obtain values from private key
+ int k = privKey.getK();
+ Permutation p = privKey.getP();
+ GF2mField field = privKey.getField();
+ PolynomialGF2mSmallM gp = privKey.getGoppaPoly();
+ GF2Matrix h = privKey.getH();
+ PolynomialGF2mSmallM[] q = privKey.getQInv();
+
+ // compute inverse permutation P^-1
+ Permutation pInv = p.computeInverse();
+
+ // multiply c with permutation P^-1
+ GF2Vector cPInv = (GF2Vector)c.multiply(pInv);
+
+ // compute syndrome of cP^-1
+ GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv);
+
+ // decode syndrome
+ GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q);
+ GF2Vector mG = (GF2Vector)cPInv.add(errors);
+
+ // multiply codeword and error vector with P
+ mG = (GF2Vector)mG.multiply(p);
+ errors = (GF2Vector)errors.multiply(p);
+
+ // extract plaintext vector (last k columns of mG)
+ GF2Vector m = mG.extractRightVector(k);
+
+ // return vectors
+ return new GF2Vector[]{m, errors};
+ }
+
+ public static GF2Vector[] decryptionPrimitive(
+ McElieceCCA2PrivateKeyParameters privKey, GF2Vector c)
+ {
+
+ // obtain values from private key
+ int k = privKey.getK();
+ Permutation p = privKey.getP();
+ GF2mField field = privKey.getField();
+ PolynomialGF2mSmallM gp = privKey.getGoppaPoly();
+ GF2Matrix h = privKey.getH();
+ PolynomialGF2mSmallM[] q = privKey.getQInv();
+
+ // compute inverse permutation P^-1
+ Permutation pInv = p.computeInverse();
+
+ // multiply c with permutation P^-1
+ GF2Vector cPInv = (GF2Vector)c.multiply(pInv);
+
+ // compute syndrome of cP^-1
+ GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv);
+
+ // decode syndrome
+ GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q);
+ GF2Vector mG = (GF2Vector)cPInv.add(errors);
+
+ // multiply codeword and error vector with P
+ mG = (GF2Vector)mG.multiply(p);
+ errors = (GF2Vector)errors.multiply(p);
+
+ // extract plaintext vector (last k columns of mG)
+ GF2Vector m = mG.extractRightVector(k);
+
+ // return vectors
+ return new GF2Vector[]{m, errors};
+ }
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java
new file mode 100644
index 00000000..77e31c6a
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java
@@ -0,0 +1,253 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceFujisakiCipher;
+import org.spongycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
+
+public class McElieceFujisakiCipherSpi
+ extends AsymmetricHybridCipher
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ // TODO digest needed?
+ private Digest digest;
+ private McElieceFujisakiCipher cipher;
+
+ /**
+ * buffer to store the input data
+ */
+ private ByteArrayOutputStream buf;
+
+
+ protected McElieceFujisakiCipherSpi(Digest digest, McElieceFujisakiCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ buf = new ByteArrayOutputStream();
+
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation.
+ *
+ * @param input byte array containing the next part of the input
+ * @param inOff index in the array where the input starts
+ * @param inLen length of the input
+ * @return the processed byte array.
+ */
+ public byte[] update(byte[] input, int inOff, int inLen)
+ {
+ buf.write(input, inOff, inLen);
+ return new byte[0];
+ }
+
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted, depending on
+ * how this cipher was initialized.
+ *
+ * @param input the input buffer
+ * @param inOff the offset in input where the input starts
+ * @param inLen the input length
+ * @return the new buffer with the result
+ * @throws BadPaddingException on deryption errors.
+ */
+ public byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws BadPaddingException
+ {
+ update(input, inOff, inLen);
+ byte[] data = buf.toByteArray();
+ buf.reset();
+ if (opMode == ENCRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageEncrypt(data);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageDecrypt(data);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ return null;
+ }
+
+
+ protected int encryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected int decryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom sr)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+
+ param = new ParametersWithRandom(param, sr);
+ digest.reset();
+ cipher.init(true, param);
+
+ }
+
+ protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ public String getName()
+ {
+ return "McElieceFujisakiCipher";
+ }
+
+ public int getKeySize(Key key)
+ throws InvalidKeyException
+ {
+ McElieceCCA2KeyParameters mcElieceCCA2KeyParameters;
+ if (key instanceof PublicKey)
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+ }
+ else
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ }
+
+
+ return cipher.getKeySize(mcElieceCCA2KeyParameters);
+ }
+
+ public byte[] messageEncrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageEncrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ public byte[] messageDecrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageDecrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////
+
+ static public class McElieceFujisaki
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki()
+ {
+ super(new SHA1Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+ static public class McElieceFujisaki224
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki224()
+ {
+ super(new SHA224Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+ static public class McElieceFujisaki256
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki256()
+ {
+ super(new SHA256Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+ static public class McElieceFujisaki384
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki384()
+ {
+ super(new SHA384Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+ static public class McElieceFujisaki512
+ extends McElieceFujisakiCipherSpi
+ {
+ public McElieceFujisaki512()
+ {
+ super(new SHA512Digest(), new McElieceFujisakiCipher());
+ }
+ }
+
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java
new file mode 100644
index 00000000..1c2007a0
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java
@@ -0,0 +1,343 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.pqc.asn1.McEliecePrivateKey;
+import org.spongycastle.pqc.asn1.McEliecePublicKey;
+import org.spongycastle.pqc.jcajce.spec.McEliecePrivateKeySpec;
+import org.spongycastle.pqc.jcajce.spec.McEliecePublicKeySpec;
+
+/**
+ * This class is used to translate between McEliece keys and key specifications.
+ *
+ * @see BCMcEliecePrivateKey
+ * @see McEliecePrivateKeySpec
+ * @see BCMcEliecePublicKey
+ * @see McEliecePublicKeySpec
+ */
+public class McElieceKeyFactorySpi
+ extends KeyFactorySpi
+{
+ /**
+ * The OID of the algorithm.
+ */
+ public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1";
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCMcEliecePublicKey}. Currently, the following key specifications
+ * are supported: {@link McEliecePublicKeySpec}, {@link X509EncodedKeySpec}.
+ *
+ * @param keySpec the key specification
+ * @return the McEliece public key
+ * @throws InvalidKeySpecException if the key specification is not supported.
+ */
+ public PublicKey generatePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof McEliecePublicKeySpec)
+ {
+ return new BCMcEliecePublicKey((McEliecePublicKeySpec)keySpec);
+ }
+ else if (keySpec instanceof X509EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to X.509 from the spec
+ byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the SubjectPublicKeyInfo data structure to the pki object
+ SubjectPublicKeyInfo pki;
+ try
+ {
+ pki = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+
+ try
+ {
+ // --- Build and return the actual key.
+ ASN1Primitive innerType = pki.parsePublicKey();
+ ASN1Sequence publicKey = (ASN1Sequence)innerType;
+
+ // decode oidString (but we don't need it right now)
+ String oidString = ((ASN1ObjectIdentifier)publicKey.getObjectAt(0))
+ .toString();
+
+ // decode <n>
+ BigInteger bigN = ((ASN1Integer)publicKey.getObjectAt(1)).getValue();
+ int n = bigN.intValue();
+
+ // decode <t>
+ BigInteger bigT = ((ASN1Integer)publicKey.getObjectAt(2)).getValue();
+ int t = bigT.intValue();
+
+ // decode <matrixG>
+ byte[] matrixG = ((ASN1OctetString)publicKey.getObjectAt(3)).getOctets();
+
+
+ return new BCMcEliecePublicKey(new McEliecePublicKeySpec(OID, t, n,
+ matrixG));
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException(
+ "Unable to decode X509EncodedKeySpec: "
+ + cce.getMessage());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCMcEliecePrivateKey}. Currently, the following key specifications
+ * are supported: {@link McEliecePrivateKeySpec},
+ * {@link PKCS8EncodedKeySpec}.
+ *
+ * @param keySpec the key specification
+ * @return the McEliece private key
+ * @throws InvalidKeySpecException if the KeySpec is not supported.
+ */
+ public PrivateKey generatePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof McEliecePrivateKeySpec)
+ {
+ return new BCMcEliecePrivateKey((McEliecePrivateKeySpec)keySpec);
+ }
+ else if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to PKCS#8 from the spec
+ byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the PKCS#8 data structure to the pki object
+ PrivateKeyInfo pki;
+
+ try
+ {
+ pki = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey));
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec: " + e);
+ }
+
+ try
+ {
+ ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
+
+ // build and return the actual key
+ ASN1Sequence privKey = (ASN1Sequence)innerType;
+
+ // decode oidString (but we don't need it right now)
+ String oidString = ((ASN1ObjectIdentifier)privKey.getObjectAt(0))
+ .toString();
+
+ // decode <n>
+ BigInteger bigN = ((ASN1Integer)privKey.getObjectAt(1)).getValue();
+ int n = bigN.intValue();
+
+ // decode <k>
+ BigInteger bigK = ((ASN1Integer)privKey.getObjectAt(2)).getValue();
+ int k = bigK.intValue();
+
+ // decode <fieldPoly>
+ byte[] encFieldPoly = ((ASN1OctetString)privKey.getObjectAt(3))
+ .getOctets();
+ // decode <goppaPoly>
+ byte[] encGoppaPoly = ((ASN1OctetString)privKey.getObjectAt(4))
+ .getOctets();
+
+ // decode <sInv>
+ byte[] encSInv = ((ASN1OctetString)privKey.getObjectAt(5)).getOctets();
+ // decode <p1>
+ byte[] encP1 = ((ASN1OctetString)privKey.getObjectAt(6)).getOctets();
+ // decode <p2>
+ byte[] encP2 = ((ASN1OctetString)privKey.getObjectAt(7)).getOctets();
+
+ //decode <h>
+ byte[] encH = ((ASN1OctetString)privKey.getObjectAt(8)).getOctets();
+
+ // decode <qInv>
+ ASN1Sequence qSeq = (ASN1Sequence)privKey.getObjectAt(9);
+ byte[][] encQInv = new byte[qSeq.size()][];
+ for (int i = 0; i < qSeq.size(); i++)
+ {
+ encQInv[i] = ((ASN1OctetString)qSeq.getObjectAt(i)).getOctets();
+ }
+
+ return new BCMcEliecePrivateKey(new McEliecePrivateKeySpec(OID, n, k,
+ encFieldPoly, encGoppaPoly, encSInv, encP1, encP2,
+ encH, encQInv));
+
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException(
+ "Unable to decode PKCS8EncodedKeySpec.");
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a given key into a key specification. Currently,
+ * the following key specifications are supported:
+ * <ul>
+ * <li>for McEliecePublicKey: {@link X509EncodedKeySpec},
+ * {@link McEliecePublicKeySpec}</li>
+ * <li>for McEliecePrivateKey: {@link PKCS8EncodedKeySpec},
+ * {@link McEliecePrivateKeySpec}</li>.
+ * </ul>
+ *
+ * @param key the key
+ * @param keySpec the key specification
+ * @return the specification of the McEliece key
+ * @throws InvalidKeySpecException if the key type or the key specification is not
+ * supported.
+ * @see BCMcEliecePrivateKey
+ * @see McEliecePrivateKeySpec
+ * @see BCMcEliecePublicKey
+ * @see McEliecePublicKeySpec
+ */
+ public KeySpec getKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (key instanceof BCMcEliecePrivateKey)
+ {
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (McEliecePrivateKeySpec.class.isAssignableFrom(keySpec))
+ {
+ BCMcEliecePrivateKey privKey = (BCMcEliecePrivateKey)key;
+ return new McEliecePrivateKeySpec(OID, privKey.getN(), privKey
+ .getK(), privKey.getField(), privKey.getGoppaPoly(),
+ privKey.getSInv(), privKey.getP1(), privKey.getP2(),
+ privKey.getH(), privKey.getQInv());
+ }
+ }
+ else if (key instanceof BCMcEliecePublicKey)
+ {
+ if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ else if (McEliecePublicKeySpec.class.isAssignableFrom(keySpec))
+ {
+ BCMcEliecePublicKey pubKey = (BCMcEliecePublicKey)key;
+ return new McEliecePublicKeySpec(OID, pubKey.getN(), pubKey.getT(),
+ pubKey.getG());
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unsupported key type: "
+ + key.getClass() + ".");
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: "
+ + keySpec + ".");
+ }
+
+ /**
+ * Translates a key into a form known by the FlexiProvider. Currently, only
+ * the following "source" keys are supported: {@link BCMcEliecePrivateKey},
+ * {@link BCMcEliecePublicKey}.
+ *
+ * @param key the key
+ * @return a key of a known key type
+ * @throws InvalidKeyException if the key type is not supported.
+ */
+ public Key translateKey(Key key)
+ throws InvalidKeyException
+ {
+ if ((key instanceof BCMcEliecePrivateKey)
+ || (key instanceof BCMcEliecePublicKey))
+ {
+ return key;
+ }
+ throw new InvalidKeyException("Unsupported key type.");
+
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo pki)
+ throws InvalidKeySpecException
+ {
+ // get the inner type inside the BIT STRING
+ try
+ {
+ ASN1Primitive innerType = pki.parsePublicKey();
+ McEliecePublicKey key = McEliecePublicKey.getInstance(innerType);
+ return new BCMcEliecePublicKey(key.getOID().getId(), key.getN(), key.getT(), key.getG());
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException("Unable to decode X509EncodedKeySpec");
+ }
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo pki)
+ throws InvalidKeySpecException
+ {
+ // get the inner type inside the BIT STRING
+ try
+ {
+ ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive();
+ McEliecePrivateKey key = McEliecePrivateKey.getInstance(innerType);
+ return new BCMcEliecePrivateKey(key.getOID().getId(), key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getSInv(), key.getP1(), key.getP2(), key.getH(), key.getQInv());
+ }
+ catch (IOException cce)
+ {
+ throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec");
+ }
+ }
+
+ protected PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected KeySpec engineGetKeySpec(Key key, Class tClass)
+ throws InvalidKeySpecException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ protected Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java
new file mode 100644
index 00000000..9e0115fd
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java
@@ -0,0 +1,146 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyGenerationParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
+import org.spongycastle.pqc.crypto.mceliece.McElieceParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.ECCKeyGenParameterSpec;
+import org.spongycastle.pqc.jcajce.spec.McElieceCCA2ParameterSpec;
+
+public abstract class McElieceKeyPairGeneratorSpi
+ extends KeyPairGenerator
+{
+ public McElieceKeyPairGeneratorSpi(
+ String algorithmName)
+ {
+ super(algorithmName);
+ }
+
+ /**
+ *
+ *
+ *
+ */
+
+ public static class McElieceCCA2
+ extends McElieceKeyPairGeneratorSpi
+ {
+
+ McElieceCCA2KeyPairGenerator kpg;
+
+
+ public McElieceCCA2()
+ {
+ super("McElieceCCA-2");
+ }
+
+ public McElieceCCA2(String s)
+ {
+ super(s);
+ }
+
+ public void initialize(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException
+ {
+ kpg = new McElieceCCA2KeyPairGenerator();
+ super.initialize(params);
+ ECCKeyGenParameterSpec ecc = (ECCKeyGenParameterSpec)params;
+
+ McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters(new SecureRandom(), new McElieceCCA2Parameters(ecc.getM(), ecc.getT()));
+ kpg.init(mccca2KGParams);
+ }
+
+ public void initialize(int keySize, SecureRandom random)
+ {
+ McElieceCCA2ParameterSpec paramSpec = new McElieceCCA2ParameterSpec();
+
+ // call the initializer with the chosen parameters
+ try
+ {
+ this.initialize(paramSpec);
+ }
+ catch (InvalidAlgorithmParameterException ae)
+ {
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair();
+ McElieceCCA2PrivateKeyParameters sk = (McElieceCCA2PrivateKeyParameters)generateKeyPair.getPrivate();
+ McElieceCCA2PublicKeyParameters pk = (McElieceCCA2PublicKeyParameters)generateKeyPair.getPublic();
+
+ return new KeyPair(new BCMcElieceCCA2PublicKey(pk), new BCMcElieceCCA2PrivateKey(sk));
+
+ }
+
+ }
+
+ /**
+ *
+ *
+ *
+ */
+
+ public static class McEliece
+ extends McElieceKeyPairGeneratorSpi
+ {
+
+ McElieceKeyPairGenerator kpg;
+
+
+ public McEliece()
+ {
+ super("McEliece");
+ }
+
+ public void initialize(AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException
+ {
+ kpg = new McElieceKeyPairGenerator();
+ super.initialize(params);
+ ECCKeyGenParameterSpec ecc = (ECCKeyGenParameterSpec)params;
+
+ McElieceKeyGenerationParameters mccKGParams = new McElieceKeyGenerationParameters(new SecureRandom(), new McElieceParameters(ecc.getM(), ecc.getT()));
+ kpg.init(mccKGParams);
+ }
+
+ public void initialize(int keySize, SecureRandom random)
+ {
+ ECCKeyGenParameterSpec paramSpec = new ECCKeyGenParameterSpec();
+
+ // call the initializer with the chosen parameters
+ try
+ {
+ this.initialize(paramSpec);
+ }
+ catch (InvalidAlgorithmParameterException ae)
+ {
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair generateKeyPair = kpg.generateKeyPair();
+ McEliecePrivateKeyParameters sk = (McEliecePrivateKeyParameters)generateKeyPair.getPrivate();
+ McEliecePublicKeyParameters pk = (McEliecePublicKeyParameters)generateKeyPair.getPublic();
+
+ return new KeyPair(new BCMcEliecePublicKey(pk), new BCMcEliecePrivateKey(sk));
+ }
+
+ }
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java
new file mode 100644
index 00000000..649d1d45
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java
@@ -0,0 +1,47 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePrivateKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca McEliece objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+public class McElieceKeysToParams
+{
+
+
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCMcEliecePublicKey)
+ {
+ BCMcEliecePublicKey k = (BCMcEliecePublicKey)key;
+
+ return new McEliecePublicKeyParameters(k.getOIDString(), k.getN(), k.getT(), k.getG(), k.getMcElieceParameters());
+ }
+
+ throw new InvalidKeyException("can't identify McEliece public key: " + key.getClass().getName());
+ }
+
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCMcEliecePrivateKey)
+ {
+ BCMcEliecePrivateKey k = (BCMcEliecePrivateKey)key;
+ return new McEliecePrivateKeyParameters(k.getOIDString(), k.getN(), k.getK(), k.getField(), k.getGoppaPoly(),
+ k.getSInv(), k.getP1(), k.getP2(), k.getH(), k.getQInv(), k.getMcElieceParameters());
+ }
+
+ throw new InvalidKeyException("can't identify McEliece private key.");
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java
new file mode 100644
index 00000000..60e77a5c
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java
@@ -0,0 +1,307 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKobaraImaiCipher;
+import org.spongycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
+
+public class McElieceKobaraImaiCipherSpi
+ extends AsymmetricHybridCipher
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+
+ // TODO digest needed?
+ private Digest digest;
+ private McElieceKobaraImaiCipher cipher;
+
+ /**
+ * buffer to store the input data
+ */
+ private ByteArrayOutputStream buf = new ByteArrayOutputStream();
+
+
+ public McElieceKobaraImaiCipherSpi()
+ {
+ buf = new ByteArrayOutputStream();
+ }
+
+ protected McElieceKobaraImaiCipherSpi(Digest digest, McElieceKobaraImaiCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ buf = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation.
+ *
+ * @param input byte array containing the next part of the input
+ * @param inOff index in the array where the input starts
+ * @param inLen length of the input
+ * @return the processed byte array.
+ */
+ public byte[] update(byte[] input, int inOff, int inLen)
+ {
+ buf.write(input, inOff, inLen);
+ return new byte[0];
+ }
+
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted, depending on
+ * how this cipher was initialized.
+ *
+ * @param input the input buffer
+ * @param inOff the offset in input where the input starts
+ * @param inLen the input length
+ * @return the new buffer with the result
+ * @throws BadPaddingException if this cipher is in decryption mode, and (un)padding has
+ * been requested, but the decrypted data is not bounded by
+ * the appropriate padding bytes
+ */
+ public byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws BadPaddingException
+ {
+ update(input, inOff, inLen);
+ if (opMode == ENCRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageEncrypt(this.pad());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+ byte[] inputOfDecr = buf.toByteArray();
+ buf.reset();
+
+ try
+ {
+ return unpad(cipher.messageDecrypt(inputOfDecr));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ return null;
+ }
+
+ protected int encryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected int decryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom sr)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+
+ buf.reset();
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+
+ param = new ParametersWithRandom(param, sr);
+ digest.reset();
+ cipher.init(true, param);
+ }
+
+ protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+
+ buf.reset();
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ public String getName()
+ {
+ return "McElieceKobaraImaiCipher";
+ }
+
+ public int getKeySize(Key key)
+ throws InvalidKeyException
+ {
+ McElieceCCA2KeyParameters mcElieceCCA2KeyParameters;
+ if (key instanceof PublicKey)
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+ return cipher.getKeySize(mcElieceCCA2KeyParameters);
+ }
+ else if (key instanceof PrivateKey)
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+ return cipher.getKeySize(mcElieceCCA2KeyParameters);
+ }
+ else
+ {
+ throw new InvalidKeyException();
+ }
+
+
+ }
+
+ /**
+ * Pad and return the message stored in the message buffer.
+ *
+ * @return the padded message
+ */
+ private byte[] pad()
+ {
+ buf.write(0x01);
+ byte[] result = buf.toByteArray();
+ buf.reset();
+ return result;
+ }
+
+ /**
+ * Unpad a message.
+ *
+ * @param pmBytes the padded message
+ * @return the message
+ * @throws BadPaddingException if the padded message is invalid.
+ */
+ private byte[] unpad(byte[] pmBytes)
+ throws BadPaddingException
+ {
+ // find first non-zero byte
+ int index;
+ for (index = pmBytes.length - 1; index >= 0 && pmBytes[index] == 0; index--)
+ {
+ ;
+ }
+
+ // check if padding byte is valid
+ if (pmBytes[index] != 0x01)
+ {
+ throw new BadPaddingException("invalid ciphertext");
+ }
+
+ // extract and return message
+ byte[] mBytes = new byte[index];
+ System.arraycopy(pmBytes, 0, mBytes, 0, index);
+ return mBytes;
+ }
+
+
+ public byte[] messageEncrypt()
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageEncrypt((this.pad()));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ public byte[] messageDecrypt()
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ byte[] inputOfDecr = buf.toByteArray();
+ buf.reset();
+ try
+ {
+ output = unpad(cipher.messageDecrypt(inputOfDecr));
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ static public class McElieceKobaraImai
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai()
+ {
+ super(new SHA1Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+ static public class McElieceKobaraImai224
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai224()
+ {
+ super(new SHA224Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+ static public class McElieceKobaraImai256
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai256()
+ {
+ super(new SHA256Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+ static public class McElieceKobaraImai384
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai384()
+ {
+ super(new SHA384Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+ static public class McElieceKobaraImai512
+ extends McElieceKobaraImaiCipherSpi
+ {
+ public McElieceKobaraImai512()
+ {
+ super(new SHA512Digest(), new McElieceKobaraImaiCipher());
+ }
+ }
+
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java
new file mode 100644
index 00000000..cbabfdcc
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java
@@ -0,0 +1,171 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.mceliece.McElieceKeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePKCSCipher;
+import org.spongycastle.pqc.jcajce.provider.util.AsymmetricBlockCipher;
+
+public class McEliecePKCSCipherSpi
+ extends AsymmetricBlockCipher
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ // TODO digest needed?
+ private Digest digest;
+ private McEliecePKCSCipher cipher;
+
+ public McEliecePKCSCipherSpi(Digest digest, McEliecePKCSCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ }
+
+ protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom sr)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+
+ CipherParameters param;
+ param = McElieceKeysToParams.generatePublicKeyParameter((PublicKey)key);
+
+ param = new ParametersWithRandom(param, sr);
+ digest.reset();
+ cipher.init(true, param);
+ this.maxPlainTextSize = cipher.maxPlainTextSize;
+ this.cipherTextSize = cipher.cipherTextSize;
+ }
+
+ protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+ param = McElieceKeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ digest.reset();
+ cipher.init(false, param);
+ this.maxPlainTextSize = cipher.maxPlainTextSize;
+ this.cipherTextSize = cipher.cipherTextSize;
+ }
+
+ protected byte[] messageEncrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageEncrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+ protected byte[] messageDecrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageDecrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+ public String getName()
+ {
+ return "McEliecePKCS";
+ }
+
+ public int getKeySize(Key key)
+ throws InvalidKeyException
+ {
+ McElieceKeyParameters mcElieceKeyParameters;
+ if (key instanceof PublicKey)
+ {
+ mcElieceKeyParameters = (McElieceKeyParameters)McElieceKeysToParams.generatePublicKeyParameter((PublicKey)key);
+ }
+ else
+ {
+ mcElieceKeyParameters = (McElieceKeyParameters)McElieceKeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ }
+
+
+ return cipher.getKeySize(mcElieceKeyParameters);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////
+
+ static public class McEliecePKCS
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS()
+ {
+ super(new SHA1Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+ static public class McEliecePKCS224
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS224()
+ {
+ super(new SHA224Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+ static public class McEliecePKCS256
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS256()
+ {
+ super(new SHA256Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+ static public class McEliecePKCS384
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS384()
+ {
+ super(new SHA384Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+ static public class McEliecePKCS512
+ extends McEliecePKCSCipherSpi
+ {
+ public McEliecePKCS512()
+ {
+ super(new SHA512Digest(), new McEliecePKCSCipher());
+ }
+ }
+
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java
new file mode 100644
index 00000000..314b7a30
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java
@@ -0,0 +1,247 @@
+package org.spongycastle.pqc.jcajce.provider.mceliece;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2KeyParameters;
+import org.spongycastle.pqc.crypto.mceliece.McEliecePointchevalCipher;
+import org.spongycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher;
+
+public class McEliecePointchevalCipherSpi
+ extends AsymmetricHybridCipher
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ // TODO digest needed?
+ private Digest digest;
+ private McEliecePointchevalCipher cipher;
+
+ /**
+ * buffer to store the input data
+ */
+ private ByteArrayOutputStream buf = new ByteArrayOutputStream();
+
+
+ protected McEliecePointchevalCipherSpi(Digest digest, McEliecePointchevalCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ buf = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation.
+ *
+ * @param input byte array containing the next part of the input
+ * @param inOff index in the array where the input starts
+ * @param inLen length of the input
+ * @return the processed byte array.
+ */
+ public byte[] update(byte[] input, int inOff, int inLen)
+ {
+ buf.write(input, inOff, inLen);
+ return new byte[0];
+ }
+
+
+ /**
+ * Encrypts or decrypts data in a single-part operation, or finishes a
+ * multiple-part operation. The data is encrypted or decrypted, depending on
+ * how this cipher was initialized.
+ *
+ * @param input the input buffer
+ * @param inOff the offset in input where the input starts
+ * @param inLen the input length
+ * @return the new buffer with the result
+ * @throws BadPaddingException on deryption errors.
+ */
+ public byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws BadPaddingException
+ {
+ update(input, inOff, inLen);
+ byte[] data = buf.toByteArray();
+ buf.reset();
+ if (opMode == ENCRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageEncrypt(data);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+
+ try
+ {
+ return cipher.messageDecrypt(data);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+ return null;
+ }
+
+ protected int encryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected int decryptOutputSize(int inLen)
+ {
+ return 0;
+ }
+
+ protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom sr)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+
+ param = new ParametersWithRandom(param, sr);
+ digest.reset();
+ cipher.init(true, param);
+ }
+
+ protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+ param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ public String getName()
+ {
+ return "McEliecePointchevalCipher";
+ }
+
+
+ public int getKeySize(Key key)
+ throws InvalidKeyException
+ {
+ McElieceCCA2KeyParameters mcElieceCCA2KeyParameters;
+ if (key instanceof PublicKey)
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key);
+ }
+ else
+ {
+ mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key);
+ }
+
+ return cipher.getKeySize(mcElieceCCA2KeyParameters);
+ }
+
+ public byte[] messageEncrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageEncrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ public byte[] messageDecrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException
+ {
+ byte[] output = null;
+ try
+ {
+ output = cipher.messageDecrypt(input);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ return output;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////77
+
+ static public class McEliecePointcheval
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval()
+ {
+ super(new SHA1Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+ static public class McEliecePointcheval224
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval224()
+ {
+ super(new SHA224Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+ static public class McEliecePointcheval256
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval256()
+ {
+ super(new SHA256Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+ static public class McEliecePointcheval384
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval384()
+ {
+ super(new SHA384Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+ static public class McEliecePointcheval512
+ extends McEliecePointchevalCipherSpi
+ {
+ public McEliecePointcheval512()
+ {
+ super(new SHA512Digest(), new McEliecePointchevalCipher());
+ }
+ }
+
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java
new file mode 100644
index 00000000..114d2009
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java
@@ -0,0 +1,243 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.util.Arrays;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.spongycastle.pqc.asn1.RainbowPrivateKey;
+import org.spongycastle.pqc.crypto.rainbow.Layer;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters;
+import org.spongycastle.pqc.crypto.rainbow.util.RainbowUtil;
+import org.spongycastle.pqc.jcajce.spec.RainbowPrivateKeySpec;
+
+/**
+ * The Private key in Rainbow consists of the linear affine maps L1, L2 and the
+ * map F, consisting of quadratic polynomials. In this implementation, we
+ * denote: L1 = A1*x + b1 L2 = A2*x + b2
+ * <p/>
+ * The coefficients of the polynomials in F are stored in 3-dimensional arrays
+ * per layer. The indices of these arrays denote the polynomial, and the
+ * variables.
+ * <p/>
+ * More detailed information about the private key is to be found in the paper
+ * of Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable Polynomial
+ * Signature Scheme. ACNS 2005: 164-175 (http://dx.doi.org/10.1007/11496137_12)
+ */
+public class BCRainbowPrivateKey
+ implements PrivateKey
+{
+ private static final long serialVersionUID = 1L;
+
+ // the inverse of L1
+ private short[][] A1inv;
+
+ // translation vector element of L1
+ private short[] b1;
+
+ // the inverse of L2
+ private short[][] A2inv;
+
+ // translation vector of L2
+ private short[] b2;
+
+ /*
+ * components of F
+ */
+ private Layer[] layers;
+
+ // set of vinegar vars per layer.
+ private int[] vi;
+
+
+ /**
+ * Constructor.
+ *
+ * @param A1inv
+ * @param b1
+ * @param A2inv
+ * @param b2
+ * @param layers
+ */
+ public BCRainbowPrivateKey(short[][] A1inv, short[] b1, short[][] A2inv,
+ short[] b2, int[] vi, Layer[] layers)
+ {
+ this.A1inv = A1inv;
+ this.b1 = b1;
+ this.A2inv = A2inv;
+ this.b2 = b2;
+ this.vi = vi;
+ this.layers = layers;
+ }
+
+ /**
+ * Constructor (used by the {@link RainbowKeyFactorySpi}).
+ *
+ * @param keySpec a {@link RainbowPrivateKeySpec}
+ */
+ public BCRainbowPrivateKey(RainbowPrivateKeySpec keySpec)
+ {
+ this(keySpec.getInvA1(), keySpec.getB1(), keySpec.getInvA2(), keySpec
+ .getB2(), keySpec.getVi(), keySpec.getLayers());
+ }
+
+ public BCRainbowPrivateKey(
+ RainbowPrivateKeyParameters params)
+ {
+ this(params.getInvA1(), params.getB1(), params.getInvA2(), params.getB2(), params.getVi(), params.getLayers());
+ }
+
+ /**
+ * Getter for the inverse matrix of A1.
+ *
+ * @return the A1inv inverse
+ */
+ public short[][] getInvA1()
+ {
+ return this.A1inv;
+ }
+
+ /**
+ * Getter for the translation part of the private quadratic map L1.
+ *
+ * @return b1 the translation part of L1
+ */
+ public short[] getB1()
+ {
+ return this.b1;
+ }
+
+ /**
+ * Getter for the translation part of the private quadratic map L2.
+ *
+ * @return b2 the translation part of L2
+ */
+ public short[] getB2()
+ {
+ return this.b2;
+ }
+
+ /**
+ * Getter for the inverse matrix of A2
+ *
+ * @return the A2inv
+ */
+ public short[][] getInvA2()
+ {
+ return this.A2inv;
+ }
+
+ /**
+ * Returns the layers contained in the private key
+ *
+ * @return layers
+ */
+ public Layer[] getLayers()
+ {
+ return this.layers;
+ }
+
+ /**
+ * Returns the array of vi-s
+ *
+ * @return the vi
+ */
+ public int[] getVi()
+ {
+ return vi;
+ }
+
+ /**
+ * Compare this Rainbow private key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof BCRainbowPrivateKey))
+ {
+ return false;
+ }
+ BCRainbowPrivateKey otherKey = (BCRainbowPrivateKey)other;
+
+ boolean eq = true;
+ // compare using shortcut rule ( && instead of &)
+ eq = eq && RainbowUtil.equals(A1inv, otherKey.getInvA1());
+ eq = eq && RainbowUtil.equals(A2inv, otherKey.getInvA2());
+ eq = eq && RainbowUtil.equals(b1, otherKey.getB1());
+ eq = eq && RainbowUtil.equals(b2, otherKey.getB2());
+ eq = eq && Arrays.equals(vi, otherKey.getVi());
+ if (layers.length != otherKey.getLayers().length)
+ {
+ return false;
+ }
+ for (int i = layers.length - 1; i >= 0; i--)
+ {
+ eq &= layers[i].equals(otherKey.getLayers()[i]);
+ }
+ return eq;
+ }
+
+ public int hashCode()
+ {
+ int hash = layers.length;
+
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(A1inv);
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(b1);
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(A2inv);
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(b2);
+ hash = hash * 37 + org.spongycastle.util.Arrays.hashCode(vi);
+
+ for (int i = layers.length - 1; i >= 0; i--)
+ {
+ hash = hash * 37 + layers[i].hashCode();
+ }
+
+
+ return hash;
+ }
+
+ /**
+ * @return name of the algorithm - "Rainbow"
+ */
+ public final String getAlgorithm()
+ {
+ return "Rainbow";
+ }
+
+ public byte[] getEncoded()
+ {
+ RainbowPrivateKey privateKey = new RainbowPrivateKey(A1inv, b1, A2inv, b2, vi, layers);
+
+ PrivateKeyInfo pki;
+ try
+ {
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.rainbow, DERNull.INSTANCE);
+ pki = new PrivateKeyInfo(algorithmIdentifier, privateKey);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ try
+ {
+ byte[] encoded = pki.getEncoded();
+ return encoded;
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java
new file mode 100644
index 00000000..12f16ed9
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java
@@ -0,0 +1,170 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.security.PublicKey;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.pqc.asn1.PQCObjectIdentifiers;
+import org.spongycastle.pqc.asn1.RainbowPublicKey;
+import org.spongycastle.pqc.crypto.rainbow.RainbowParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters;
+import org.spongycastle.pqc.crypto.rainbow.util.RainbowUtil;
+import org.spongycastle.pqc.jcajce.provider.util.KeyUtil;
+import org.spongycastle.pqc.jcajce.spec.RainbowPublicKeySpec;
+import org.spongycastle.util.Arrays;
+
+/**
+ * This class implements CipherParameters and PublicKey.
+ * <p/>
+ * The public key in Rainbow consists of n - v1 polynomial components of the
+ * private key's F and the field structure of the finite field k.
+ * <p/>
+ * The quadratic (or mixed) coefficients of the polynomials from the public key
+ * are stored in the 2-dimensional array in lexicographical order, requiring n *
+ * (n + 1) / 2 entries for each polynomial. The singular terms are stored in a
+ * 2-dimensional array requiring n entries per polynomial, the scalar term of
+ * each polynomial is stored in a 1-dimensional array.
+ * <p/>
+ * More detailed information on the public key is to be found in the paper of
+ * Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable Polynomial
+ * Signature Scheme. ACNS 2005: 164-175 (http://dx.doi.org/10.1007/11496137_12)
+ */
+public class BCRainbowPublicKey
+ implements PublicKey
+{
+ private static final long serialVersionUID = 1L;
+
+ private short[][] coeffquadratic;
+ private short[][] coeffsingular;
+ private short[] coeffscalar;
+ private int docLength; // length of possible document to sign
+
+ private RainbowParameters rainbowParams;
+
+ /**
+ * Constructor
+ *
+ * @param docLength
+ * @param coeffQuadratic
+ * @param coeffSingular
+ * @param coeffScalar
+ */
+ public BCRainbowPublicKey(int docLength,
+ short[][] coeffQuadratic, short[][] coeffSingular,
+ short[] coeffScalar)
+ {
+ this.docLength = docLength;
+ this.coeffquadratic = coeffQuadratic;
+ this.coeffsingular = coeffSingular;
+ this.coeffscalar = coeffScalar;
+ }
+
+ /**
+ * Constructor (used by the {@link RainbowKeyFactorySpi}).
+ *
+ * @param keySpec a {@link RainbowPublicKeySpec}
+ */
+ public BCRainbowPublicKey(RainbowPublicKeySpec keySpec)
+ {
+ this(keySpec.getDocLength(), keySpec.getCoeffQuadratic(), keySpec
+ .getCoeffSingular(), keySpec.getCoeffScalar());
+ }
+
+ public BCRainbowPublicKey(
+ RainbowPublicKeyParameters params)
+ {
+ this(params.getDocLength(), params.getCoeffQuadratic(), params.getCoeffSingular(), params.getCoeffScalar());
+ }
+
+ /**
+ * @return the docLength
+ */
+ public int getDocLength()
+ {
+ return this.docLength;
+ }
+
+ /**
+ * @return the coeffQuadratic
+ */
+ public short[][] getCoeffQuadratic()
+ {
+ return coeffquadratic;
+ }
+
+ /**
+ * @return the coeffSingular
+ */
+ public short[][] getCoeffSingular()
+ {
+ short[][] copy = new short[coeffsingular.length][];
+
+ for (int i = 0; i != coeffsingular.length; i++)
+ {
+ copy[i] = Arrays.clone(coeffsingular[i]);
+ }
+
+ return copy;
+ }
+
+
+ /**
+ * @return the coeffScalar
+ */
+ public short[] getCoeffScalar()
+ {
+ return Arrays.clone(coeffscalar);
+ }
+
+ /**
+ * Compare this Rainbow public key with another object.
+ *
+ * @param other the other object
+ * @return the result of the comparison
+ */
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof BCRainbowPublicKey))
+ {
+ return false;
+ }
+ BCRainbowPublicKey otherKey = (BCRainbowPublicKey)other;
+
+ return docLength == otherKey.getDocLength()
+ && RainbowUtil.equals(coeffquadratic, otherKey.getCoeffQuadratic())
+ && RainbowUtil.equals(coeffsingular, otherKey.getCoeffSingular())
+ && RainbowUtil.equals(coeffscalar, otherKey.getCoeffScalar());
+ }
+
+ public int hashCode()
+ {
+ int hash = docLength;
+
+ hash = hash * 37 + Arrays.hashCode(coeffquadratic);
+ hash = hash * 37 + Arrays.hashCode(coeffsingular);
+ hash = hash * 37 + Arrays.hashCode(coeffscalar);
+
+ return hash;
+ }
+
+ /**
+ * @return name of the algorithm - "Rainbow"
+ */
+ public final String getAlgorithm()
+ {
+ return "Rainbow";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ RainbowPublicKey key = new RainbowPublicKey(docLength, coeffquadratic, coeffsingular, coeffscalar);
+ AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.rainbow, DERNull.INSTANCE);
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(algorithmIdentifier, key);
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java
new file mode 100644
index 00000000..614e0796
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java
@@ -0,0 +1,236 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.spongycastle.pqc.asn1.RainbowPrivateKey;
+import org.spongycastle.pqc.asn1.RainbowPublicKey;
+import org.spongycastle.pqc.jcajce.spec.RainbowPrivateKeySpec;
+import org.spongycastle.pqc.jcajce.spec.RainbowPublicKeySpec;
+
+
+/**
+ * This class transforms Rainbow keys and Rainbow key specifications.
+ *
+ * @see BCRainbowPublicKey
+ * @see RainbowPublicKeySpec
+ * @see BCRainbowPrivateKey
+ * @see RainbowPrivateKeySpec
+ */
+public class RainbowKeyFactorySpi
+ extends KeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCRainbowPrivateKey}. Currently, the following key specifications
+ * are supported: {@link RainbowPrivateKeySpec}, {@link PKCS8EncodedKeySpec}.
+ * <p/>
+ * <p/>
+ * <p/>
+ * The ASN.1 definition of the key structure is
+ * <p/>
+ * <pre>
+ * RainbowPrivateKey ::= SEQUENCE {
+ * oid OBJECT IDENTIFIER -- OID identifying the algorithm
+ * A1inv SEQUENCE OF OCTET STRING -- inversed matrix of L1
+ * b1 OCTET STRING -- translation vector of L1
+ * A2inv SEQUENCE OF OCTET STRING -- inversed matrix of L2
+ * b2 OCTET STRING -- translation vector of L2
+ * vi OCTET STRING -- num of elmts in each Set S
+ * layers SEQUENCE OF Layer -- layers of F
+ * }
+ *
+ * Layer ::= SEQUENCE OF Poly
+ * Poly ::= SEQUENCE {
+ * alpha SEQUENCE OF OCTET STRING
+ * beta SEQUENCE OF OCTET STRING
+ * gamma OCTET STRING
+ * eta OCTET
+ * }
+ * </pre>
+ * <p/>
+ * <p/>
+ *
+ * @param keySpec the key specification
+ * @return the Rainbow private key
+ * @throws InvalidKeySpecException if the KeySpec is not supported.
+ */
+ public PrivateKey engineGeneratePrivate(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof RainbowPrivateKeySpec)
+ {
+ return new BCRainbowPrivateKey((RainbowPrivateKeySpec)keySpec);
+ }
+ else if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to PKCS#8 from the spec
+ byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
+
+ try
+ {
+ return generatePrivate(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unsupported key specification: "
+ + keySpec.getClass() + ".");
+ }
+
+ /**
+ * Converts, if possible, a key specification into a
+ * {@link BCRainbowPublicKey}. Currently, the following key specifications are
+ * supported:{@link X509EncodedKeySpec}.
+ * <p/>
+ * <p/>
+ * <p/>
+ * The ASN.1 definition of a public key's structure is
+ * <p/>
+ * <pre>
+ * RainbowPublicKey ::= SEQUENCE {
+ * oid OBJECT IDENTIFIER -- OID identifying the algorithm
+ * docLength Integer -- length of signable msg
+ * coeffquadratic SEQUENCE OF OCTET STRING -- quadratic (mixed) coefficients
+ * coeffsingular SEQUENCE OF OCTET STRING -- singular coefficients
+ * coeffscalar OCTET STRING -- scalar coefficients
+ * }
+ * </pre>
+ * <p/>
+ * <p/>
+ *
+ * @param keySpec the key specification
+ * @return the Rainbow public key
+ * @throws InvalidKeySpecException if the KeySpec is not supported.
+ */
+ public PublicKey engineGeneratePublic(KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof RainbowPublicKeySpec)
+ {
+ return new BCRainbowPublicKey((RainbowPublicKeySpec)keySpec);
+ }
+ else if (keySpec instanceof X509EncodedKeySpec)
+ {
+ // get the DER-encoded Key according to X.509 from the spec
+ byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded();
+
+ // decode the SubjectPublicKeyInfo data structure to the pki object
+ try
+ {
+ return generatePublic(SubjectPublicKeyInfo.getInstance(encKey));
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: " + keySpec + ".");
+ }
+
+ /**
+ * Converts a given key into a key specification, if possible. Currently the
+ * following specs are supported:
+ * <ul>
+ * <li>for RainbowPublicKey: X509EncodedKeySpec, RainbowPublicKeySpec
+ * <li>for RainbowPrivateKey: PKCS8EncodedKeySpec, RainbowPrivateKeySpec
+ * </ul>
+ *
+ * @param key the key
+ * @param keySpec the key specification
+ * @return the specification of the CMSS key
+ * @throws InvalidKeySpecException if the key type or key specification is not supported.
+ */
+ public final KeySpec engineGetKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (key instanceof BCRainbowPrivateKey)
+ {
+ if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (RainbowPrivateKeySpec.class.isAssignableFrom(keySpec))
+ {
+ BCRainbowPrivateKey privKey = (BCRainbowPrivateKey)key;
+ return new RainbowPrivateKeySpec(privKey.getInvA1(), privKey
+ .getB1(), privKey.getInvA2(), privKey.getB2(), privKey
+ .getVi(), privKey.getLayers());
+ }
+ }
+ else if (key instanceof BCRainbowPublicKey)
+ {
+ if (X509EncodedKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+ else if (RainbowPublicKeySpec.class.isAssignableFrom(keySpec))
+ {
+ BCRainbowPublicKey pubKey = (BCRainbowPublicKey)key;
+ return new RainbowPublicKeySpec(pubKey.getDocLength(), pubKey
+ .getCoeffQuadratic(), pubKey.getCoeffSingular(), pubKey
+ .getCoeffScalar());
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("Unsupported key type: "
+ + key.getClass() + ".");
+ }
+
+ throw new InvalidKeySpecException("Unknown key specification: "
+ + keySpec + ".");
+ }
+
+ /**
+ * Translates a key into a form known by the FlexiProvider. Currently the
+ * following key types are supported: RainbowPrivateKey, RainbowPublicKey.
+ *
+ * @param key the key
+ * @return a key of a known key type
+ * @throws InvalidKeyException if the key is not supported.
+ */
+ public final Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCRainbowPrivateKey || key instanceof BCRainbowPublicKey)
+ {
+ return key;
+ }
+
+ throw new InvalidKeyException("Unsupported key type");
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ RainbowPrivateKey pKey = RainbowPrivateKey.getInstance(keyInfo.parsePrivateKey());
+
+ return new BCRainbowPrivateKey(pKey.getInvA1(), pKey.getB1(), pKey.getInvA2(), pKey.getB2(), pKey.getVi(), pKey.getLayers());
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ RainbowPublicKey pKey = RainbowPublicKey.getInstance(keyInfo.parsePublicKey());
+
+ return new BCRainbowPublicKey(pKey.getDocLength(), pKey.getCoeffQuadratic(), pKey.getCoeffSingular(), pKey.getCoeffScalar());
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java
new file mode 100644
index 00000000..82239575
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java
@@ -0,0 +1,72 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.pqc.crypto.rainbow.RainbowKeyGenerationParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowKeyPairGenerator;
+import org.spongycastle.pqc.crypto.rainbow.RainbowParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters;
+import org.spongycastle.pqc.jcajce.spec.RainbowParameterSpec;
+
+public class RainbowKeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ RainbowKeyGenerationParameters param;
+ RainbowKeyPairGenerator engine = new RainbowKeyPairGenerator();
+ int strength = 1024;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+
+ public RainbowKeyPairGeneratorSpi()
+ {
+ super("Rainbow");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof RainbowParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a RainbowParameterSpec");
+ }
+ RainbowParameterSpec rainbowParams = (RainbowParameterSpec)params;
+
+ param = new RainbowKeyGenerationParameters(random, new RainbowParameters(rainbowParams.getVi()));
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ param = new RainbowKeyGenerationParameters(random, new RainbowParameters(new RainbowParameterSpec().getVi()));
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ RainbowPublicKeyParameters pub = (RainbowPublicKeyParameters)pair.getPublic();
+ RainbowPrivateKeyParameters priv = (RainbowPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCRainbowPublicKey(pub),
+ new BCRainbowPrivateKey(priv));
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeysToParams.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeysToParams.java
new file mode 100644
index 00000000..0ae006ef
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/RainbowKeysToParams.java
@@ -0,0 +1,49 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters;
+import org.spongycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters;
+
+
+/**
+ * utility class for converting jce/jca Rainbow objects
+ * objects into their org.spongycastle.crypto counterparts.
+ */
+
+public class RainbowKeysToParams
+{
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCRainbowPublicKey)
+ {
+ BCRainbowPublicKey k = (BCRainbowPublicKey)key;
+
+ return new RainbowPublicKeyParameters(k.getDocLength(), k.getCoeffQuadratic(),
+ k.getCoeffSingular(), k.getCoeffScalar());
+ }
+
+ throw new InvalidKeyException("can't identify Rainbow public key: " + key.getClass().getName());
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof BCRainbowPrivateKey)
+ {
+ BCRainbowPrivateKey k = (BCRainbowPrivateKey)key;
+ return new RainbowPrivateKeyParameters(k.getInvA1(), k.getB1(),
+ k.getInvA2(), k.getB2(), k.getVi(), k.getLayers());
+ }
+
+ throw new InvalidKeyException("can't identify Rainbow private key.");
+ }
+}
+
+
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java
new file mode 100644
index 00000000..01b12699
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java
@@ -0,0 +1,164 @@
+package org.spongycastle.pqc.jcajce.provider.rainbow;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.SHA224Digest;
+import org.spongycastle.crypto.digests.SHA256Digest;
+import org.spongycastle.crypto.digests.SHA384Digest;
+import org.spongycastle.crypto.digests.SHA512Digest;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.pqc.crypto.rainbow.RainbowSigner;
+
+/**
+ * Rainbow Signature class, extending the jce SignatureSpi.
+ */
+public class SignatureSpi
+ extends java.security.SignatureSpi
+{
+ private Digest digest;
+ private RainbowSigner signer;
+ private SecureRandom random;
+
+ protected SignatureSpi(Digest digest, RainbowSigner signer)
+ {
+ this.digest = digest;
+ this.signer = signer;
+ }
+
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+ param = RainbowKeysToParams.generatePublicKeyParameter(publicKey);
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
+ throws InvalidKeyException
+ {
+ this.random = random;
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+ param = RainbowKeysToParams.generatePrivateKeyParameter(privateKey);
+
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ digest.reset();
+ signer.init(true, param);
+
+ }
+
+ protected void engineUpdate(byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+ try
+ {
+ byte[] sig = signer.generateSignature(hash);
+
+ return sig;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+ return signer.verifySignature(hash, sigBytes);
+ }
+
+ protected void engineSetParameter(AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href =
+ * "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)"
+ * >
+ */
+ protected void engineSetParameter(String param, Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+
+ static public class withSha224
+ extends SignatureSpi
+ {
+ public withSha224()
+ {
+ super(new SHA224Digest(), new RainbowSigner());
+ }
+ }
+
+ static public class withSha256
+ extends SignatureSpi
+ {
+ public withSha256()
+ {
+ super(new SHA256Digest(), new RainbowSigner());
+ }
+ }
+
+ static public class withSha384
+ extends SignatureSpi
+ {
+ public withSha384()
+ {
+ super(new SHA384Digest(), new RainbowSigner());
+ }
+ }
+
+ static public class withSha512
+ extends SignatureSpi
+ {
+ public withSha512()
+ {
+ super(new SHA512Digest(), new RainbowSigner());
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java
new file mode 100644
index 00000000..2e5678ad
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java
@@ -0,0 +1,522 @@
+package org.spongycastle.pqc.jcajce.provider.util;
+
+import java.io.ByteArrayOutputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+
+
+/**
+ * The AsymmetricBlockCipher class extends CipherSpiExt.
+ * NOTE: Some Ciphers are using Padding. OneAndZeroesPadding is used as default
+ * padding. However padding can still be specified, but mode is not supported;
+ * if you try to instantiate the cipher with something else than "NONE" as mode
+ * NoSuchAlgorithmException is thrown.
+ */
+public abstract class AsymmetricBlockCipher
+ extends CipherSpiExt
+{
+
+ /**
+ * ParameterSpec used with this cipher
+ */
+ protected AlgorithmParameterSpec paramSpec;
+
+ /**
+ * Internal buffer
+ */
+ protected ByteArrayOutputStream buf;
+
+ /**
+ * The maximum number of bytes the cipher can decrypt.
+ */
+ protected int maxPlainTextSize;
+
+ /**
+ * The maximum number of bytes the cipher can encrypt.
+ */
+ protected int cipherTextSize;
+
+ /**
+ * The AsymmetricBlockCipher() constructor
+ */
+ public AsymmetricBlockCipher()
+ {
+ buf = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Return the block size (in bytes). Note: although the ciphers extending
+ * this class are not block ciphers, the method was adopted to return the
+ * maximal plaintext and ciphertext sizes for non hybrid ciphers. If the
+ * cipher is hybrid, it returns 0.
+ *
+ * @return if the cipher is not a hybrid one the max plain/cipher text size
+ * is returned, otherwise 0 is returned
+ */
+ public final int getBlockSize()
+ {
+ return opMode == ENCRYPT_MODE ? maxPlainTextSize : cipherTextSize;
+ }
+
+ /**
+ * @return <tt>null</tt> since no initialization vector is used.
+ */
+ public final byte[] getIV()
+ {
+ return null;
+ }
+
+ /**
+ * Return the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next update or doFinal operation, given
+ * the input length <tt>inLen</tt> (in bytes). This call takes into
+ * account any unprocessed (buffered) data from a previous update call, and
+ * padding. The actual output length of the next update() or doFinal() call
+ * may be smaller than the length returned by this method.
+ * <p/>
+ * If the input length plus the length of the buffered data exceeds the
+ * maximum length, <tt>0</tt> is returned.
+ *
+ * @param inLen the length of the input
+ * @return the length of the ciphertext or <tt>0</tt> if the input is too
+ * long.
+ */
+ public final int getOutputSize(int inLen)
+ {
+
+ int totalLen = inLen + buf.size();
+
+ int maxLen = getBlockSize();
+
+ if (totalLen > maxLen)
+ {
+ // the length of the input exceeds the maximal supported length
+ return 0;
+ }
+
+ return maxLen;
+ }
+
+ /**
+ * <p/>
+ * Returns the parameters used with this cipher.
+ * <p/>
+ * The returned parameters may be the same that were used to initialize this
+ * cipher, or may contain the default set of parameters or a set of randomly
+ * generated parameters used by the underlying cipher implementation
+ * (provided that the underlying cipher implementation uses a default set of
+ * parameters or creates new parameters if it needs parameters but was not
+ * initialized with any).
+ * <p/>
+ *
+ * @return the parameters used with this cipher, or null if this cipher does
+ * not use any parameters.
+ */
+ public final AlgorithmParameterSpec getParameters()
+ {
+ return paramSpec;
+ }
+
+ /**
+ * Initializes the cipher for encryption by forwarding it to
+ * initEncrypt(Key, FlexiSecureRandom).
+ * <p/>
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * @param key the encryption or decryption key.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ */
+ public final void initEncrypt(Key key)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initEncrypt(key, null, new SecureRandom());
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initialize this cipher for encryption by forwarding it to
+ * initEncrypt(Key, FlexiSecureRandom, AlgorithmParameterSpec).
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * @param key the encryption or decryption key.
+ * @param random the source of randomness.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ */
+ public final void initEncrypt(Key key, SecureRandom random)
+ throws InvalidKeyException
+ {
+
+ try
+ {
+ initEncrypt(key, null, random);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initializes the cipher for encryption by forwarding it to
+ * initEncrypt(Key, FlexiSecureRandom, AlgorithmParameterSpec).
+ *
+ * @param key the encryption or decryption key.
+ * @param params the algorithm parameters.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidAlgorithmParameterException if the given algortihm parameters are inappropriate for
+ * this cipher, or if this cipher is being initialized for
+ * decryption and requires algorithm parameters and params
+ * is null.
+ */
+ public final void initEncrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initEncrypt(key, params, new SecureRandom());
+ }
+
+ /**
+ * This method initializes the AsymmetricBlockCipher with a certain key for
+ * data encryption.
+ * <p/>
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ * <p/>
+ * Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it
+ * <p/>
+ *
+ * @param key the key which has to be used to encrypt data.
+ * @param secureRandom the source of randomness.
+ * @param params the algorithm parameters.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is being initialized for
+ * decryption and requires algorithm parameters and params
+ * is null.
+ */
+ public final void initEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom secureRandom)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+ opMode = ENCRYPT_MODE;
+ initCipherEncrypt(key, params, secureRandom);
+ }
+
+ /**
+ * Initialize the cipher for decryption by forwarding it to
+ * {@link #initDecrypt(Key, AlgorithmParameterSpec)}.
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using engineGetParameters or
+ * engineGetIV (if the parameter is an IV).
+ *
+ * @param key the encryption or decryption key.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ */
+ public final void initDecrypt(Key key)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initDecrypt(key, null);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * This method initializes the AsymmetricBlockCipher with a certain key for
+ * data decryption.
+ * <p/>
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ * <p/>
+ * Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it
+ * <p/>
+ *
+ * @param key the key which has to be used to decrypt data.
+ * @param params the algorithm parameters.
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is being initialized for
+ * decryption and requires algorithm parameters and params
+ * is null.
+ */
+ public final void initDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ opMode = DECRYPT_MODE;
+ initCipherDecrypt(key, params);
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation. This method
+ * just writes the input into an internal buffer.
+ *
+ * @param input byte array containing the next part of the input
+ * @param inOff index in the array where the input starts
+ * @param inLen length of the input
+ * @return a new buffer with the result (always empty)
+ */
+ public final byte[] update(byte[] input, int inOff, int inLen)
+ {
+ if (inLen != 0)
+ {
+ buf.write(input, inOff, inLen);
+ }
+ return new byte[0];
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the output buffer
+ * @param outOff the offset where the result is stored
+ * @return the length of the output (always 0)
+ */
+ public final int update(byte[] input, int inOff, int inLen, byte[] output,
+ int outOff)
+ {
+ update(input, inOff, inLen);
+ return 0;
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result
+ * @throws IllegalBlockSizeException if the plaintext or ciphertext size is too large.
+ * @throws BadPaddingException if the ciphertext is invalid.
+ */
+ public final byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+
+ checkLength(inLen);
+ update(input, inOff, inLen);
+ byte[] mBytes = buf.toByteArray();
+ buf.reset();
+
+ switch (opMode)
+ {
+ case ENCRYPT_MODE:
+ return messageEncrypt(mBytes);
+
+ case DECRYPT_MODE:
+ return messageDecrypt(mBytes);
+
+ default:
+ return null;
+
+ }
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the buffer for the result
+ * @param outOff the offset where the result is stored
+ * @return the output length
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ * @throws IllegalBlockSizeException if the plaintext or ciphertext size is too large.
+ * @throws BadPaddingException if the ciphertext is invalid.
+ */
+ public final int doFinal(byte[] input, int inOff, int inLen, byte[] output,
+ int outOff)
+ throws ShortBufferException, IllegalBlockSizeException,
+ BadPaddingException
+ {
+
+ if (output.length < getOutputSize(inLen))
+ {
+ throw new ShortBufferException("Output buffer too short.");
+ }
+
+ byte[] out = doFinal(input, inOff, inLen);
+ System.arraycopy(out, 0, output, outOff, out.length);
+ return out.length;
+ }
+
+ /**
+ * Since asymmetric block ciphers do not support modes, this method does
+ * nothing.
+ *
+ * @param modeName the cipher mode (unused)
+ */
+ protected final void setMode(String modeName)
+ {
+ // empty
+ }
+
+ /**
+ * Since asymmetric block ciphers do not support padding, this method does
+ * nothing.
+ *
+ * @param paddingName the name of the padding scheme (not used)
+ */
+ protected final void setPadding(String paddingName)
+ {
+ // empty
+ }
+
+ /**
+ * Check if the message length plus the length of the input length can be
+ * en/decrypted. This method uses the specific values
+ * {@link #maxPlainTextSize} and {@link #cipherTextSize} which are set by
+ * the implementations. If the input length plus the length of the internal
+ * buffer is greater than {@link #maxPlainTextSize} for encryption or not
+ * equal to {@link #cipherTextSize} for decryption, an
+ * {@link IllegalBlockSizeException} will be thrown.
+ *
+ * @param inLen length of the input to check
+ * @throws IllegalBlockSizeException if the input length is invalid.
+ */
+ protected void checkLength(int inLen)
+ throws IllegalBlockSizeException
+ {
+
+ int inLength = inLen + buf.size();
+
+ if (opMode == ENCRYPT_MODE)
+ {
+ if (inLength > maxPlainTextSize)
+ {
+ throw new IllegalBlockSizeException(
+ "The length of the plaintext (" + inLength
+ + " bytes) is not supported by "
+ + "the cipher (max. " + maxPlainTextSize
+ + " bytes).");
+ }
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+ if (inLength != cipherTextSize)
+ {
+ throw new IllegalBlockSizeException(
+ "Illegal ciphertext length (expected " + cipherTextSize
+ + " bytes, was " + inLength + " bytes).");
+ }
+ }
+
+ }
+
+ /**
+ * Initialize the AsymmetricBlockCipher with a certain key for data
+ * encryption.
+ *
+ * @param key the key which has to be used to encrypt data
+ * @param params the algorithm parameters
+ * @param sr the source of randomness
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for
+ * initializing this cipher.
+ */
+ protected abstract void initCipherEncrypt(Key key,
+ AlgorithmParameterSpec params, SecureRandom sr)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Initialize the AsymmetricBlockCipher with a certain key for data
+ * encryption.
+ *
+ * @param key the key which has to be used to decrypt data
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for
+ * initializing this cipher.
+ */
+ protected abstract void initCipherDecrypt(Key key,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException;
+
+ /**
+ * Encrypt the message stored in input. The method should also perform an
+ * additional length check.
+ *
+ * @param input the message to be encrypted (usually the message length is
+ * less than or equal to maxPlainTextSize)
+ * @return the encrypted message (it has length equal to maxCipherTextSize_)
+ * @throws IllegalBlockSizeException if the input is inappropriate for this cipher.
+ * @throws BadPaddingException if the input format is invalid.
+ */
+ protected abstract byte[] messageEncrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException;
+
+ /**
+ * Decrypt the ciphertext stored in input. The method should also perform an
+ * additional length check.
+ *
+ * @param input the ciphertext to be decrypted (the ciphertext length is
+ * less than or equal to maxCipherTextSize)
+ * @return the decrypted message
+ * @throws IllegalBlockSizeException if the input is inappropriate for this cipher.
+ * @throws BadPaddingException if the input format is invalid.
+ */
+ protected abstract byte[] messageDecrypt(byte[] input)
+ throws IllegalBlockSizeException, BadPaddingException;
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricHybridCipher.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricHybridCipher.java
new file mode 100644
index 00000000..57d367b2
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/AsymmetricHybridCipher.java
@@ -0,0 +1,397 @@
+package org.spongycastle.pqc.jcajce.provider.util;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.ShortBufferException;
+
+/**
+ * The AsymmetricHybridCipher class extends CipherSpiExt.
+ * NOTE: Some Ciphers are using Padding. OneAndZeroesPadding is used as default
+ * padding. However padding can still be specified, but mode is not supported;
+ * if you try to instantiate the cipher with something else than "NONE" as mode,
+ * NoSuchAlgorithmException is thrown.
+ */
+public abstract class AsymmetricHybridCipher
+ extends CipherSpiExt
+{
+
+ /**
+ * ParameterSpec used with this cipher
+ */
+ protected AlgorithmParameterSpec paramSpec;
+
+ /**
+ * Since asymmetric hybrid ciphers do not support modes, this method does
+ * nothing.
+ *
+ * @param modeName the cipher mode (unused)
+ */
+ protected final void setMode(String modeName)
+ {
+ // empty
+ }
+
+ /**
+ * Since asymmetric hybrid ciphers do not support padding, this method does
+ * nothing.
+ *
+ * @param paddingName the name of the padding scheme (not used)
+ */
+ protected final void setPadding(String paddingName)
+ {
+ // empty
+ }
+
+ /**
+ * @return <tt>null</tt> since no initialization vector is used.
+ */
+ public final byte[] getIV()
+ {
+ return null;
+ }
+
+ /**
+ * @return 0 since the implementing algorithms are not block ciphers
+ */
+ public final int getBlockSize()
+ {
+ return 0;
+ }
+
+ /**
+ * Return the parameters used with this cipher.
+ * <p/>
+ * The returned parameters may be the same that were used to initialize this
+ * cipher, or may contain the default set of parameters or a set of randomly
+ * generated parameters used by the underlying cipher implementation
+ * (provided that the underlying cipher implementation uses a default set of
+ * parameters or creates new parameters if it needs parameters but was not
+ * initialized with any).
+ *
+ * @return the parameters used with this cipher, or <tt>null</tt> if this
+ * cipher does not use any parameters.
+ */
+ public final AlgorithmParameterSpec getParameters()
+ {
+ return paramSpec;
+ }
+
+ /**
+ * Return the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next update or doFinal operation, given
+ * the input length <tt>inLen</tt> (in bytes). This call takes into
+ * account any unprocessed (buffered) data from a previous update call, and
+ * padding. The actual output length of the next update() or doFinal() call
+ * may be smaller than the length returned by this method.
+ *
+ * @param inLen the length of the input
+ * @return the length of the output of the next <tt>update()</tt> or
+ * <tt>doFinal()</tt> call
+ */
+ public final int getOutputSize(int inLen)
+ {
+ return opMode == ENCRYPT_MODE ? encryptOutputSize(inLen)
+ : decryptOutputSize(inLen);
+ }
+
+ /**
+ * Initialize the cipher for encryption by forwarding it to
+ * {@link #initEncrypt(Key, AlgorithmParameterSpec, SecureRandom)}.
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using {@link #getParameters()}.
+ *
+ * @param key the encryption key
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidParameterException if this cipher needs algorithm parameters for
+ * initialization and cannot generate parameters itself.
+ */
+ public final void initEncrypt(Key key)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initEncrypt(key, null, new SecureRandom());
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initialize this cipher for encryption by forwarding it to
+ * {@link #initEncrypt(Key, AlgorithmParameterSpec, SecureRandom)}.
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using {@link #getParameters()}.
+ *
+ * @param key the encryption key
+ * @param random the source of randomness
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidParameterException if this cipher needs algorithm parameters for
+ * initialization and cannot generate parameters itself.
+ */
+ public final void initEncrypt(Key key, SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initEncrypt(key, null, random);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initialize the cipher for encryption by forwarding it to initEncrypt(Key,
+ * FlexiSecureRandom, AlgorithmParameterSpec).
+ *
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is initialized with
+ * <tt>null</tt> parameters and cannot generate parameters
+ * itself.
+ */
+ public final void initEncrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ initEncrypt(key, params, new SecureRandom());
+ }
+
+ /**
+ * Initialize the cipher with a certain key for data encryption.
+ * <p/>
+ * If this cipher requires any random bytes (e.g., for parameter
+ * generation), it will get them from <tt>random</tt>.
+ * <p/>
+ * Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it.
+ *
+ * @param key the encryption key
+ * @param random the source of randomness
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is initialized with
+ * <tt>null</tt> parameters and cannot generate parameters
+ * itself.
+ */
+ public final void initEncrypt(Key key, AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException
+ {
+ opMode = ENCRYPT_MODE;
+ initCipherEncrypt(key, params, random);
+ }
+
+ /**
+ * Initialize the cipher for decryption by forwarding it to initDecrypt(Key,
+ * FlexiSecureRandom).
+ * <p/>
+ * If this cipher requires any algorithm parameters that cannot be derived
+ * from the given key, the underlying cipher implementation is supposed to
+ * generate the required parameters itself (using provider-specific default
+ * or random values) if it is being initialized for encryption, and raise an
+ * InvalidKeyException if it is being initialized for decryption. The
+ * generated parameters can be retrieved using {@link #getParameters()}.
+ *
+ * @param key the decryption key
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ */
+ public final void initDecrypt(Key key)
+ throws InvalidKeyException
+ {
+ try
+ {
+ initDecrypt(key, null);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new InvalidParameterException(
+ "This cipher needs algorithm parameters for initialization (cannot be null).");
+ }
+ }
+
+ /**
+ * Initialize the cipher with a certain key for data decryption.
+ * <p/>
+ * If this cipher requires any random bytes (e.g., for parameter
+ * generation), it will get them from <tt>random</tt>.
+ * <p/>
+ * Note that when a Cipher object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it
+ *
+ * @param key the decryption key
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is initialized with
+ * <tt>null</tt> parameters and cannot generate parameters
+ * itself.
+ */
+ public final void initDecrypt(Key key, AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ opMode = DECRYPT_MODE;
+ initCipherDecrypt(key, params);
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result (maybe an empty byte array)
+ */
+ public abstract byte[] update(byte[] input, int inOff, int inLen);
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the output buffer
+ * @param outOff the offset where the result is stored
+ * @return the length of the output
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ */
+ public final int update(byte[] input, int inOff, int inLen, byte[] output,
+ int outOff)
+ throws ShortBufferException
+ {
+ if (output.length < getOutputSize(inLen))
+ {
+ throw new ShortBufferException("output");
+ }
+ byte[] out = update(input, inOff, inLen);
+ System.arraycopy(out, 0, output, outOff, out.length);
+ return out.length;
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result
+ * @throws BadPaddingException if the ciphertext is invalid.
+ */
+ public abstract byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws BadPaddingException;
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the buffer for the result
+ * @param outOff the offset where the result is stored
+ * @return the output length
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ * @throws BadPaddingException if the ciphertext is invalid.
+ */
+ public final int doFinal(byte[] input, int inOff, int inLen, byte[] output,
+ int outOff)
+ throws ShortBufferException, BadPaddingException
+ {
+
+ if (output.length < getOutputSize(inLen))
+ {
+ throw new ShortBufferException("Output buffer too short.");
+ }
+ byte[] out = doFinal(input, inOff, inLen);
+ System.arraycopy(out, 0, output, outOff, out.length);
+ return out.length;
+ }
+
+ /**
+ * Compute the output size of an update() or doFinal() operation of a hybrid
+ * asymmetric cipher in encryption mode when given input of the specified
+ * length.
+ *
+ * @param inLen the length of the input
+ * @return the output size
+ */
+ protected abstract int encryptOutputSize(int inLen);
+
+ /**
+ * Compute the output size of an update() or doFinal() operation of a hybrid
+ * asymmetric cipher in decryption mode when given input of the specified
+ * length.
+ *
+ * @param inLen the length of the input
+ * @return the output size
+ */
+ protected abstract int decryptOutputSize(int inLen);
+
+ /**
+ * Initialize the AsymmetricHybridCipher with a certain key for data
+ * encryption.
+ *
+ * @param key the key which has to be used to encrypt data
+ * @param params the algorithm parameters
+ * @param sr the source of randomness
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher.
+ * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for
+ * initializing this cipher.
+ */
+ protected abstract void initCipherEncrypt(Key key,
+ AlgorithmParameterSpec params, SecureRandom sr)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Initialize the AsymmetricHybridCipher with a certain key for data
+ * encryption.
+ *
+ * @param key the key which has to be used to decrypt data
+ * @param params the algorithm parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws InvalidAlgorithmParameterException if the given parameters are inappropriate for
+ * initializing this cipher.
+ */
+ protected abstract void initCipherDecrypt(Key key,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException;
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/CipherSpiExt.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/CipherSpiExt.java
new file mode 100644
index 00000000..7978e2ae
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/CipherSpiExt.java
@@ -0,0 +1,635 @@
+package org.spongycastle.pqc.jcajce.provider.util;
+
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+
+/**
+ * The CipherSpiExt class extends CipherSpi.
+ */
+public abstract class CipherSpiExt
+ extends CipherSpi
+{
+
+ /**
+ * Constant specifying encrypt mode.
+ */
+ public static final int ENCRYPT_MODE = javax.crypto.Cipher.ENCRYPT_MODE;
+
+ /**
+ * Constant specifying decrypt mode.
+ */
+ public static final int DECRYPT_MODE = javax.crypto.Cipher.DECRYPT_MODE;
+
+ /**
+ * The operation mode for this cipher ({@link #ENCRYPT_MODE} or
+ * {@link #DECRYPT_MODE}).
+ */
+ protected int opMode;
+
+ // ****************************************************
+ // JCA adapter methods
+ // ****************************************************
+
+ /**
+ * Initialize this cipher object with a proper key and some random seed.
+ * Before a cipher object is ready for data processing, it has to be
+ * initialized according to the desired cryptographic operation, which is
+ * specified by the <tt>opMode</tt> parameter.
+ * <p/>
+ * If this cipher (including its underlying mode or padding scheme) requires
+ * any random bytes, it will obtain them from <tt>random</tt>.
+ * <p/>
+ * Note: If the mode needs an initialization vector, a blank array is used
+ * in this case.
+ *
+ * @param opMode the operation mode ({@link #ENCRYPT_MODE} or
+ * {@link #DECRYPT_MODE})
+ * @param key the key
+ * @param random the random seed
+ * @throws java.security.InvalidKeyException if the key is inappropriate for initializing this cipher.
+ */
+ protected final void engineInit(int opMode, java.security.Key key,
+ java.security.SecureRandom random)
+ throws java.security.InvalidKeyException
+ {
+
+ try
+ {
+ engineInit(opMode, key,
+ (java.security.spec.AlgorithmParameterSpec)null, random);
+ }
+ catch (java.security.InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException(e.getMessage());
+ }
+ }
+
+ /**
+ * Initialize this cipher with a key, a set of algorithm parameters, and a
+ * source of randomness. The cipher is initialized for encryption or
+ * decryption, depending on the value of <tt>opMode</tt>.
+ * <p/>
+ * If this cipher (including its underlying mode or padding scheme) requires
+ * any random bytes, it will obtain them from <tt>random</tt>. Note that
+ * when a {@link BlockCipher} object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it.
+ * <p/>
+ * Note: If the mode needs an initialization vector, a try to retrieve it
+ * from the AlgorithmParametersSpec is made.
+ *
+ * @param opMode the operation mode ({@link #ENCRYPT_MODE} or
+ * {@link #DECRYPT_MODE})
+ * @param key the key
+ * @param algParams the algorithm parameters
+ * @param random the random seed
+ * @throws java.security.InvalidKeyException if the key is inappropriate for initializing this block
+ * cipher.
+ * @throws java.security.InvalidAlgorithmParameterException if the parameters are inappropriate for initializing this
+ * block cipher.
+ */
+ protected final void engineInit(int opMode, java.security.Key key,
+ java.security.AlgorithmParameters algParams,
+ java.security.SecureRandom random)
+ throws java.security.InvalidKeyException,
+ java.security.InvalidAlgorithmParameterException
+ {
+
+ // if algParams are not specified, initialize without them
+ if (algParams == null)
+ {
+ engineInit(opMode, key, random);
+ return;
+ }
+
+ AlgorithmParameterSpec paramSpec = null;
+ // XXX getting AlgorithmParameterSpec from AlgorithmParameters
+
+ engineInit(opMode, key, paramSpec, random);
+ }
+
+ /**
+ * Initialize this cipher with a key, a set of algorithm parameters, and a
+ * source of randomness. The cipher is initialized for one of the following
+ * four operations: encryption, decryption, key wrapping or key unwrapping,
+ * depending on the value of opMode. If this cipher (including its
+ * underlying feedback or padding scheme) requires any random bytes (e.g.,
+ * for parameter generation), it will get them from random. Note that when a
+ * Cipher object is initialized, it loses all previously-acquired state. In
+ * other words, initializing a Cipher is equivalent to creating a new
+ * instance of that Cipher and initializing it.
+ *
+ * @param opMode the operation mode ({@link #ENCRYPT_MODE} or
+ * {@link #DECRYPT_MODE})
+ * @param key the encryption key
+ * @param params the algorithm parameters
+ * @param javaRand the source of randomness
+ * @throws java.security.InvalidKeyException if the given key is inappropriate for initializing this
+ * cipher
+ * @throws java.security.InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for
+ * this cipher, or if this cipher is being initialized for
+ * decryption and requires algorithm parameters and the
+ * parameters are null.
+ */
+ protected void engineInit(int opMode, java.security.Key key,
+ java.security.spec.AlgorithmParameterSpec params,
+ java.security.SecureRandom javaRand)
+ throws java.security.InvalidKeyException,
+ java.security.InvalidAlgorithmParameterException
+ {
+
+ if ((params != null) && !(params instanceof AlgorithmParameterSpec))
+ {
+ throw new java.security.InvalidAlgorithmParameterException();
+ }
+
+ if ((key == null) || !(key instanceof Key))
+ {
+ throw new java.security.InvalidKeyException();
+ }
+
+ this.opMode = opMode;
+
+ if (opMode == ENCRYPT_MODE)
+ {
+ SecureRandom flexiRand = javaRand;
+ initEncrypt((Key)key, (AlgorithmParameterSpec)params, flexiRand);
+
+ }
+ else if (opMode == DECRYPT_MODE)
+ {
+ initDecrypt((Key)key, (AlgorithmParameterSpec)params);
+
+ }
+ }
+
+ /**
+ * Return the result of the last step of a multi-step en-/decryption
+ * operation or the result of a single-step en-/decryption operation by
+ * processing the given input data and any remaining buffered data. The data
+ * to be processed is given in an input byte array. Beginning at
+ * inputOffset, only the first inputLen bytes are en-/decrypted, including
+ * any buffered bytes of a previous update operation. If necessary, padding
+ * is performed. The result is returned as a output byte array.
+ *
+ * @param input the byte array holding the data to be processed
+ * @param inOff the offset indicating the start position within the input
+ * byte array
+ * @param inLen the number of bytes to be processed
+ * @return the byte array containing the en-/decrypted data
+ * @throws javax.crypto.IllegalBlockSizeException if the ciphertext length is not a multiple of the
+ * blocklength.
+ * @throws javax.crypto.BadPaddingException if unpadding is not possible.
+ */
+ protected final byte[] engineDoFinal(byte[] input, int inOff, int inLen)
+ throws javax.crypto.IllegalBlockSizeException,
+ javax.crypto.BadPaddingException
+ {
+ return doFinal(input, inOff, inLen);
+ }
+
+ /**
+ * Perform the last step of a multi-step en-/decryption operation or a
+ * single-step en-/decryption operation by processing the given input data
+ * and any remaining buffered data. The data to be processed is given in an
+ * input byte array. Beginning at inputOffset, only the first inputLen bytes
+ * are en-/decrypted, including any buffered bytes of a previous update
+ * operation. If necessary, padding is performed. The result is stored in
+ * the given output byte array, beginning at outputOffset. The number of
+ * bytes stored in this byte array are returned.
+ *
+ * @param input the byte array holding the data to be processed
+ * @param inOff the offset indicating the start position within the input
+ * byte array
+ * @param inLen the number of bytes to be processed
+ * @param output the byte array for holding the result
+ * @param outOff the offset indicating the start position within the output
+ * byte array to which the en/decrypted data is written
+ * @return the number of bytes stored in the output byte array
+ * @throws javax.crypto.ShortBufferException if the output buffer is too short to hold the output.
+ * @throws javax.crypto.IllegalBlockSizeException if the ciphertext length is not a multiple of the
+ * blocklength.
+ * @throws javax.crypto.BadPaddingException if unpadding is not possible.
+ */
+ protected final int engineDoFinal(byte[] input, int inOff, int inLen,
+ byte[] output, int outOff)
+ throws javax.crypto.ShortBufferException,
+ javax.crypto.IllegalBlockSizeException,
+ javax.crypto.BadPaddingException
+ {
+ return doFinal(input, inOff, inLen, output, outOff);
+ }
+
+ /**
+ * @return the block size (in bytes), or 0 if the underlying algorithm is
+ * not a block cipher
+ */
+ protected final int engineGetBlockSize()
+ {
+ return getBlockSize();
+ }
+
+ /**
+ * Return the key size of the given key object in bits.
+ *
+ * @param key the key object
+ * @return the key size in bits of the given key object
+ * @throws java.security.InvalidKeyException if key is invalid.
+ */
+ protected final int engineGetKeySize(java.security.Key key)
+ throws java.security.InvalidKeyException
+ {
+ if (!(key instanceof Key))
+ {
+ throw new java.security.InvalidKeyException("Unsupported key.");
+ }
+ return getKeySize((Key)key);
+ }
+
+ /**
+ * Return the initialization vector. This is useful in the context of
+ * password-based encryption or decryption, where the IV is derived from a
+ * user-provided passphrase.
+ *
+ * @return the initialization vector in a new buffer, or <tt>null</tt> if
+ * the underlying algorithm does not use an IV, or if the IV has not
+ * yet been set.
+ */
+ protected final byte[] engineGetIV()
+ {
+ return getIV();
+ }
+
+ /**
+ * Return the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next update or doFinal operation, given
+ * the input length inputLen (in bytes).
+ * <p/>
+ * This call takes into account any unprocessed (buffered) data from a
+ * previous update call, and padding.
+ * <p/>
+ * The actual output length of the next update or doFinal call may be
+ * smaller than the length returned by this method.
+ *
+ * @param inLen the input length (in bytes)
+ * @return the required output buffer size (in bytes)
+ */
+ protected final int engineGetOutputSize(int inLen)
+ {
+ return getOutputSize(inLen);
+ }
+
+ /**
+ * Returns the parameters used with this cipher.
+ * <p/>
+ * The returned parameters may be the same that were used to initialize this
+ * cipher, or may contain the default set of parameters or a set of randomly
+ * generated parameters used by the underlying cipher implementation
+ * (provided that the underlying cipher implementation uses a default set of
+ * parameters or creates new parameters if it needs parameters but was not
+ * initialized with any).
+ *
+ * @return the parameters used with this cipher, or null if this cipher does
+ * not use any parameters.
+ */
+ protected final java.security.AlgorithmParameters engineGetParameters()
+ {
+ // TODO
+ return null;
+ }
+
+ /**
+ * Set the mode of this cipher.
+ *
+ * @param modeName the cipher mode
+ * @throws java.security.NoSuchAlgorithmException if neither the mode with the given name nor the default
+ * mode can be found
+ */
+ protected final void engineSetMode(String modeName)
+ throws java.security.NoSuchAlgorithmException
+ {
+ setMode(modeName);
+ }
+
+ /**
+ * Set the padding scheme of this cipher.
+ *
+ * @param paddingName the padding scheme
+ * @throws javax.crypto.NoSuchPaddingException if the requested padding scheme cannot be found.
+ */
+ protected final void engineSetPadding(String paddingName)
+ throws javax.crypto.NoSuchPaddingException
+ {
+ setPadding(paddingName);
+ }
+
+ /**
+ * Return the result of the next step of a multi-step en-/decryption
+ * operation. The data to be processed is given in an input byte array.
+ * Beginning at inputOffset, only the first inputLen bytes are
+ * en-/decrypted. The result is returned as a byte array.
+ *
+ * @param input the byte array holding the data to be processed
+ * @param inOff the offset indicating the start position within the input
+ * byte array
+ * @param inLen the number of bytes to be processed
+ * @return the byte array containing the en-/decrypted data
+ */
+ protected final byte[] engineUpdate(byte[] input, int inOff, int inLen)
+ {
+ return update(input, inOff, inLen);
+ }
+
+ /**
+ * Perform the next step of a multi-step en-/decryption operation. The data
+ * to be processed is given in an input byte array. Beginning at
+ * inputOffset, only the first inputLen bytes are en-/decrypted. The result
+ * is stored in the given output byte array, beginning at outputOffset. The
+ * number of bytes stored in this output byte array are returned.
+ *
+ * @param input the byte array holding the data to be processed
+ * @param inOff the offset indicating the start position within the input
+ * byte array
+ * @param inLen the number of bytes to be processed
+ * @param output the byte array for holding the result
+ * @param outOff the offset indicating the start position within the output
+ * byte array to which the en-/decrypted data is written
+ * @return the number of bytes that are stored in the output byte array
+ * @throws javax.crypto.ShortBufferException if the output buffer is too short to hold the output.
+ */
+ protected final int engineUpdate(final byte[] input, final int inOff,
+ final int inLen, byte[] output, final int outOff)
+ throws javax.crypto.ShortBufferException
+ {
+ return update(input, inOff, inLen, output, outOff);
+ }
+
+ /**
+ * Initialize this cipher with a key, a set of algorithm parameters, and a
+ * source of randomness for encryption.
+ * <p/>
+ * If this cipher requires any algorithm parameters and paramSpec is null,
+ * the underlying cipher implementation is supposed to generate the required
+ * parameters itself (using provider-specific default or random values) if
+ * it is being initialized for encryption, and raise an
+ * InvalidAlgorithmParameterException if it is being initialized for
+ * decryption. The generated parameters can be retrieved using
+ * engineGetParameters or engineGetIV (if the parameter is an IV).
+ * <p/>
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ * <p/>
+ * Note that when a {@link BlockCipher} object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it.
+ *
+ * @param key the encryption key
+ * @param cipherParams the cipher parameters
+ * @param random the source of randomness
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * block cipher.
+ * @throws InvalidAlgorithmParameterException if the parameters are inappropriate for initializing this
+ * block cipher.
+ */
+ public abstract void initEncrypt(Key key,
+ AlgorithmParameterSpec cipherParams, SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException;
+
+ /**
+ * Initialize this cipher with a key, a set of algorithm parameters, and a
+ * source of randomness for decryption.
+ * <p/>
+ * If this cipher requires any algorithm parameters and paramSpec is null,
+ * the underlying cipher implementation is supposed to generate the required
+ * parameters itself (using provider-specific default or random values) if
+ * it is being initialized for encryption, and throw an
+ * {@link InvalidAlgorithmParameterException} if it is being initialized for
+ * decryption. The generated parameters can be retrieved using
+ * engineGetParameters or engineGetIV (if the parameter is an IV).
+ * <p/>
+ * If this cipher (including its underlying feedback or padding scheme)
+ * requires any random bytes (e.g., for parameter generation), it will get
+ * them from random.
+ * <p/>
+ * Note that when a {@link BlockCipher} object is initialized, it loses all
+ * previously-acquired state. In other words, initializing a Cipher is
+ * equivalent to creating a new instance of that Cipher and initializing it.
+ *
+ * @param key the encryption key
+ * @param cipherParams the cipher parameters
+ * @throws InvalidKeyException if the given key is inappropriate for initializing this
+ * block cipher.
+ * @throws InvalidAlgorithmParameterException if the parameters are inappropriate for initializing this
+ * block cipher.
+ */
+ public abstract void initDecrypt(Key key,
+ AlgorithmParameterSpec cipherParams)
+ throws InvalidKeyException,
+ InvalidAlgorithmParameterException;
+
+ /**
+ * @return the name of this cipher
+ */
+ public abstract String getName();
+
+ /**
+ * @return the block size (in bytes), or 0 if the underlying algorithm is
+ * not a block cipher
+ */
+ public abstract int getBlockSize();
+
+ /**
+ * Returns the length in bytes that an output buffer would need to be in
+ * order to hold the result of the next update or doFinal operation, given
+ * the input length inputLen (in bytes).
+ * <p/>
+ * This call takes into account any unprocessed (buffered) data from a
+ * previous update call, and padding.
+ * <p/>
+ * The actual output length of the next update or doFinal call may be
+ * smaller than the length returned by this method.
+ *
+ * @param inputLen the input length (in bytes)
+ * @return the required output buffer size (in bytes)
+ */
+ public abstract int getOutputSize(int inputLen);
+
+ /**
+ * Return the key size of the given key object in bits.
+ *
+ * @param key the key object
+ * @return the key size in bits of the given key object
+ * @throws InvalidKeyException if key is invalid.
+ */
+ public abstract int getKeySize(Key key)
+ throws InvalidKeyException;
+
+ /**
+ * Returns the parameters used with this cipher.
+ * <p/>
+ * The returned parameters may be the same that were used to initialize this
+ * cipher, or may contain the default set of parameters or a set of randomly
+ * generated parameters used by the underlying cipher implementation
+ * (provided that the underlying cipher implementation uses a default set of
+ * parameters or creates new parameters if it needs parameters but was not
+ * initialized with any).
+ *
+ * @return the parameters used with this cipher, or null if this cipher does
+ * not use any parameters.
+ */
+ public abstract AlgorithmParameterSpec getParameters();
+
+ /**
+ * Return the initialization vector. This is useful in the context of
+ * password-based encryption or decryption, where the IV is derived from a
+ * user-provided passphrase.
+ *
+ * @return the initialization vector in a new buffer, or <tt>null</tt> if
+ * the underlying algorithm does not use an IV, or if the IV has not
+ * yet been set.
+ */
+ public abstract byte[] getIV();
+
+ /**
+ * Set the mode of this cipher.
+ *
+ * @param mode the cipher mode
+ * @throws NoSuchModeException if the requested mode cannot be found.
+ */
+ protected abstract void setMode(String mode)
+ throws NoSuchAlgorithmException;
+
+ /**
+ * Set the padding mechanism of this cipher.
+ *
+ * @param padding the padding mechanism
+ * @throws NoSuchPaddingException if the requested padding scheme cannot be found.
+ */
+ protected abstract void setPadding(String padding)
+ throws NoSuchPaddingException;
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @return a new buffer with the result (maybe an empty byte array)
+ */
+ public final byte[] update(byte[] input)
+ {
+ return update(input, 0, input.length);
+ }
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result (maybe an empty byte array)
+ */
+ public abstract byte[] update(byte[] input, int inOff, int inLen);
+
+ /**
+ * Continue a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized), processing another data part.
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the output buffer
+ * @param outOff the offset where the result is stored
+ * @return the length of the output
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ */
+ public abstract int update(byte[] input, int inOff, int inLen,
+ byte[] output, int outOff)
+ throws ShortBufferException;
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @return a new buffer with the result
+ * @throws IllegalBlockSizeException if this cipher is a block cipher and the total input
+ * length is not a multiple of the block size (for
+ * encryption when no padding is used or for decryption).
+ * @throws BadPaddingException if this cipher is a block cipher and unpadding fails.
+ */
+ public final byte[] doFinal()
+ throws IllegalBlockSizeException,
+ BadPaddingException
+ {
+ return doFinal(null, 0, 0);
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @return a new buffer with the result
+ * @throws IllegalBlockSizeException if this cipher is a block cipher and the total input
+ * length is not a multiple of the block size (for
+ * encryption when no padding is used or for decryption).
+ * @throws BadPaddingException if this cipher is a block cipher and unpadding fails.
+ */
+ public final byte[] doFinal(byte[] input)
+ throws IllegalBlockSizeException,
+ BadPaddingException
+ {
+ return doFinal(input, 0, input.length);
+ }
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @return a new buffer with the result
+ * @throws IllegalBlockSizeException if this cipher is a block cipher and the total input
+ * length is not a multiple of the block size (for
+ * encryption when no padding is used or for decryption).
+ * @throws BadPaddingException if this cipher is a block cipher and unpadding fails.
+ */
+ public abstract byte[] doFinal(byte[] input, int inOff, int inLen)
+ throws IllegalBlockSizeException, BadPaddingException;
+
+ /**
+ * Finish a multiple-part encryption or decryption operation (depending on
+ * how this cipher was initialized).
+ *
+ * @param input the input buffer
+ * @param inOff the offset where the input starts
+ * @param inLen the input length
+ * @param output the buffer for the result
+ * @param outOff the offset where the result is stored
+ * @return the output length
+ * @throws ShortBufferException if the output buffer is too small to hold the result.
+ * @throws IllegalBlockSizeException if this cipher is a block cipher and the total input
+ * length is not a multiple of the block size (for
+ * encryption when no padding is used or for decryption).
+ * @throws BadPaddingException if this cipher is a block cipher and unpadding fails.
+ */
+ public abstract int doFinal(byte[] input, int inOff, int inLen,
+ byte[] output, int outOff)
+ throws ShortBufferException,
+ IllegalBlockSizeException, BadPaddingException;
+
+}
diff --git a/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/KeyUtil.java b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/KeyUtil.java
new file mode 100644
index 00000000..ae780b6d
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/util/KeyUtil.java
@@ -0,0 +1,72 @@
+package org.spongycastle.pqc.jcajce.provider.util;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public class KeyUtil
+{
+ public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, ASN1Encodable keyData)
+ {
+ try
+ {
+ return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, byte[] keyData)
+ {
+ try
+ {
+ return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedSubjectPublicKeyInfo(SubjectPublicKeyInfo info)
+ {
+ try
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedPrivateKeyInfo(AlgorithmIdentifier algId, ASN1Encodable privKey)
+ {
+ try
+ {
+ PrivateKeyInfo info = new PrivateKeyInfo(algId, privKey.toASN1Primitive());
+
+ return getEncodedPrivateKeyInfo(info);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedPrivateKeyInfo(PrivateKeyInfo info)
+ {
+ try
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+}