diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa')
9 files changed, 2073 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java new file mode 100644 index 0000000..99ac36c --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java @@ -0,0 +1,273 @@ +package org.bouncycastle.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.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.RSAESOAEPparams; +import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.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()), + // BEGIN android-changed + DERNull.INSTANCE); + // END android-changed + MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters(); + AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier( + PKCSObjectIdentifiers.id_mgf1, + // BEGIN android-changed + new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE)); + // END android-changed + 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()), + // BEGIN android-changed + DERNull.INSTANCE); + // END android-changed + MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters(); + AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier( + PKCSObjectIdentifiers.id_mgf1, + // BEGIN android-changed + new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE)); + // END android-changed + 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/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java new file mode 100644 index 0000000..b0aa66e --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java @@ -0,0 +1,243 @@ +package org.bouncycastle.jcajce.provider.asymmetric.rsa; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.spec.RSAPrivateCrtKeySpec; + +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.pkcs.RSAPrivateKey; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.bouncycastle.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.bouncycastle.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() + { + // BEGIN android-changed + return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient())); + // END android-changed + } + + /** + * 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/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java new file mode 100644 index 0000000..6643f13 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java @@ -0,0 +1,142 @@ +package org.bouncycastle.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.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; +import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; +import org.bouncycastle.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(); + } + + public BigInteger getModulus() + { + return modulus; + } + + public BigInteger getPrivateExponent() + { + return privateExponent; + } + + public String getAlgorithm() + { + return "RSA"; + } + + public String getFormat() + { + return "PKCS#8"; + } + + public byte[] getEncoded() + { + // BEGIN android-changed + return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO)); + // END android-changed + } + + 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( + DERObjectIdentifier 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/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java new file mode 100644 index 0000000..e57da4a --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java @@ -0,0 +1,131 @@ +package org.bouncycastle.jcajce.provider.asymmetric.rsa; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.RSAPublicKeySpec; + +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; + +public class BCRSAPublicKey + implements RSAPublicKey +{ + static final long serialVersionUID = 2675817738516720772L; + + private BigInteger modulus; + private BigInteger publicExponent; + + BCRSAPublicKey( + RSAKeyParameters key) + { + this.modulus = key.getModulus(); + this.publicExponent = key.getExponent(); + } + + BCRSAPublicKey( + RSAPublicKeySpec spec) + { + this.modulus = spec.getModulus(); + this.publicExponent = spec.getPublicExponent(); + } + + BCRSAPublicKey( + RSAPublicKey key) + { + this.modulus = key.getModulus(); + this.publicExponent = key.getPublicExponent(); + } + + BCRSAPublicKey( + SubjectPublicKeyInfo info) + { + try + { + org.bouncycastle.asn1.pkcs.RSAPublicKey pubKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey()); + + 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() + { + // BEGIN android-changed + return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent())); + // END android-changed + } + + 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(); + } +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java new file mode 100644 index 0000000..1f53f5a --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java @@ -0,0 +1,589 @@ +package org.bouncycastle.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.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.crypto.AsymmetricBlockCipher; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.InvalidCipherTextException; +// BEGIN android-removed +// import org.bouncycastle.crypto.encodings.ISO9796d1Encoding; +// END android-removed +import org.bouncycastle.crypto.encodings.OAEPEncoding; +import org.bouncycastle.crypto.encodings.PKCS1Encoding; +import org.bouncycastle.crypto.engines.RSABlindedEngine; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi; +import org.bouncycastle.jcajce.provider.util.DigestFactory; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.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()); + } + // BEGIN android-removed + // else if (pad.equals("ISO9796-1PADDING")) + // { + // cipher = new ISO9796d1Encoding(new RSABlindedEngine()); + // } + // END android-removed + 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); + } + // BEGIN android-removed + // else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-224ANDMGF1PADDING")) + // { + // initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT)); + // } + // END android-removed + 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 IllegalArgumentException("unknown parameter type."); + } + + if (!(cipher instanceof RSABlindedEngine)) + { + if (random != null) + { + param = new ParametersWithRandom(param, random); + } + else + { + param = new ParametersWithRandom(param, new SecureRandom()); + } + } + + 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(); + bOut.reset(); + + out = cipher.processBlock(bytes, 0, bytes.length); + } + catch (InvalidCipherTextException e) + { + throw new BadPaddingException(e.getMessage()); + } + + 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()); + } + } + + // BEGIN android-removed + // 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())); + // } + // } + // END android-removed +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java new file mode 100644 index 0000000..a1bdc65 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java @@ -0,0 +1,389 @@ +package org.bouncycastle.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.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +// BEGIN android-removed +// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +// END android-removed +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.DigestInfo; +import org.bouncycastle.crypto.AsymmetricBlockCipher; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +// BEGIN android-removed +// import org.bouncycastle.crypto.digests.MD2Digest; +// import org.bouncycastle.crypto.digests.MD4Digest; +// import org.bouncycastle.crypto.digests.MD5Digest; +// import org.bouncycastle.crypto.digests.NullDigest; +// import org.bouncycastle.crypto.digests.RIPEMD128Digest; +// import org.bouncycastle.crypto.digests.RIPEMD160Digest; +// import org.bouncycastle.crypto.digests.RIPEMD256Digest; +// import org.bouncycastle.crypto.digests.SHA1Digest; +// import org.bouncycastle.crypto.digests.SHA224Digest; +// import org.bouncycastle.crypto.digests.SHA256Digest; +// import org.bouncycastle.crypto.digests.SHA384Digest; +// import org.bouncycastle.crypto.digests.SHA512Digest; +// END android-removed +// BEGIN android-added +import org.bouncycastle.crypto.digests.AndroidDigestFactory; +// END android-added +import org.bouncycastle.crypto.encodings.PKCS1Encoding; +import org.bouncycastle.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() + { + // BEGIN android-changed + super(OIWObjectIdentifiers.idSHA1, AndroidDigestFactory.getSHA1(), new PKCS1Encoding(new RSABlindedEngine())); + // END android-changed + } + } + + // BEGIN android-removed + // static public class SHA224 + // extends DigestSignatureSpi + // { + // public SHA224() + // { + // super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine())); + // } + // } + // END android-removed + + static public class SHA256 + extends DigestSignatureSpi + { + public SHA256() + { + // BEGIN android-changed + super(NISTObjectIdentifiers.id_sha256, AndroidDigestFactory.getSHA256(), new PKCS1Encoding(new RSABlindedEngine())); + // END android-changed + } + } + + static public class SHA384 + extends DigestSignatureSpi + { + public SHA384() + { + // BEGIN android-changed + super(NISTObjectIdentifiers.id_sha384, AndroidDigestFactory.getSHA384(), new PKCS1Encoding(new RSABlindedEngine())); + // END android-changed + } + } + + static public class SHA512 + extends DigestSignatureSpi + { + public SHA512() + { + // BEGIN android-changed + super(NISTObjectIdentifiers.id_sha512, AndroidDigestFactory.getSHA512(), new PKCS1Encoding(new RSABlindedEngine())); + // END android-changed + } + } + + // BEGIN android-removed + // 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())); + // } + // } + // END android-removed + + static public class MD5 + extends DigestSignatureSpi + { + public MD5() + { + // BEGIN android-changed + super(PKCSObjectIdentifiers.md5, AndroidDigestFactory.getMD5(), new PKCS1Encoding(new RSABlindedEngine())); + // END android-changed + } + } + + // BEGIN android-removed + // 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())); + // } + // } + // END android-removed +} diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java new file mode 100644 index 0000000..d8eb539 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java @@ -0,0 +1,162 @@ +package org.bouncycastle.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.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.pkcs.RSAPrivateKey; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; +import org.bouncycastle.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)) + { + 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/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java new file mode 100644 index 0000000..c61e7cb --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java @@ -0,0 +1,78 @@ +package org.bouncycastle.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.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.RSAKeyPairGenerator; +import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.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/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java new file mode 100644 index 0000000..4943a99 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java @@ -0,0 +1,66 @@ +package org.bouncycastle.jcajce.provider.asymmetric.rsa; + +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; + +/** + * utility class for converting java.security RSA objects into their + * org.bouncycastle.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()); + } + } +} |