diff options
Diffstat (limited to 'prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/rsa')
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()); + } + } +} |