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/jcajce/provider/asymmetric/rsa')
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java265
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java241
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java145
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java177
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java586
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java366
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java142
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java171
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java78
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java394
-rw-r--r--prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java66
11 files changed, 2631 insertions, 0 deletions
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
new file mode 100644
index 00000000..6402bd28
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -0,0 +1,265 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1Integer;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.DEROctetString;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.RSAESOAEPparams;
+import org.spongycastle.asn1.pkcs.RSASSAPSSparams;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.jcajce.provider.util.DigestFactory;
+
+public abstract class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ public static class OAEP
+ extends AlgorithmParametersSpi
+ {
+ OAEPParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSAES-OAEP-params.
+ */
+ protected byte[] engineGetEncoded()
+ {
+ AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+ DigestFactory.getOID(currentSpec.getDigestAlgorithm()),
+ DERNull.INSTANCE);
+ MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters();
+ AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_mgf1,
+ new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+ PSource.PSpecified pSource = (PSource.PSpecified)currentSpec.getPSource();
+ AlgorithmIdentifier pSourceAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(pSource.getValue()));
+ RSAESOAEPparams oaepP = new RSAESOAEPparams(hashAlgorithm, maskGenAlgorithm, pSourceAlgorithm);
+
+ try
+ {
+ return oaepP.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding OAEPParameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == OAEPParameterSpec.class && currentSpec != null)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof OAEPParameterSpec))
+ {
+ throw new InvalidParameterSpecException("OAEPParameterSpec required to initialise an OAEP algorithm parameters object");
+ }
+
+ this.currentSpec = (OAEPParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSAESOAEPparams oaepP = RSAESOAEPparams.getInstance(params);
+
+ currentSpec = new OAEPParameterSpec(
+ oaepP.getHashAlgorithm().getAlgorithm().getId(),
+ oaepP.getMaskGenAlgorithm().getAlgorithm().getId(),
+ new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(oaepP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+ new PSource.PSpecified(ASN1OctetString.getInstance(oaepP.getPSourceAlgorithm().getParameters()).getOctets()));
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "OAEP Parameters";
+ }
+ }
+
+ public static class PSS
+ extends AlgorithmParametersSpi
+ {
+ PSSParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
+ */
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ PSSParameterSpec pssSpec = currentSpec;
+ AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+ DigestFactory.getOID(pssSpec.getDigestAlgorithm()),
+ DERNull.INSTANCE);
+ MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
+ AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_mgf1,
+ new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+ RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new ASN1Integer(pssSpec.getSaltLength()), new ASN1Integer(pssSpec.getTrailerField()));
+
+ return pssP.getEncoded("DER");
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PSSParameterSpec.class && currentSpec != null)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PSSParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
+ }
+
+ this.currentSpec = (PSSParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+
+ currentSpec = new PSSParameterSpec(
+ pssP.getHashAlgorithm().getAlgorithm().getId(),
+ pssP.getMaskGenAlgorithm().getAlgorithm().getId(),
+ new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+ pssP.getSaltLength().intValue(),
+ pssP.getTrailerField().intValue());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "PSS Parameters";
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
new file mode 100644
index 00000000..31772a14
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
@@ -0,0 +1,241 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.RSAPrivateKey;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+/**
+ * A provider representation for a RSA private key, with CRT factors included.
+ */
+public class BCRSAPrivateCrtKey
+ extends BCRSAPrivateKey
+ implements RSAPrivateCrtKey
+{
+ static final long serialVersionUID = 7834723820638524718L;
+
+ private BigInteger publicExponent;
+ private BigInteger primeP;
+ private BigInteger primeQ;
+ private BigInteger primeExponentP;
+ private BigInteger primeExponentQ;
+ private BigInteger crtCoefficient;
+
+ /**
+ * construct a private key from it's org.spongycastle.crypto equivalent.
+ *
+ * @param key the parameters object representing the private key.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateCrtKeyParameters key)
+ {
+ super(key);
+
+ this.publicExponent = key.getPublicExponent();
+ this.primeP = key.getP();
+ this.primeQ = key.getQ();
+ this.primeExponentP = key.getDP();
+ this.primeExponentQ = key.getDQ();
+ this.crtCoefficient = key.getQInv();
+ }
+
+ /**
+ * construct a private key from an RSAPrivateCrtKeySpec
+ *
+ * @param spec the spec to be used in construction.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateCrtKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ this.privateExponent = spec.getPrivateExponent();
+ this.primeP = spec.getPrimeP();
+ this.primeQ = spec.getPrimeQ();
+ this.primeExponentP = spec.getPrimeExponentP();
+ this.primeExponentQ = spec.getPrimeExponentQ();
+ this.crtCoefficient = spec.getCrtCoefficient();
+ }
+
+ /**
+ * construct a private key from another RSAPrivateCrtKey.
+ *
+ * @param key the object implementing the RSAPrivateCrtKey interface.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateCrtKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrimeP();
+ this.primeQ = key.getPrimeQ();
+ this.primeExponentP = key.getPrimeExponentP();
+ this.primeExponentQ = key.getPrimeExponentQ();
+ this.crtCoefficient = key.getCrtCoefficient();
+ }
+
+ /**
+ * construct an RSA key from a private key info object.
+ */
+ BCRSAPrivateCrtKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ this(RSAPrivateKey.getInstance(info.parsePrivateKey()));
+ }
+
+ /**
+ * construct an RSA key from a ASN.1 RSA private key object.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrime1();
+ this.primeQ = key.getPrime2();
+ this.primeExponentP = key.getExponent1();
+ this.primeExponentQ = key.getExponent2();
+ this.crtCoefficient = key.getCoefficient();
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the encoding format we produce in getEncoded().
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ /**
+ * return the prime P.
+ *
+ * @return the prime P.
+ */
+ public BigInteger getPrimeP()
+ {
+ return primeP;
+ }
+
+ /**
+ * return the prime Q.
+ *
+ * @return the prime Q.
+ */
+ public BigInteger getPrimeQ()
+ {
+ return primeQ;
+ }
+
+ /**
+ * return the prime exponent for P.
+ *
+ * @return the prime exponent for P.
+ */
+ public BigInteger getPrimeExponentP()
+ {
+ return primeExponentP;
+ }
+
+ /**
+ * return the prime exponent for Q.
+ *
+ * @return the prime exponent for Q.
+ */
+ public BigInteger getPrimeExponentQ()
+ {
+ return primeExponentQ;
+ }
+
+ /**
+ * return the CRT coefficient.
+ *
+ * @return the CRT coefficient.
+ */
+ public BigInteger getCrtCoefficient()
+ {
+ return crtCoefficient;
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode()
+ ^ this.getPublicExponent().hashCode()
+ ^ this.getPrivateExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPrivateCrtKey))
+ {
+ return false;
+ }
+
+ RSAPrivateCrtKey key = (RSAPrivateCrtKey)o;
+
+ return this.getModulus().equals(key.getModulus())
+ && this.getPublicExponent().equals(key.getPublicExponent())
+ && this.getPrivateExponent().equals(key.getPrivateExponent())
+ && this.getPrimeP().equals(key.getPrimeP())
+ && this.getPrimeQ().equals(key.getPrimeQ())
+ && this.getPrimeExponentP().equals(key.getPrimeExponentP())
+ && this.getPrimeExponentQ().equals(key.getPrimeExponentQ())
+ && this.getCrtCoefficient().equals(key.getCrtCoefficient());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Private CRT Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+ buf.append(" private exponent: ").append(this.getPrivateExponent().toString(16)).append(nl);
+ buf.append(" primeP: ").append(this.getPrimeP().toString(16)).append(nl);
+ buf.append(" primeQ: ").append(this.getPrimeQ().toString(16)).append(nl);
+ buf.append(" primeExponentP: ").append(this.getPrimeExponentP().toString(16)).append(nl);
+ buf.append(" primeExponentQ: ").append(this.getPrimeExponentQ().toString(16)).append(nl);
+ buf.append(" crtCoefficient: ").append(this.getCrtCoefficient().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
new file mode 100644
index 00000000..1e63f3b5
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
@@ -0,0 +1,145 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.spongycastle.asn1.ASN1Encodable;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.spongycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.spongycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class BCRSAPrivateKey
+ implements RSAPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 5110188922551353628L;
+
+ private static BigInteger ZERO = BigInteger.valueOf(0);
+
+ protected BigInteger modulus;
+ protected BigInteger privateExponent;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCRSAPrivateKey()
+ {
+ }
+
+ BCRSAPrivateKey(
+ RSAKeyParameters key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getExponent();
+ }
+
+ BCRSAPrivateKey(
+ RSAPrivateKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.privateExponent = spec.getPrivateExponent();
+ }
+
+ BCRSAPrivateKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getPrivateExponent();
+ }
+
+ BCRSAPrivateKey(org.spongycastle.asn1.pkcs.RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getPrivateExponent();
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPrivateExponent()
+ {
+ return privateExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.spongycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof RSAPrivateKey))
+ {
+ return false;
+ }
+
+ if (o == this)
+ {
+ return true;
+ }
+
+ RSAPrivateKey key = (RSAPrivateKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPrivateExponent().equals(key.getPrivateExponent());
+ }
+
+ public int hashCode()
+ {
+ return getModulus().hashCode() ^ getPrivateExponent().hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ ASN1ObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
new file mode 100644
index 00000000..7a4454c5
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
@@ -0,0 +1,177 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OptionalDataException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCRSAPublicKey
+ implements RSAPublicKey
+{
+ private static final AlgorithmIdentifier DEFAULT_ALGORITHM_IDENTIFIER = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
+
+ static final long serialVersionUID = 2675817738516720772L;
+
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+ private transient AlgorithmIdentifier algorithmIdentifier;
+
+ BCRSAPublicKey(
+ RSAKeyParameters key)
+ {
+ this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getExponent();
+ }
+
+ BCRSAPublicKey(
+ RSAPublicKeySpec spec)
+ {
+ this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ }
+
+ BCRSAPublicKey(
+ RSAPublicKey key)
+ {
+ this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ }
+
+ BCRSAPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ populateFromPublicKeyInfo(info);
+ }
+
+ private void populateFromPublicKeyInfo(SubjectPublicKeyInfo info)
+ {
+ try
+ {
+ org.spongycastle.asn1.pkcs.RSAPublicKey pubKey = org.spongycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey());
+
+ this.algorithmIdentifier = info.getAlgorithm();
+ this.modulus = pubKey.getModulus();
+ this.publicExponent = pubKey.getPublicExponent();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in RSA public key");
+ }
+ }
+
+ /**
+ * return the modulus.
+ *
+ * @return the modulus.
+ */
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(algorithmIdentifier, new org.spongycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent()));
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode() ^ this.getPublicExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPublicKey))
+ {
+ return false;
+ }
+
+ RSAPublicKey key = (RSAPublicKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPublicExponent().equals(key.getPublicExponent());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Public Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ try
+ {
+ algorithmIdentifier = AlgorithmIdentifier.getInstance(in.readObject());
+ }
+ catch (OptionalDataException e)
+ {
+ algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+ }
+ catch (EOFException e)
+ {
+ algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
+ }
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ if (!algorithmIdentifier.equals(DEFAULT_ALGORITHM_IDENTIFIER))
+ {
+ out.writeObject(algorithmIdentifier.getEncoded());
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
new file mode 100644
index 00000000..6edd4aef
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -0,0 +1,586 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+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.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.InvalidCipherTextException;
+import org.spongycastle.crypto.encodings.ISO9796d1Encoding;
+import org.spongycastle.crypto.encodings.OAEPEncoding;
+import org.spongycastle.crypto.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.spongycastle.jcajce.provider.util.DigestFactory;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.util.Strings;
+
+public class CipherSpi
+ extends BaseCipherSpi
+{
+ private AsymmetricBlockCipher cipher;
+ private AlgorithmParameterSpec paramSpec;
+ private AlgorithmParameters engineParams;
+ private boolean publicKeyOnly = false;
+ private boolean privateKeyOnly = false;
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public CipherSpi(
+ AsymmetricBlockCipher engine)
+ {
+ cipher = engine;
+ }
+
+ public CipherSpi(
+ OAEPParameterSpec pSpec)
+ {
+ try
+ {
+ initFromSpec(pSpec);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+
+ public CipherSpi(
+ boolean publicKeyOnly,
+ boolean privateKeyOnly,
+ AsymmetricBlockCipher engine)
+ {
+ this.publicKeyOnly = publicKeyOnly;
+ this.privateKeyOnly = privateKeyOnly;
+ cipher = engine;
+ }
+
+ private void initFromSpec(
+ OAEPParameterSpec pSpec)
+ throws NoSuchPaddingException
+ {
+ MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)pSpec.getMGFParameters();
+ Digest digest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+
+ if (digest == null)
+ {
+ throw new NoSuchPaddingException("no match on OAEP constructor for digest algorithm: "+ mgfParams.getDigestAlgorithm());
+ }
+
+ cipher = new OAEPEncoding(new RSABlindedEngine(), digest, ((PSource.PSpecified)pSpec.getPSource()).getValue());
+ paramSpec = pSpec;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ try
+ {
+ return cipher.getInputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ if (key instanceof RSAPrivateKey)
+ {
+ RSAPrivateKey k = (RSAPrivateKey)key;
+
+ return k.getModulus().bitLength();
+ }
+ else if (key instanceof RSAPublicKey)
+ {
+ RSAPublicKey k = (RSAPublicKey)key;
+
+ return k.getModulus().bitLength();
+ }
+
+ throw new IllegalArgumentException("not an RSA key!");
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ try
+ {
+ return cipher.getOutputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ String md = Strings.toUpperCase(mode);
+
+ if (md.equals("NONE") || md.equals("ECB"))
+ {
+ return;
+ }
+
+ if (md.equals("1"))
+ {
+ privateKeyOnly = true;
+ publicKeyOnly = false;
+ return;
+ }
+ else if (md.equals("2"))
+ {
+ privateKeyOnly = false;
+ publicKeyOnly = true;
+ return;
+ }
+
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String pad = Strings.toUpperCase(padding);
+
+ if (pad.equals("NOPADDING"))
+ {
+ cipher = new RSABlindedEngine();
+ }
+ else if (pad.equals("PKCS1PADDING"))
+ {
+ cipher = new PKCS1Encoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("ISO9796-1PADDING"))
+ {
+ cipher = new ISO9796d1Encoding(new RSABlindedEngine());
+ }
+ else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("MD5", "MGF1", new MGF1ParameterSpec("MD5"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPPADDING"))
+ {
+ initFromSpec(OAEPParameterSpec.DEFAULT);
+ }
+ else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-1ANDMGF1PADDING"))
+ {
+ initFromSpec(OAEPParameterSpec.DEFAULT);
+ }
+ else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-224ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-256ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA384ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-384ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA512ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-512ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
+ }
+ else
+ {
+ throw new NoSuchPaddingException(padding + " unavailable with RSA.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (params == null || params instanceof OAEPParameterSpec)
+ {
+ if (key instanceof RSAPublicKey)
+ {
+ if (privateKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 1 requires RSAPrivateKey");
+ }
+
+ param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)key);
+ }
+ else if (key instanceof RSAPrivateKey)
+ {
+ if (publicKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 2 requires RSAPublicKey");
+ }
+
+ param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)key);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown key type passed to RSA");
+ }
+
+ if (params != null)
+ {
+ OAEPParameterSpec spec = (OAEPParameterSpec)params;
+
+ paramSpec = params;
+
+ if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1") && !spec.getMGFAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1.getId()))
+ {
+ throw new InvalidAlgorithmParameterException("unknown mask generation function specified");
+ }
+
+ if (!(spec.getMGFParameters() instanceof MGF1ParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("unkown MGF parameters");
+ }
+
+ Digest digest = DigestFactory.getDigest(spec.getDigestAlgorithm());
+
+ if (digest == null)
+ {
+ throw new InvalidAlgorithmParameterException("no match on digest algorithm: "+ spec.getDigestAlgorithm());
+ }
+
+ MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)spec.getMGFParameters();
+ Digest mgfDigest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+
+ if (mgfDigest == null)
+ {
+ throw new InvalidAlgorithmParameterException("no match on MGF digest algorithm: "+ mgfParams.getDigestAlgorithm());
+ }
+
+ cipher = new OAEPEncoding(new RSABlindedEngine(), digest, mgfDigest, ((PSource.PSpecified)spec.getPSource()).getValue());
+ }
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type: " + params.getClass().getName());
+ }
+
+ if (!(cipher instanceof RSABlindedEngine))
+ {
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+ else
+ {
+ param = new ParametersWithRandom(param, new SecureRandom());
+ }
+ }
+
+ bOut.reset();
+
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed to RSA");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(OAEPParameterSpec.class);
+ }
+ catch (InvalidParameterSpecException e)
+ {
+ throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + e.toString(), e);
+ }
+ }
+
+ engineParams = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // this shouldn't happen
+ throw new InvalidKeyException("Eeeek! " + e.toString(), e);
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return 0;
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ return cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ byte[] out;
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ out = cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ finally
+ {
+ bOut.reset();
+ }
+
+ for (int i = 0; i != out.length; i++)
+ {
+ output[outputOffset + i] = out[i];
+ }
+
+ return out.length;
+ }
+
+ /**
+ * classes that inherit from us.
+ */
+
+ static public class NoPadding
+ extends CipherSpi
+ {
+ public NoPadding()
+ {
+ super(new RSABlindedEngine());
+ }
+ }
+
+ static public class PKCS1v1_5Padding
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding()
+ {
+ super(new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class PKCS1v1_5Padding_PrivateOnly
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding_PrivateOnly()
+ {
+ super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class PKCS1v1_5Padding_PublicOnly
+ extends CipherSpi
+ {
+ public PKCS1v1_5Padding_PublicOnly()
+ {
+ super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class OAEPPadding
+ extends CipherSpi
+ {
+ public OAEPPadding()
+ {
+ super(OAEPParameterSpec.DEFAULT);
+ }
+ }
+
+ static public class ISO9796d1Padding
+ extends CipherSpi
+ {
+ public ISO9796d1Padding()
+ {
+ super(new ISO9796d1Encoding(new RSABlindedEngine()));
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
new file mode 100644
index 00000000..90e3667c
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -0,0 +1,366 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.DERNull;
+import org.spongycastle.asn1.nist.NISTObjectIdentifiers;
+import org.spongycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.DigestInfo;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.MD2Digest;
+import org.spongycastle.crypto.digests.MD4Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.NullDigest;
+import org.spongycastle.crypto.digests.RIPEMD128Digest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.RIPEMD256Digest;
+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.encodings.PKCS1Encoding;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+
+public class DigestSignatureSpi
+ extends SignatureSpi
+{
+ private Digest digest;
+ private AsymmetricBlockCipher cipher;
+ private AlgorithmIdentifier algId;
+
+ // care - this constructor is actually used by outside organisations
+ protected DigestSignatureSpi(
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ this.algId = null;
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected DigestSignatureSpi(
+ ASN1ObjectIdentifier objId,
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ this.algId = new AlgorithmIdentifier(objId, DERNull.INSTANCE);
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ {
+ throw new InvalidKeyException("Supplied key (" + getType(publicKey) + ") is not a RSAPublicKey instance");
+ }
+
+ CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key (" + getType(privateKey) + ") is not a RSAPrivateKey instance");
+ }
+
+ CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+ digest.reset();
+
+ cipher.init(true, param);
+ }
+
+ private String getType(
+ Object o)
+ {
+ if (o == null)
+ {
+ return null;
+ }
+
+ return o.getClass().getName();
+ }
+
+ 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[] bytes = derEncode(hash);
+
+ return cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new SignatureException("key too small for signature type");
+ }
+ 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);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = cipher.processBlock(sigBytes, 0, sigBytes.length);
+
+ expected = derEncode(hash);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ if (sig.length == expected.length)
+ {
+ for (int i = 0; i < sig.length; i++)
+ {
+ if (sig[i] != expected[i])
+ {
+ return false;
+ }
+ }
+ }
+ else if (sig.length == expected.length - 2) // NULL left out
+ {
+ int sigOffset = sig.length - hash.length - 2;
+ int expectedOffset = expected.length - hash.length - 2;
+
+ expected[1] -= 2; // adjust lengths
+ expected[3] -= 2;
+
+ for (int i = 0; i < hash.length; i++)
+ {
+ if (sig[sigOffset + i] != expected[expectedOffset + i]) // check hash
+ {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ if (sig[i] != expected[i]) // check header less NULL
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ 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)
+ {
+ return null;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return null;
+ }
+
+ private byte[] derEncode(
+ byte[] hash)
+ throws IOException
+ {
+ if (algId == null)
+ {
+ // For raw RSA, the DigestInfo must be prepared externally
+ return hash;
+ }
+
+ DigestInfo dInfo = new DigestInfo(algId, hash);
+
+ return dInfo.getEncoded(ASN1Encoding.DER);
+ }
+
+ static public class SHA1
+ extends DigestSignatureSpi
+ {
+ public SHA1()
+ {
+ super(OIWObjectIdentifiers.idSHA1, new SHA1Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA224
+ extends DigestSignatureSpi
+ {
+ public SHA224()
+ {
+ super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA256
+ extends DigestSignatureSpi
+ {
+ public SHA256()
+ {
+ super(NISTObjectIdentifiers.id_sha256, new SHA256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA384
+ extends DigestSignatureSpi
+ {
+ public SHA384()
+ {
+ super(NISTObjectIdentifiers.id_sha384, new SHA384Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class SHA512
+ extends DigestSignatureSpi
+ {
+ public SHA512()
+ {
+ super(NISTObjectIdentifiers.id_sha512, new SHA512Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class MD2
+ extends DigestSignatureSpi
+ {
+ public MD2()
+ {
+ super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class MD4
+ extends DigestSignatureSpi
+ {
+ public MD4()
+ {
+ super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class MD5
+ extends DigestSignatureSpi
+ {
+ public MD5()
+ {
+ super(PKCSObjectIdentifiers.md5, new MD5Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class RIPEMD160
+ extends DigestSignatureSpi
+ {
+ public RIPEMD160()
+ {
+ super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class RIPEMD128
+ extends DigestSignatureSpi
+ {
+ public RIPEMD128()
+ {
+ super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class RIPEMD256
+ extends DigestSignatureSpi
+ {
+ public RIPEMD256()
+ {
+ super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+
+ static public class noneRSA
+ extends DigestSignatureSpi
+ {
+ public noneRSA()
+ {
+ super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine()));
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java
new file mode 100644
index 00000000..9337e6b1
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/ISOSignatureSpi.java
@@ -0,0 +1,142 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CipherParameters;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.digests.MD5Digest;
+import org.spongycastle.crypto.digests.RIPEMD160Digest;
+import org.spongycastle.crypto.digests.SHA1Digest;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.signers.ISO9796d2Signer;
+
+public class ISOSignatureSpi
+ extends SignatureSpi
+{
+ private ISO9796d2Signer signer;
+
+ protected ISOSignatureSpi(
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ signer = new ISO9796d2Signer(cipher, digest, true);
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+ signer.init(true, param);
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ signer.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ signer.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ byte[] sig = signer.generateSignature();
+
+ return sig;
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ boolean yes = signer.verifySignature(sigBytes);
+
+ return yes;
+ }
+
+ 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 SHA1WithRSAEncryption
+ extends ISOSignatureSpi
+ {
+ public SHA1WithRSAEncryption()
+ {
+ super(new SHA1Digest(), new RSABlindedEngine());
+ }
+ }
+
+ static public class MD5WithRSAEncryption
+ extends ISOSignatureSpi
+ {
+ public MD5WithRSAEncryption()
+ {
+ super(new MD5Digest(), new RSABlindedEngine());
+ }
+ }
+
+ static public class RIPEMD160WithRSAEncryption
+ extends ISOSignatureSpi
+ {
+ public RIPEMD160WithRSAEncryption()
+ {
+ super(new RIPEMD160Digest(), new RSABlindedEngine());
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
new file mode 100644
index 00000000..fcc973af
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
@@ -0,0 +1,171 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PrivateKeyInfo;
+import org.spongycastle.asn1.pkcs.RSAPrivateKey;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.spongycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(RSAPublicKeySpec.class) && key instanceof RSAPublicKey)
+ {
+ RSAPublicKey k = (RSAPublicKey)key;
+
+ return new RSAPublicKeySpec(k.getModulus(), k.getPublicExponent());
+ }
+ else if (spec.isAssignableFrom(RSAPrivateKeySpec.class) && key instanceof java.security.interfaces.RSAPrivateKey)
+ {
+ java.security.interfaces.RSAPrivateKey k = (java.security.interfaces.RSAPrivateKey)key;
+
+ return new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent());
+ }
+ else if (spec.isAssignableFrom(RSAPrivateCrtKeySpec.class) && key instanceof RSAPrivateCrtKey)
+ {
+ RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+ return new RSAPrivateCrtKeySpec(
+ k.getModulus(), k.getPublicExponent(),
+ k.getPrivateExponent(),
+ k.getPrimeP(), k.getPrimeQ(),
+ k.getPrimeExponentP(), k.getPrimeExponentQ(),
+ k.getCrtCoefficient());
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof RSAPublicKey)
+ {
+ return new BCRSAPublicKey((RSAPublicKey)key);
+ }
+ else if (key instanceof RSAPrivateCrtKey)
+ {
+ return new BCRSAPrivateCrtKey((RSAPrivateCrtKey)key);
+ }
+ else if (key instanceof java.security.interfaces.RSAPrivateKey)
+ {
+ return new BCRSAPrivateKey((java.security.interfaces.RSAPrivateKey)key);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ try
+ {
+ return generatePrivate(PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+ }
+ catch (Exception e)
+ {
+ //
+ // in case it's just a RSAPrivateKey object... -- openSSL produces these
+ //
+ try
+ {
+ return new BCRSAPrivateCrtKey(
+ RSAPrivateKey.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+ }
+ catch (Exception ex)
+ {
+ throw new ExtendedInvalidKeySpecException("unable to process key spec: " + e.toString(), e);
+ }
+ }
+ }
+ else if (keySpec instanceof RSAPrivateCrtKeySpec)
+ {
+ return new BCRSAPrivateCrtKey((RSAPrivateCrtKeySpec)keySpec);
+ }
+ else if (keySpec instanceof RSAPrivateKeySpec)
+ {
+ return new BCRSAPrivateKey((RSAPrivateKeySpec)keySpec);
+ }
+
+ throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof RSAPublicKeySpec)
+ {
+ return new BCRSAPublicKey((RSAPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (RSAUtil.isRsaOid(algOid))
+ {
+ RSAPrivateKey rsaPrivKey = RSAPrivateKey.getInstance(keyInfo.parsePrivateKey());
+
+ if (rsaPrivKey.getCoefficient().intValue() == 0)
+ {
+ return new BCRSAPrivateKey(rsaPrivKey);
+ }
+ else
+ {
+ return new BCRSAPrivateCrtKey(keyInfo);
+ }
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (RSAUtil.isRsaOid(algOid))
+ {
+ return new BCRSAPublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
new file mode 100644
index 00000000..1239628e
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
@@ -0,0 +1,78 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+
+import org.spongycastle.crypto.AsymmetricCipherKeyPair;
+import org.spongycastle.crypto.generators.RSAKeyPairGenerator;
+import org.spongycastle.crypto.params.RSAKeyGenerationParameters;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ public KeyPairGeneratorSpi(
+ String algorithmName)
+ {
+ super(algorithmName);
+ }
+
+ final static BigInteger defaultPublicExponent = BigInteger.valueOf(0x10001);
+ final static int defaultTests = 12;
+
+ RSAKeyGenerationParameters param;
+ RSAKeyPairGenerator engine;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("RSA");
+
+ engine = new RSAKeyPairGenerator();
+ param = new RSAKeyGenerationParameters(defaultPublicExponent,
+ new SecureRandom(), 2048, defaultTests);
+ engine.init(param);
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ param = new RSAKeyGenerationParameters(defaultPublicExponent,
+ random, strength, defaultTests);
+
+ engine.init(param);
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof RSAKeyGenParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a RSAKeyGenParameterSpec");
+ }
+ RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
+
+ param = new RSAKeyGenerationParameters(
+ rsaParams.getPublicExponent(),
+ random, rsaParams.getKeysize(), defaultTests);
+
+ engine.init(param);
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ RSAKeyParameters pub = (RSAKeyParameters)pair.getPublic();
+ RSAPrivateCrtKeyParameters priv = (RSAPrivateCrtKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCRSAPublicKey(pub),
+ new BCRSAPrivateCrtKey(priv));
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
new file mode 100644
index 00000000..adce8b59
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java
@@ -0,0 +1,394 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.crypto.AsymmetricBlockCipher;
+import org.spongycastle.crypto.CryptoException;
+import org.spongycastle.crypto.Digest;
+import org.spongycastle.crypto.engines.RSABlindedEngine;
+import org.spongycastle.crypto.params.ParametersWithRandom;
+import org.spongycastle.jcajce.provider.util.DigestFactory;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+
+public class PSSSignatureSpi
+ extends SignatureSpi
+{
+ private AlgorithmParameters engineParams;
+ private PSSParameterSpec paramSpec;
+ private PSSParameterSpec originalSpec;
+ private AsymmetricBlockCipher signer;
+ private Digest contentDigest;
+ private Digest mgfDigest;
+ private int saltLength;
+ private byte trailer;
+ private boolean isRaw;
+
+ private org.spongycastle.crypto.signers.PSSSigner pss;
+
+ private byte getTrailer(
+ int trailerField)
+ {
+ if (trailerField == 1)
+ {
+ return org.spongycastle.crypto.signers.PSSSigner.TRAILER_IMPLICIT;
+ }
+
+ throw new IllegalArgumentException("unknown trailer field");
+ }
+
+ private void setupContentDigest()
+ {
+ if (isRaw)
+ {
+ this.contentDigest = new NullPssDigest(mgfDigest);
+ }
+ else
+ {
+ this.contentDigest = mgfDigest;
+ }
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected PSSSignatureSpi(
+ AsymmetricBlockCipher signer,
+ PSSParameterSpec paramSpecArg)
+ {
+ this(signer, paramSpecArg, false);
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected PSSSignatureSpi(
+ AsymmetricBlockCipher signer,
+ PSSParameterSpec baseParamSpec,
+ boolean isRaw)
+ {
+ this.signer = signer;
+ this.originalSpec = baseParamSpec;
+
+ if (baseParamSpec == null)
+ {
+ this.paramSpec = PSSParameterSpec.DEFAULT;
+ }
+ else
+ {
+ this.paramSpec = baseParamSpec;
+ }
+
+ this.mgfDigest = DigestFactory.getDigest(paramSpec.getDigestAlgorithm());
+ this.saltLength = paramSpec.getSaltLength();
+ this.trailer = getTrailer(paramSpec.getTrailerField());
+ this.isRaw = isRaw;
+
+ setupContentDigest();
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPublicKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer);
+ pss.init(false,
+ RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey));
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer);
+ pss.init(true, new ParametersWithRandom(RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey), random));
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
+ }
+
+ pss = new org.spongycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer);
+ pss.init(true, RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey));
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ pss.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ pss.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ try
+ {
+ return pss.generateSignature();
+ }
+ catch (CryptoException e)
+ {
+ throw new SignatureException(e.getMessage());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ return pss.verifySignature(sigBytes);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ throws InvalidParameterException
+ {
+ if (params instanceof PSSParameterSpec)
+ {
+ PSSParameterSpec newParamSpec = (PSSParameterSpec)params;
+
+ if (originalSpec != null)
+ {
+ if (!DigestFactory.isSameDigest(originalSpec.getDigestAlgorithm(), newParamSpec.getDigestAlgorithm()))
+ {
+ throw new InvalidParameterException("parameter must be using " + originalSpec.getDigestAlgorithm());
+ }
+ }
+ if (!newParamSpec.getMGFAlgorithm().equalsIgnoreCase("MGF1") && !newParamSpec.getMGFAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1.getId()))
+ {
+ throw new InvalidParameterException("unknown mask generation function specified");
+ }
+
+ if (!(newParamSpec.getMGFParameters() instanceof MGF1ParameterSpec))
+ {
+ throw new InvalidParameterException("unkown MGF parameters");
+ }
+
+ MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)newParamSpec.getMGFParameters();
+
+ if (!DigestFactory.isSameDigest(mgfParams.getDigestAlgorithm(), newParamSpec.getDigestAlgorithm()))
+ {
+ throw new InvalidParameterException("digest algorithm for MGF should be the same as for PSS parameters.");
+ }
+
+ Digest newDigest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+
+ if (newDigest == null)
+ {
+ throw new InvalidParameterException("no match on MGF digest algorithm: "+ mgfParams.getDigestAlgorithm());
+ }
+
+ this.engineParams = null;
+ this.paramSpec = newParamSpec;
+ this.mgfDigest = newDigest;
+ this.saltLength = paramSpec.getSaltLength();
+ this.trailer = getTrailer(paramSpec.getTrailerField());
+
+ setupContentDigest();
+ }
+ else
+ {
+ throw new InvalidParameterException("Only PSSParameterSpec supported");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("PSS", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineGetParameter unsupported");
+ }
+
+ static public class nonePSS
+ extends PSSSignatureSpi
+ {
+ public nonePSS()
+ {
+ super(new RSABlindedEngine(), null, true);
+ }
+ }
+
+ static public class PSSwithRSA
+ extends PSSSignatureSpi
+ {
+ public PSSwithRSA()
+ {
+ super(new RSABlindedEngine(), null);
+ }
+ }
+
+ static public class SHA1withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA1withRSA()
+ {
+ super(new RSABlindedEngine(), PSSParameterSpec.DEFAULT);
+ }
+ }
+
+ static public class SHA224withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA224withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), 28, 1));
+ }
+ }
+
+ static public class SHA256withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA256withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1));
+ }
+ }
+
+ static public class SHA384withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA384withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA-384", "MGF1", new MGF1ParameterSpec("SHA-384"), 48, 1));
+ }
+ }
+
+ static public class SHA512withRSA
+ extends PSSSignatureSpi
+ {
+ public SHA512withRSA()
+ {
+ super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512", "MGF1", new MGF1ParameterSpec("SHA-512"), 64, 1));
+ }
+ }
+
+ private class NullPssDigest
+ implements Digest
+ {
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ private Digest baseDigest;
+ private boolean oddTime = true;
+
+ public NullPssDigest(Digest mgfDigest)
+ {
+ this.baseDigest = mgfDigest;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "NULL";
+ }
+
+ public int getDigestSize()
+ {
+ return baseDigest.getDigestSize();
+ }
+
+ public void update(byte in)
+ {
+ bOut.write(in);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ bOut.write(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ byte[] res = bOut.toByteArray();
+
+ if (oddTime)
+ {
+ System.arraycopy(res, 0, out, outOff, res.length);
+ }
+ else
+ {
+ baseDigest.update(res, 0, res.length);
+
+ baseDigest.doFinal(out, outOff);
+ }
+
+ reset();
+
+ oddTime = !oddTime;
+
+ return res.length;
+ }
+
+ public void reset()
+ {
+ bOut.reset();
+ baseDigest.reset();
+ }
+
+ public int getByteLength()
+ {
+ return 0;
+ }
+ }
+}
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
new file mode 100644
index 00000000..da57ec3b
--- /dev/null
+++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
@@ -0,0 +1,66 @@
+package org.spongycastle.jcajce.provider.asymmetric.rsa;
+
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.spongycastle.asn1.x509.X509ObjectIdentifiers;
+import org.spongycastle.crypto.params.RSAKeyParameters;
+import org.spongycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * utility class for converting java.security RSA objects into their
+ * org.spongycastle.crypto counterparts.
+ */
+public class RSAUtil
+{
+ public static final ASN1ObjectIdentifier[] rsaOids =
+ {
+ PKCSObjectIdentifiers.rsaEncryption,
+ X509ObjectIdentifiers.id_ea_rsa,
+ PKCSObjectIdentifiers.id_RSAES_OAEP,
+ PKCSObjectIdentifiers.id_RSASSA_PSS
+ };
+
+ public static boolean isRsaOid(
+ ASN1ObjectIdentifier algOid)
+ {
+ for (int i = 0; i != rsaOids.length; i++)
+ {
+ if (algOid.equals(rsaOids[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static RSAKeyParameters generatePublicKeyParameter(
+ RSAPublicKey key)
+ {
+ return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent());
+
+ }
+
+ static RSAKeyParameters generatePrivateKeyParameter(
+ RSAPrivateKey key)
+ {
+ if (key instanceof RSAPrivateCrtKey)
+ {
+ RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+ return new RSAPrivateCrtKeyParameters(k.getModulus(),
+ k.getPublicExponent(), k.getPrivateExponent(),
+ k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(), k.getPrimeExponentQ(), k.getCrtCoefficient());
+ }
+ else
+ {
+ RSAPrivateKey k = key;
+
+ return new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent());
+ }
+ }
+}