diff --git a/boot_signer/src/main/java/BootSignature.java b/boot_signer/src/main/java/BootSignature.java index 03eb32a..3cf9499 100644 --- a/boot_signer/src/main/java/BootSignature.java +++ b/boot_signer/src/main/java/BootSignature.java @@ -149,6 +149,7 @@ public class BootSignature extends ASN1Object throws Exception, IOException, CertificateEncodingException { ASN1InputStream s = new ASN1InputStream(cert.getEncoded()); certificate = s.readObject(); + publicKey = cert.getPublicKey(); } public byte[] generateSignableImage(byte[] image) throws IOException { @@ -253,7 +254,7 @@ public class BootSignature extends ASN1Object Utils.write(image_with_metadata, outPath); } - public static void verifySignature(String imagePath) throws Exception { + public static void verifySignature(String imagePath, String certPath) throws Exception { byte[] image = Utils.read(imagePath); int signableSize = getSignableImageSize(image); @@ -264,6 +265,11 @@ public class BootSignature extends ASN1Object byte[] signature = Arrays.copyOfRange(image, signableSize, image.length); BootSignature bootsig = new BootSignature(signature); + if (!certPath.isEmpty()) { + System.err.println("NOTE: verifying using public key from " + certPath); + bootsig.setCertificate(Utils.loadPEMCertificate(certPath)); + } + try { if (bootsig.verify(Arrays.copyOf(image, signableSize))) { System.err.println("Signature is VALID"); @@ -291,8 +297,15 @@ public class BootSignature extends ASN1Object Security.addProvider(new BouncyCastleProvider()); if ("-verify".equals(args[0])) { + String certPath = ""; + + if (args.length >= 4 && "-certificate".equals(args[2])) { + /* args[3] is the path to a public key certificate */ + certPath = args[3]; + } + /* args[1] is the path to a signed boot image */ - verifySignature(args[1]); + verifySignature(args[1], certPath); } else { /* args[0] is the target name, typically /boot args[1] is the path to a boot image to sign diff --git a/boot_signer/src/main/java/Utils.java b/boot_signer/src/main/java/Utils.java index 937c206..6d80276 100644 --- a/boot_signer/src/main/java/Utils.java +++ b/boot_signer/src/main/java/Utils.java @@ -258,10 +258,10 @@ public class Utils { static boolean verify(PublicKey key, byte[] input, byte[] signature, AlgorithmIdentifier algId) throws Exception { - String algName = ID_TO_ALG.get(algId.getObjectId().getId()); + String algName = ID_TO_ALG.get(algId.getAlgorithm().getId()); if (algName == null) { - throw new IllegalArgumentException("Unsupported algorithm " + algId.getObjectId()); + throw new IllegalArgumentException("Unsupported algorithm " + algId.getAlgorithm()); } Signature verifier = Signature.getInstance(algName); diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/AttributeCertificateHolder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/AttributeCertificateHolder.java index 074d3fc..0fc3433 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/AttributeCertificateHolder.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/AttributeCertificateHolder.java @@ -53,20 +53,36 @@ public class AttributeCertificateHolder holder = Holder.getInstance(seq); } + /** + * Create a holder using the baseCertificateID element. + * + * @param issuerName name of associated certificate's issuer. + * @param serialNumber serial number of associated certificate. + */ public AttributeCertificateHolder(X500Name issuerName, BigInteger serialNumber) { holder = new Holder(new IssuerSerial( - new GeneralNames(new GeneralName(issuerName)), + generateGeneralNames(issuerName), new ASN1Integer(serialNumber))); } + /** + * Create a holder using the baseCertificateID option based on the passed in associated certificate, + * + * @param cert the certificate to be associated with this holder. + */ public AttributeCertificateHolder(X509CertificateHolder cert) { holder = new Holder(new IssuerSerial(generateGeneralNames(cert.getIssuer()), new ASN1Integer(cert.getSerialNumber()))); } + /** + * Create a holder using the entityName option based on the passed in principal. + * + * @param principal the entityName to be associated with the attribute certificate. + */ public AttributeCertificateHolder(X500Name principal) { holder = new Holder(generateGeneralNames(principal)); diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509AttributeCertificateHolder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509AttributeCertificateHolder.java index a34b3b3..e6b0d7e 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509AttributeCertificateHolder.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509AttributeCertificateHolder.java @@ -21,11 +21,13 @@ import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.Extensions; import org.bouncycastle.operator.ContentVerifier; import org.bouncycastle.operator.ContentVerifierProvider; +import org.bouncycastle.util.Encodable; /** * Holding class for an X.509 AttributeCertificate structure. */ public class X509AttributeCertificateHolder + implements Encodable { private static Attribute[] EMPTY_ARRAY = new Attribute[0]; @@ -277,7 +279,7 @@ public class X509AttributeCertificateHolder */ public byte[] getSignature() { - return attrCert.getSignatureValue().getBytes(); + return attrCert.getSignatureValue().getOctets(); } /** @@ -338,7 +340,7 @@ public class X509AttributeCertificateHolder throw new CertException("unable to process signature: " + e.getMessage(), e); } - return verifier.verify(attrCert.getSignatureValue().getBytes()); + return verifier.verify(this.getSignature()); } public boolean equals( diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509CRLHolder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509CRLHolder.java index b3723f3..4b773e2 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509CRLHolder.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509CRLHolder.java @@ -24,11 +24,13 @@ import org.bouncycastle.asn1.x509.IssuingDistributionPoint; import org.bouncycastle.asn1.x509.TBSCertList; import org.bouncycastle.operator.ContentVerifier; import org.bouncycastle.operator.ContentVerifierProvider; +import org.bouncycastle.util.Encodable; /** * Holding class for an X.509 CRL structure. */ public class X509CRLHolder + implements Encodable { private CertificateList x509CRL; private boolean isIndirect; @@ -289,7 +291,7 @@ public class X509CRLHolder throw new CertException("unable to process signature: " + e.getMessage(), e); } - return verifier.verify(x509CRL.getSignature().getBytes()); + return verifier.verify(x509CRL.getSignature().getOctets()); } public boolean equals( diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509CertificateHolder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509CertificateHolder.java index 1081d93..b5ad578 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509CertificateHolder.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/X509CertificateHolder.java @@ -19,11 +19,13 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.TBSCertificate; import org.bouncycastle.operator.ContentVerifier; import org.bouncycastle.operator.ContentVerifierProvider; +import org.bouncycastle.util.Encodable; /** * Holding class for an X.509 Certificate structure. */ public class X509CertificateHolder + implements Encodable { private Certificate x509Certificate; private Extensions extensions; @@ -214,7 +216,7 @@ public class X509CertificateHolder /** * Return the underlying ASN.1 structure for the certificate in this holder. * - * @return a X509CertificateStructure object. + * @return a Certificate object. */ public Certificate toASN1Structure() { @@ -238,7 +240,7 @@ public class X509CertificateHolder */ public byte[] getSignature() { - return x509Certificate.getSignature().getBytes(); + return x509Certificate.getSignature().getOctets(); } /** @@ -287,7 +289,7 @@ public class X509CertificateHolder throw new CertException("unable to process signature: " + e.getMessage(), e); } - return verifier.verify(x509Certificate.getSignature().getBytes()); + return verifier.verify(this.getSignature()); } public boolean equals( diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPResp.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPResp.java new file mode 100644 index 0000000..d74bef0 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPResp.java @@ -0,0 +1,225 @@ +package org.bouncycastle.cert.ocsp; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; +import java.util.List; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ocsp.BasicOCSPResponse; +import org.bouncycastle.asn1.ocsp.ResponseData; +import org.bouncycastle.asn1.ocsp.SingleResponse; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.operator.ContentVerifier; +import org.bouncycastle.operator.ContentVerifierProvider; +import org.bouncycastle.util.Encodable; + +/** + *
+ * BasicOCSPResponse       ::= SEQUENCE {
+ *    tbsResponseData      ResponseData,
+ *    signatureAlgorithm   AlgorithmIdentifier,
+ *    signature            BIT STRING,
+ *    certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ * 
+ */ +public class BasicOCSPResp + implements Encodable +{ + private BasicOCSPResponse resp; + private ResponseData data; + private Extensions extensions; + + public BasicOCSPResp( + BasicOCSPResponse resp) + { + this.resp = resp; + this.data = resp.getTbsResponseData(); + this.extensions = Extensions.getInstance(resp.getTbsResponseData().getResponseExtensions()); + } + + /** + * Return the DER encoding of the tbsResponseData field. + * @return DER encoding of tbsResponseData + */ + public byte[] getTBSResponseData() + { + try + { + return resp.getTbsResponseData().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + return null; + } + } + + /** + * Return the algorithm identifier describing the signature used in the response. + * + * @return an AlgorithmIdentifier + */ + public AlgorithmIdentifier getSignatureAlgorithmID() + { + return resp.getSignatureAlgorithm(); + } + + public int getVersion() + { + return data.getVersion().getValue().intValue() + 1; + } + + public RespID getResponderId() + { + return new RespID(data.getResponderID()); + } + + public Date getProducedAt() + { + return OCSPUtils.extractDate(data.getProducedAt()); + } + + public SingleResp[] getResponses() + { + ASN1Sequence s = data.getResponses(); + SingleResp[] rs = new SingleResp[s.size()]; + + for (int i = 0; i != rs.length; i++) + { + rs[i] = new SingleResp(SingleResponse.getInstance(s.getObjectAt(i))); + } + + return rs; + } + + public boolean hasExtensions() + { + return extensions != null; + } + + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + public List getExtensionOIDs() + { + return OCSPUtils.getExtensionOIDs(extensions); + } + + public Set getCriticalExtensionOIDs() + { + return OCSPUtils.getCriticalExtensionOIDs(extensions); + } + + public Set getNonCriticalExtensionOIDs() + { + return OCSPUtils.getNonCriticalExtensionOIDs(extensions); + } + + + public ASN1ObjectIdentifier getSignatureAlgOID() + { + return resp.getSignatureAlgorithm().getAlgorithm(); + } + + public byte[] getSignature() + { + return resp.getSignature().getOctets(); + } + + public X509CertificateHolder[] getCerts() + { + // + // load the certificates if we have any + // + if (resp.getCerts() != null) + { + ASN1Sequence s = resp.getCerts(); + + if (s != null) + { + X509CertificateHolder[] certs = new X509CertificateHolder[s.size()]; + + for (int i = 0; i != certs.length; i++) + { + certs[i] = new X509CertificateHolder(Certificate.getInstance(s.getObjectAt(i))); + } + + return certs; + } + + return OCSPUtils.EMPTY_CERTS; + } + else + { + return OCSPUtils.EMPTY_CERTS; + } + } + + /** + * verify the signature against the tbsResponseData object we contain. + */ + public boolean isSignatureValid( + ContentVerifierProvider verifierProvider) + throws OCSPException + { + try + { + ContentVerifier verifier = verifierProvider.get(resp.getSignatureAlgorithm()); + OutputStream vOut = verifier.getOutputStream(); + + vOut.write(resp.getTbsResponseData().getEncoded(ASN1Encoding.DER)); + vOut.close(); + + return verifier.verify(this.getSignature()); + } + catch (Exception e) + { + throw new OCSPException("exception processing sig: " + e, e); + } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + return resp.getEncoded(); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof BasicOCSPResp)) + { + return false; + } + + BasicOCSPResp r = (BasicOCSPResp)o; + + return resp.equals(r.resp); + } + + public int hashCode() + { + return resp.hashCode(); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java new file mode 100644 index 0000000..5695907 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java @@ -0,0 +1,283 @@ +package org.bouncycastle.cert.ocsp; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.ocsp.BasicOCSPResponse; +import org.bouncycastle.asn1.ocsp.CertStatus; +import org.bouncycastle.asn1.ocsp.ResponseData; +import org.bouncycastle.asn1.ocsp.RevokedInfo; +import org.bouncycastle.asn1.ocsp.SingleResponse; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.CRLReason; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.DigestCalculator; + +/** + * Generator for basic OCSP response objects. + */ +public class BasicOCSPRespBuilder +{ + private List list = new ArrayList(); + private Extensions responseExtensions = null; + private RespID responderID; + + private class ResponseObject + { + CertificateID certId; + CertStatus certStatus; + ASN1GeneralizedTime thisUpdate; + ASN1GeneralizedTime nextUpdate; + Extensions extensions; + + public ResponseObject( + CertificateID certId, + CertificateStatus certStatus, + Date thisUpdate, + Date nextUpdate, + Extensions extensions) + { + this.certId = certId; + + if (certStatus == null) + { + this.certStatus = new CertStatus(); + } + else if (certStatus instanceof UnknownStatus) + { + this.certStatus = new CertStatus(2, DERNull.INSTANCE); + } + else + { + RevokedStatus rs = (RevokedStatus)certStatus; + + if (rs.hasRevocationReason()) + { + this.certStatus = new CertStatus( + new RevokedInfo(new ASN1GeneralizedTime(rs.getRevocationTime()), CRLReason.lookup(rs.getRevocationReason()))); + } + else + { + this.certStatus = new CertStatus( + new RevokedInfo(new ASN1GeneralizedTime(rs.getRevocationTime()), null)); + } + } + + this.thisUpdate = new DERGeneralizedTime(thisUpdate); + + if (nextUpdate != null) + { + this.nextUpdate = new DERGeneralizedTime(nextUpdate); + } + else + { + this.nextUpdate = null; + } + + this.extensions = extensions; + } + + public SingleResponse toResponse() + throws Exception + { + return new SingleResponse(certId.toASN1Primitive(), certStatus, thisUpdate, nextUpdate, extensions); + } + } + + /** + * basic constructor + */ + public BasicOCSPRespBuilder( + RespID responderID) + { + this.responderID = responderID; + } + + /** + * construct with the responderID to be the SHA-1 keyHash of the passed in public key. + * + * @param key the key info of the responder public key. + * @param digCalc a SHA-1 digest calculator + */ + public BasicOCSPRespBuilder( + SubjectPublicKeyInfo key, + DigestCalculator digCalc) + throws OCSPException + { + this.responderID = new RespID(key, digCalc); + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param certStatus status of the certificate - null if okay + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus) + { + this.addResponse(certID, certStatus, new Date(), null, null); + + return this; + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param certStatus status of the certificate - null if okay + * @param singleExtensions optional extensions + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus, + Extensions singleExtensions) + { + this.addResponse(certID, certStatus, new Date(), null, singleExtensions); + + return this; + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param nextUpdate date when next update should be requested + * @param certStatus status of the certificate - null if okay + * @param singleExtensions optional extensions + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus, + Date nextUpdate, + Extensions singleExtensions) + { + this.addResponse(certID, certStatus, new Date(), nextUpdate, singleExtensions); + + return this; + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param thisUpdate date this response was valid on + * @param nextUpdate date when next update should be requested + * @param certStatus status of the certificate - null if okay + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus, + Date thisUpdate, + Date nextUpdate) + { + this.addResponse(certID, certStatus, thisUpdate, nextUpdate, null); + + return this; + } + + /** + * Add a response for a particular Certificate ID. + * + * @param certID certificate ID details + * @param thisUpdate date this response was valid on + * @param nextUpdate date when next update should be requested + * @param certStatus status of the certificate - null if okay + * @param singleExtensions optional extensions + */ + public BasicOCSPRespBuilder addResponse( + CertificateID certID, + CertificateStatus certStatus, + Date thisUpdate, + Date nextUpdate, + Extensions singleExtensions) + { + list.add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions)); + + return this; + } + + /** + * Set the extensions for the response. + * + * @param responseExtensions the extension object to carry. + */ + public BasicOCSPRespBuilder setResponseExtensions( + Extensions responseExtensions) + { + this.responseExtensions = responseExtensions; + + return this; + } + + public BasicOCSPResp build( + ContentSigner signer, + X509CertificateHolder[] chain, + Date producedAt) + throws OCSPException + { + Iterator it = list.iterator(); + + ASN1EncodableVector responses = new ASN1EncodableVector(); + + while (it.hasNext()) + { + try + { + responses.add(((ResponseObject)it.next()).toResponse()); + } + catch (Exception e) + { + throw new OCSPException("exception creating Request", e); + } + } + + ResponseData tbsResp = new ResponseData(responderID.toASN1Primitive(), new ASN1GeneralizedTime(producedAt), new DERSequence(responses), responseExtensions); + DERBitString bitSig; + + try + { + OutputStream sigOut = signer.getOutputStream(); + + sigOut.write(tbsResp.getEncoded(ASN1Encoding.DER)); + sigOut.close(); + + bitSig = new DERBitString(signer.getSignature()); + } + catch (Exception e) + { + throw new OCSPException("exception processing TBSRequest: " + e.getMessage(), e); + } + + AlgorithmIdentifier sigAlgId = signer.getAlgorithmIdentifier(); + + DERSequence chainSeq = null; + if (chain != null && chain.length > 0) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != chain.length; i++) + { + v.add(chain[i].toASN1Structure()); + } + + chainSeq = new DERSequence(v); + } + + return new BasicOCSPResp(new BasicOCSPResponse(tbsResp, sigAlgId, bitSig, chainSeq)); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateID.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateID.java new file mode 100644 index 0000000..aa97f19 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateID.java @@ -0,0 +1,156 @@ +package org.bouncycastle.cert.ocsp; + +import java.io.OutputStream; +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.ocsp.CertID; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.operator.DigestCalculator; +import org.bouncycastle.operator.DigestCalculatorProvider; +import org.bouncycastle.operator.OperatorCreationException; + +public class CertificateID +{ + public static final AlgorithmIdentifier HASH_SHA1 = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + + private final CertID id; + + public CertificateID( + CertID id) + { + if (id == null) + { + throw new IllegalArgumentException("'id' cannot be null"); + } + this.id = id; + } + + /** + * create from an issuer certificate and the serial number of the + * certificate it signed. + * + * @param issuerCert issuing certificate + * @param number serial number + * + * @exception OCSPException if any problems occur creating the id fields. + */ + public CertificateID( + DigestCalculator digestCalculator, X509CertificateHolder issuerCert, + BigInteger number) + throws OCSPException + { + this.id = createCertID(digestCalculator, issuerCert, new ASN1Integer(number)); + } + + public ASN1ObjectIdentifier getHashAlgOID() + { + return id.getHashAlgorithm().getAlgorithm(); + } + + public byte[] getIssuerNameHash() + { + return id.getIssuerNameHash().getOctets(); + } + + public byte[] getIssuerKeyHash() + { + return id.getIssuerKeyHash().getOctets(); + } + + /** + * return the serial number for the certificate associated + * with this request. + */ + public BigInteger getSerialNumber() + { + return id.getSerialNumber().getValue(); + } + + public boolean matchesIssuer(X509CertificateHolder issuerCert, DigestCalculatorProvider digCalcProvider) + throws OCSPException + { + try + { + return createCertID(digCalcProvider.get(id.getHashAlgorithm()), issuerCert, id.getSerialNumber()).equals(id); + } + catch (OperatorCreationException e) + { + throw new OCSPException("unable to create digest calculator: " + e.getMessage(), e); + } + } + + public CertID toASN1Primitive() + { + return id; + } + + public boolean equals( + Object o) + { + if (!(o instanceof CertificateID)) + { + return false; + } + + CertificateID obj = (CertificateID)o; + + return id.toASN1Primitive().equals(obj.id.toASN1Primitive()); + } + + public int hashCode() + { + return id.toASN1Primitive().hashCode(); + } + + /** + * Create a new CertificateID for a new serial number derived from a previous one + * calculated for the same CA certificate. + * + * @param original the previously calculated CertificateID for the CA. + * @param newSerialNumber the serial number for the new certificate of interest. + * + * @return a new CertificateID for newSerialNumber + */ + public static CertificateID deriveCertificateID(CertificateID original, BigInteger newSerialNumber) + { + return new CertificateID(new CertID(original.id.getHashAlgorithm(), original.id.getIssuerNameHash(), original.id.getIssuerKeyHash(), new ASN1Integer(newSerialNumber))); + } + + private static CertID createCertID(DigestCalculator digCalc, X509CertificateHolder issuerCert, ASN1Integer serialNumber) + throws OCSPException + { + try + { + OutputStream dgOut = digCalc.getOutputStream(); + + dgOut.write(issuerCert.toASN1Structure().getSubject().getEncoded(ASN1Encoding.DER)); + dgOut.close(); + + ASN1OctetString issuerNameHash = new DEROctetString(digCalc.getDigest()); + + SubjectPublicKeyInfo info = issuerCert.getSubjectPublicKeyInfo(); + + dgOut = digCalc.getOutputStream(); + + dgOut.write(info.getPublicKeyData().getBytes()); + dgOut.close(); + + ASN1OctetString issuerKeyHash = new DEROctetString(digCalc.getDigest()); + + return new CertID(digCalc.getAlgorithmIdentifier(), issuerNameHash, issuerKeyHash, serialNumber); + } + catch (Exception e) + { + throw new OCSPException("problem creating ID: " + e, e); + } + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateStatus.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateStatus.java new file mode 100644 index 0000000..3aa117d --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/CertificateStatus.java @@ -0,0 +1,6 @@ +package org.bouncycastle.cert.ocsp; + +public interface CertificateStatus +{ + public static final CertificateStatus GOOD = null; +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPException.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPException.java new file mode 100644 index 0000000..6489788 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPException.java @@ -0,0 +1,27 @@ +package org.bouncycastle.cert.ocsp; + +public class OCSPException + extends Exception +{ + private Throwable cause; + + public OCSPException( + String name) + { + super(name); + } + + public OCSPException( + String name, + Throwable cause) + { + super(name); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java new file mode 100644 index 0000000..437d37b --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReq.java @@ -0,0 +1,259 @@ +package org.bouncycastle.cert.ocsp; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Exception; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OutputStream; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ocsp.OCSPRequest; +import org.bouncycastle.asn1.ocsp.Request; +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.cert.CertIOException; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.operator.ContentVerifier; +import org.bouncycastle.operator.ContentVerifierProvider; + +/** + *
+ * OCSPRequest     ::=     SEQUENCE {
+ *       tbsRequest                  TBSRequest,
+ *       optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+ *
+ *   TBSRequest      ::=     SEQUENCE {
+ *       version             [0]     EXPLICIT Version DEFAULT v1,
+ *       requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
+ *       requestList                 SEQUENCE OF Request,
+ *       requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
+ *
+ *   Signature       ::=     SEQUENCE {
+ *       signatureAlgorithm      AlgorithmIdentifier,
+ *       signature               BIT STRING,
+ *       certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
+ *
+ *   Version         ::=             INTEGER  {  v1(0) }
+ *
+ *   Request         ::=     SEQUENCE {
+ *       reqCert                     CertID,
+ *       singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
+ *
+ *   CertID          ::=     SEQUENCE {
+ *       hashAlgorithm       AlgorithmIdentifier,
+ *       issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
+ *       issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
+ *       serialNumber        CertificateSerialNumber }
+ * 
+ */ +public class OCSPReq +{ + private static final X509CertificateHolder[] EMPTY_CERTS = new X509CertificateHolder[0]; + + private OCSPRequest req; + private Extensions extensions; + + public OCSPReq( + OCSPRequest req) + { + this.req = req; + this.extensions = req.getTbsRequest().getRequestExtensions(); + } + + public OCSPReq( + byte[] req) + throws IOException + { + this(new ASN1InputStream(req)); + } + + private OCSPReq( + ASN1InputStream aIn) + throws IOException + { + try + { + this.req = OCSPRequest.getInstance(aIn.readObject()); + if (req == null) + { + throw new CertIOException("malformed request: no request data found"); + } + this.extensions = req.getTbsRequest().getRequestExtensions(); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed request: " + e.getMessage(), e); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed request: " + e.getMessage(), e); + } + catch (ASN1Exception e) + { + throw new CertIOException("malformed request: " + e.getMessage(), e); + } + } + + public int getVersionNumber() + { + return req.getTbsRequest().getVersion().getValue().intValue() + 1; + } + + public GeneralName getRequestorName() + { + return GeneralName.getInstance(req.getTbsRequest().getRequestorName()); + } + + public Req[] getRequestList() + { + ASN1Sequence seq = req.getTbsRequest().getRequestList(); + Req[] requests = new Req[seq.size()]; + + for (int i = 0; i != requests.length; i++) + { + requests[i] = new Req(Request.getInstance(seq.getObjectAt(i))); + } + + return requests; + } + + public boolean hasExtensions() + { + return extensions != null; + } + + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + public List getExtensionOIDs() + { + return OCSPUtils.getExtensionOIDs(extensions); + } + + public Set getCriticalExtensionOIDs() + { + return OCSPUtils.getCriticalExtensionOIDs(extensions); + } + + public Set getNonCriticalExtensionOIDs() + { + return OCSPUtils.getNonCriticalExtensionOIDs(extensions); + } + + /** + * return the object identifier representing the signature algorithm + */ + public ASN1ObjectIdentifier getSignatureAlgOID() + { + if (!this.isSigned()) + { + return null; + } + + return req.getOptionalSignature().getSignatureAlgorithm().getAlgorithm(); + } + + public byte[] getSignature() + { + if (!this.isSigned()) + { + return null; + } + + return req.getOptionalSignature().getSignature().getOctets(); + } + + public X509CertificateHolder[] getCerts() + { + // + // load the certificates if we have any + // + if (req.getOptionalSignature() != null) + { + ASN1Sequence s = req.getOptionalSignature().getCerts(); + + if (s != null) + { + X509CertificateHolder[] certs = new X509CertificateHolder[s.size()]; + + for (int i = 0; i != certs.length; i++) + { + certs[i] = new X509CertificateHolder(Certificate.getInstance(s.getObjectAt(i))); + } + + return certs; + } + + return EMPTY_CERTS; + } + else + { + return EMPTY_CERTS; + } + } + + /** + * Return whether or not this request is signed. + * + * @return true if signed false otherwise. + */ + public boolean isSigned() + { + return req.getOptionalSignature() != null; + } + + /** + * verify the signature against the TBSRequest object we contain. + */ + public boolean isSignatureValid( + ContentVerifierProvider verifierProvider) + throws OCSPException + { + if (!this.isSigned()) + { + throw new OCSPException("attempt to verify signature on unsigned object"); + } + + try + { + ContentVerifier verifier = verifierProvider.get(req.getOptionalSignature().getSignatureAlgorithm()); + OutputStream sOut = verifier.getOutputStream(); + + sOut.write(req.getTbsRequest().getEncoded(ASN1Encoding.DER)); + + return verifier.verify(this.getSignature()); + } + catch (Exception e) + { + throw new OCSPException("exception processing signature: " + e, e); + } + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + aOut.writeObject(req); + + return bOut.toByteArray(); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java new file mode 100644 index 0000000..b0cfb9e --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java @@ -0,0 +1,199 @@ +package org.bouncycastle.cert.ocsp; + +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.ocsp.OCSPRequest; +import org.bouncycastle.asn1.ocsp.Request; +import org.bouncycastle.asn1.ocsp.Signature; +import org.bouncycastle.asn1.ocsp.TBSRequest; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.operator.ContentSigner; + +public class OCSPReqBuilder +{ + private List list = new ArrayList(); + private GeneralName requestorName = null; + private Extensions requestExtensions = null; + + private class RequestObject + { + CertificateID certId; + Extensions extensions; + + public RequestObject( + CertificateID certId, + Extensions extensions) + { + this.certId = certId; + this.extensions = extensions; + } + + public Request toRequest() + throws Exception + { + return new Request(certId.toASN1Primitive(), extensions); + } + } + + /** + * Add a request for the given CertificateID. + * + * @param certId certificate ID of interest + */ + public OCSPReqBuilder addRequest( + CertificateID certId) + { + list.add(new RequestObject(certId, null)); + + return this; + } + + /** + * Add a request with extensions + * + * @param certId certificate ID of interest + * @param singleRequestExtensions the extensions to attach to the request + */ + public OCSPReqBuilder addRequest( + CertificateID certId, + Extensions singleRequestExtensions) + { + list.add(new RequestObject(certId, singleRequestExtensions)); + + return this; + } + + /** + * Set the requestor name to the passed in X500Principal + * + * @param requestorName a X500Principal representing the requestor name. + */ + public OCSPReqBuilder setRequestorName( + X500Name requestorName) + { + this.requestorName = new GeneralName(GeneralName.directoryName, requestorName); + + return this; + } + + public OCSPReqBuilder setRequestorName( + GeneralName requestorName) + { + this.requestorName = requestorName; + + return this; + } + + public OCSPReqBuilder setRequestExtensions( + Extensions requestExtensions) + { + this.requestExtensions = requestExtensions; + + return this; + } + + private OCSPReq generateRequest( + ContentSigner contentSigner, + X509CertificateHolder[] chain) + throws OCSPException + { + Iterator it = list.iterator(); + + ASN1EncodableVector requests = new ASN1EncodableVector(); + + while (it.hasNext()) + { + try + { + requests.add(((RequestObject)it.next()).toRequest()); + } + catch (Exception e) + { + throw new OCSPException("exception creating Request", e); + } + } + + TBSRequest tbsReq = new TBSRequest(requestorName, new DERSequence(requests), requestExtensions); + + Signature signature = null; + + if (contentSigner != null) + { + if (requestorName == null) + { + throw new OCSPException("requestorName must be specified if request is signed."); + } + + try + { + OutputStream sOut = contentSigner.getOutputStream(); + + sOut.write(tbsReq.getEncoded(ASN1Encoding.DER)); + + sOut.close(); + } + catch (Exception e) + { + throw new OCSPException("exception processing TBSRequest: " + e, e); + } + + DERBitString bitSig = new DERBitString(contentSigner.getSignature()); + + AlgorithmIdentifier sigAlgId = contentSigner.getAlgorithmIdentifier(); + + if (chain != null && chain.length > 0) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (int i = 0; i != chain.length; i++) + { + v.add(chain[i].toASN1Structure()); + } + + signature = new Signature(sigAlgId, bitSig, new DERSequence(v)); + } + else + { + signature = new Signature(sigAlgId, bitSig); + } + } + + return new OCSPReq(new OCSPRequest(tbsReq, signature)); + } + + /** + * Generate an unsigned request + * + * @return the OCSPReq + * @throws org.bouncycastle.ocsp.OCSPException + */ + public OCSPReq build() + throws OCSPException + { + return generateRequest(null, null); + } + + public OCSPReq build( + ContentSigner signer, + X509CertificateHolder[] chain) + throws OCSPException, IllegalArgumentException + { + if (signer == null) + { + throw new IllegalArgumentException("no signer specified"); + } + + return generateRequest(signer, chain); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java new file mode 100644 index 0000000..ed3918a --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPResp.java @@ -0,0 +1,141 @@ +package org.bouncycastle.cert.ocsp; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.asn1.ASN1Exception; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ocsp.BasicOCSPResponse; +import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; +import org.bouncycastle.asn1.ocsp.OCSPResponse; +import org.bouncycastle.asn1.ocsp.ResponseBytes; +import org.bouncycastle.cert.CertIOException; + +public class OCSPResp +{ + public static final int SUCCESSFUL = 0; // Response has valid confirmations + public static final int MALFORMED_REQUEST = 1; // Illegal confirmation request + public static final int INTERNAL_ERROR = 2; // Internal error in issuer + public static final int TRY_LATER = 3; // Try again later + // (4) is not used + public static final int SIG_REQUIRED = 5; // Must sign the request + public static final int UNAUTHORIZED = 6; // Request unauthorized + + private OCSPResponse resp; + + public OCSPResp( + OCSPResponse resp) + { + this.resp = resp; + } + + public OCSPResp( + byte[] resp) + throws IOException + { + this(new ByteArrayInputStream(resp)); + } + + public OCSPResp( + InputStream resp) + throws IOException + { + this(new ASN1InputStream(resp)); + } + + private OCSPResp( + ASN1InputStream aIn) + throws IOException + { + try + { + this.resp = OCSPResponse.getInstance(aIn.readObject()); + } + catch (IllegalArgumentException e) + { + throw new CertIOException("malformed response: " + e.getMessage(), e); + } + catch (ClassCastException e) + { + throw new CertIOException("malformed response: " + e.getMessage(), e); + } + catch (ASN1Exception e) + { + throw new CertIOException("malformed response: " + e.getMessage(), e); + } + + if (resp == null) + { + throw new CertIOException("malformed response: no response data found"); + } + } + + public int getStatus() + { + return this.resp.getResponseStatus().getValue().intValue(); + } + + public Object getResponseObject() + throws OCSPException + { + ResponseBytes rb = this.resp.getResponseBytes(); + + if (rb == null) + { + return null; + } + + if (rb.getResponseType().equals(OCSPObjectIdentifiers.id_pkix_ocsp_basic)) + { + try + { + ASN1Primitive obj = ASN1Primitive.fromByteArray(rb.getResponse().getOctets()); + return new BasicOCSPResp(BasicOCSPResponse.getInstance(obj)); + } + catch (Exception e) + { + throw new OCSPException("problem decoding object: " + e, e); + } + } + + return rb.getResponse(); + } + + /** + * return the ASN.1 encoded representation of this object. + */ + public byte[] getEncoded() + throws IOException + { + return resp.getEncoded(); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof OCSPResp)) + { + return false; + } + + OCSPResp r = (OCSPResp)o; + + return resp.equals(r.resp); + } + + public int hashCode() + { + return resp.hashCode(); + } + + public OCSPResponse toASN1Structure() + { + return resp; + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPRespBuilder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPRespBuilder.java new file mode 100644 index 0000000..c372ebf --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPRespBuilder.java @@ -0,0 +1,59 @@ +package org.bouncycastle.cert.ocsp; + +import java.io.IOException; + +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; +import org.bouncycastle.asn1.ocsp.OCSPResponse; +import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; +import org.bouncycastle.asn1.ocsp.ResponseBytes; + +/** + * base generator for an OCSP response - at the moment this only supports the + * generation of responses containing BasicOCSP responses. + */ +public class OCSPRespBuilder +{ + public static final int SUCCESSFUL = 0; // Response has valid confirmations + public static final int MALFORMED_REQUEST = 1; // Illegal confirmation request + public static final int INTERNAL_ERROR = 2; // Internal error in issuer + public static final int TRY_LATER = 3; // Try again later + // (4) is not used + public static final int SIG_REQUIRED = 5; // Must sign the request + public static final int UNAUTHORIZED = 6; // Request unauthorized + + public OCSPResp build( + int status, + Object response) + throws OCSPException + { + if (response == null) + { + return new OCSPResp(new OCSPResponse(new OCSPResponseStatus(status), null)); + } + + if (response instanceof BasicOCSPResp) + { + BasicOCSPResp r = (BasicOCSPResp)response; + ASN1OctetString octs; + + try + { + octs = new DEROctetString(r.getEncoded()); + } + catch (IOException e) + { + throw new OCSPException("can't encode object.", e); + } + + ResponseBytes rb = new ResponseBytes( + OCSPObjectIdentifiers.id_pkix_ocsp_basic, octs); + + return new OCSPResp(new OCSPResponse( + new OCSPResponseStatus(status), rb)); + } + + throw new OCSPException("unknown response object"); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPUtils.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPUtils.java new file mode 100644 index 0000000..a84f409 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPUtils.java @@ -0,0 +1,64 @@ +package org.bouncycastle.cert.ocsp; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.cert.X509CertificateHolder; + +class OCSPUtils +{ + static final X509CertificateHolder[] EMPTY_CERTS = new X509CertificateHolder[0]; + + static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet()); + static List EMPTY_LIST = Collections.unmodifiableList(new ArrayList()); + + static Date extractDate(ASN1GeneralizedTime time) + { + try + { + return time.getDate(); + } + catch (Exception e) + { + throw new IllegalStateException("exception processing GeneralizedTime: " + e.getMessage()); + } + } + + static Set getCriticalExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_SET; + } + + return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getCriticalExtensionOIDs()))); + } + + static Set getNonCriticalExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_SET; + } + + // TODO: should probably produce a set that imposes correct ordering + return Collections.unmodifiableSet(new HashSet(Arrays.asList(extensions.getNonCriticalExtensionOIDs()))); + } + + static List getExtensionOIDs(Extensions extensions) + { + if (extensions == null) + { + return EMPTY_LIST; + } + + return Collections.unmodifiableList(Arrays.asList(extensions.getExtensionOIDs())); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/Req.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/Req.java new file mode 100644 index 0000000..6df083c --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/Req.java @@ -0,0 +1,25 @@ +package org.bouncycastle.cert.ocsp; + +import org.bouncycastle.asn1.ocsp.Request; +import org.bouncycastle.asn1.x509.Extensions; + +public class Req +{ + private Request req; + + public Req( + Request req) + { + this.req = req; + } + + public CertificateID getCertID() + { + return new CertificateID(req.getReqCert()); + } + + public Extensions getSingleRequestExtensions() + { + return req.getSingleRequestExtensions(); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespData.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespData.java new file mode 100644 index 0000000..6960fa8 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespData.java @@ -0,0 +1,52 @@ +package org.bouncycastle.cert.ocsp; + +import java.util.Date; + +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ocsp.ResponseData; +import org.bouncycastle.asn1.ocsp.SingleResponse; +import org.bouncycastle.asn1.x509.Extensions; + +public class RespData +{ + private ResponseData data; + + public RespData( + ResponseData data) + { + this.data = data; + } + + public int getVersion() + { + return data.getVersion().getValue().intValue() + 1; + } + + public RespID getResponderId() + { + return new RespID(data.getResponderID()); + } + + public Date getProducedAt() + { + return OCSPUtils.extractDate(data.getProducedAt()); + } + + public SingleResp[] getResponses() + { + ASN1Sequence s = data.getResponses(); + SingleResp[] rs = new SingleResp[s.size()]; + + for (int i = 0; i != rs.length; i++) + { + rs[i] = new SingleResp(SingleResponse.getInstance(s.getObjectAt(i))); + } + + return rs; + } + + public Extensions getResponseExtensions() + { + return data.getResponseExtensions(); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java new file mode 100644 index 0000000..a0fd765 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RespID.java @@ -0,0 +1,89 @@ +package org.bouncycastle.cert.ocsp; + +import java.io.OutputStream; + +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.ocsp.ResponderID; +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.operator.DigestCalculator; + +/** + * Carrier for a ResponderID. + */ +public class RespID +{ + public static final AlgorithmIdentifier HASH_SHA1 = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + + ResponderID id; + + public RespID( + ResponderID id) + { + this.id = id; + } + + public RespID( + X500Name name) + { + this.id = new ResponderID(name); + } + + /** + * Calculate a RespID based on the public key of the responder. + * + * @param subjectPublicKeyInfo the info structure for the responder public key. + * @param digCalc a SHA-1 digest calculator. + * @throws OCSPException on exception creating ID. + */ + public RespID( + SubjectPublicKeyInfo subjectPublicKeyInfo, + DigestCalculator digCalc) + throws OCSPException + { + try + { + if (!digCalc.getAlgorithmIdentifier().equals(HASH_SHA1)) + { + throw new IllegalArgumentException("only SHA-1 can be used with RespID"); + } + + OutputStream digOut = digCalc.getOutputStream(); + + digOut.write(subjectPublicKeyInfo.getPublicKeyData().getBytes()); + digOut.close(); + + this.id = new ResponderID(new DEROctetString(digCalc.getDigest())); + } + catch (Exception e) + { + throw new OCSPException("problem creating ID: " + e, e); + } + } + + public ResponderID toASN1Primitive() + { + return id; + } + + public boolean equals( + Object o) + { + if (!(o instanceof RespID)) + { + return false; + } + + RespID obj = (RespID)o; + + return id.equals(obj.id); + } + + public int hashCode() + { + return id.hashCode(); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RevokedStatus.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RevokedStatus.java new file mode 100644 index 0000000..d349f07 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/RevokedStatus.java @@ -0,0 +1,55 @@ +package org.bouncycastle.cert.ocsp; + +import java.util.Date; + +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ocsp.RevokedInfo; +import org.bouncycastle.asn1.x509.CRLReason; + +/** + * wrapper for the RevokedInfo object + */ +public class RevokedStatus + implements CertificateStatus +{ + RevokedInfo info; + + public RevokedStatus( + RevokedInfo info) + { + this.info = info; + } + + public RevokedStatus( + Date revocationDate, + int reason) + { + this.info = new RevokedInfo(new ASN1GeneralizedTime(revocationDate), CRLReason.lookup(reason)); + } + + public Date getRevocationTime() + { + return OCSPUtils.extractDate(info.getRevocationTime()); + } + + public boolean hasRevocationReason() + { + return (info.getRevocationReason() != null); + } + + /** + * return the revocation reason. Note: this field is optional, test for it + * with hasRevocationReason() first. + * @return the revocation reason value. + * @exception IllegalStateException if a reason is asked for and none is avaliable + */ + public int getRevocationReason() + { + if (info.getRevocationReason() == null) + { + throw new IllegalStateException("attempt to get a reason where none is available"); + } + + return info.getRevocationReason().getValue().intValue(); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/SingleResp.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/SingleResp.java new file mode 100644 index 0000000..ece7ea2 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/SingleResp.java @@ -0,0 +1,102 @@ +package org.bouncycastle.cert.ocsp; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ocsp.CertStatus; +import org.bouncycastle.asn1.ocsp.RevokedInfo; +import org.bouncycastle.asn1.ocsp.SingleResponse; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; + +public class SingleResp +{ + private SingleResponse resp; + private Extensions extensions; + + public SingleResp( + SingleResponse resp) + { + this.resp = resp; + this.extensions = resp.getSingleExtensions(); + } + + public CertificateID getCertID() + { + return new CertificateID(resp.getCertID()); + } + + /** + * Return the status object for the response - null indicates good. + * + * @return the status object for the response, null if it is good. + */ + public CertificateStatus getCertStatus() + { + CertStatus s = resp.getCertStatus(); + + if (s.getTagNo() == 0) + { + return null; // good + } + else if (s.getTagNo() == 1) + { + return new RevokedStatus(RevokedInfo.getInstance(s.getStatus())); + } + + return new UnknownStatus(); + } + + public Date getThisUpdate() + { + return OCSPUtils.extractDate(resp.getThisUpdate()); + } + + /** + * return the NextUpdate value - note: this is an optional field so may + * be returned as null. + * + * @return nextUpdate, or null if not present. + */ + public Date getNextUpdate() + { + if (resp.getNextUpdate() == null) + { + return null; + } + + return OCSPUtils.extractDate(resp.getNextUpdate()); + } + + public boolean hasExtensions() + { + return extensions != null; + } + + public Extension getExtension(ASN1ObjectIdentifier oid) + { + if (extensions != null) + { + return extensions.getExtension(oid); + } + + return null; + } + + public List getExtensionOIDs() + { + return OCSPUtils.getExtensionOIDs(extensions); + } + + public Set getCriticalExtensionOIDs() + { + return OCSPUtils.getCriticalExtensionOIDs(extensions); + } + + public Set getNonCriticalExtensionOIDs() + { + return OCSPUtils.getNonCriticalExtensionOIDs(extensions); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/UnknownStatus.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/UnknownStatus.java new file mode 100644 index 0000000..8d60e2b --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/UnknownStatus.java @@ -0,0 +1,12 @@ +package org.bouncycastle.cert.ocsp; + +/** + * wrapper for the UnknownInfo object + */ +public class UnknownStatus + implements CertificateStatus +{ + public UnknownStatus() + { + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java new file mode 100644 index 0000000..94bf52f --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaBasicOCSPRespBuilder.java @@ -0,0 +1,18 @@ +package org.bouncycastle.cert.ocsp.jcajce; + +import java.security.PublicKey; + +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder; +import org.bouncycastle.cert.ocsp.OCSPException; +import org.bouncycastle.operator.DigestCalculator; + +public class JcaBasicOCSPRespBuilder + extends BasicOCSPRespBuilder +{ + public JcaBasicOCSPRespBuilder(PublicKey key, DigestCalculator digCalc) + throws OCSPException + { + super(SubjectPublicKeyInfo.getInstance(key.getEncoded()), digCalc); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaCertificateID.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaCertificateID.java new file mode 100644 index 0000000..446b38b --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaCertificateID.java @@ -0,0 +1,20 @@ +package org.bouncycastle.cert.ocsp.jcajce; + +import java.math.BigInteger; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; +import org.bouncycastle.cert.ocsp.CertificateID; +import org.bouncycastle.cert.ocsp.OCSPException; +import org.bouncycastle.operator.DigestCalculator; + +public class JcaCertificateID + extends CertificateID +{ + public JcaCertificateID(DigestCalculator digestCalculator, X509Certificate issuerCert, BigInteger number) + throws OCSPException, CertificateEncodingException + { + super(digestCalculator, new JcaX509CertificateHolder(issuerCert), number); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaRespID.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaRespID.java new file mode 100644 index 0000000..8bc9edb --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/JcaRespID.java @@ -0,0 +1,26 @@ +package org.bouncycastle.cert.ocsp.jcajce; + +import java.security.PublicKey; + +import javax.security.auth.x500.X500Principal; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.ocsp.OCSPException; +import org.bouncycastle.cert.ocsp.RespID; +import org.bouncycastle.operator.DigestCalculator; + +public class JcaRespID + extends RespID +{ + public JcaRespID(X500Principal name) + { + super(X500Name.getInstance(name.getEncoded())); + } + + public JcaRespID(PublicKey pubKey, DigestCalculator digCalc) + throws OCSPException + { + super(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()), digCalc); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/package.html b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/package.html new file mode 100644 index 0000000..cfe87f2 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/ocsp/jcajce/package.html @@ -0,0 +1,7 @@ + + + +JCA extensions to the OCSP online certificate status package. + + \ No newline at end of file diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java index 3f4e22c..8f6d119 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java @@ -4,14 +4,16 @@ import java.io.IOException; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.util.Pack; class MSOutlookKeyIdCalculator { + // This is less than ideal, but it seems to be the best way of supporting this without exposing SHA-1 + // as the class is only used to workout the MSOutlook Key ID, you can think of the fact it's SHA-1 as + // a coincidence... static byte[] calculateKeyId(SubjectPublicKeyInfo info) { - Digest dig = new SHA1Digest(); // TODO: include definition of SHA-1 here + SHA1Digest dig = new SHA1Digest(); byte[] hash = new byte[dig.getDigestSize()]; byte[] spkiEnc = new byte[0]; try @@ -30,4 +32,391 @@ class MSOutlookKeyIdCalculator return hash; } + + private static abstract class GeneralDigest + { + private static final int BYTE_LENGTH = 64; + private byte[] xBuf; + private int xBufOff; + + private long byteCount; + + /** + * Standard constructor + */ + protected GeneralDigest() + { + xBuf = new byte[4]; + xBufOff = 0; + } + + /** + * Copy constructor. We are using copy constructors in place + * of the Object.clone() interface as this interface is not + * supported by J2ME. + */ + protected GeneralDigest(GeneralDigest t) + { + xBuf = new byte[t.xBuf.length]; + + copyIn(t); + } + + protected void copyIn(GeneralDigest t) + { + System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length); + + xBufOff = t.xBufOff; + byteCount = t.byteCount; + } + + public void update( + byte in) + { + xBuf[xBufOff++] = in; + + if (xBufOff == xBuf.length) + { + processWord(xBuf, 0); + xBufOff = 0; + } + + byteCount++; + } + + public void update( + byte[] in, + int inOff, + int len) + { + // + // fill the current word + // + while ((xBufOff != 0) && (len > 0)) + { + update(in[inOff]); + + inOff++; + len--; + } + + // + // process whole words. + // + while (len > xBuf.length) + { + processWord(in, inOff); + + inOff += xBuf.length; + len -= xBuf.length; + byteCount += xBuf.length; + } + + // + // load in the remainder. + // + while (len > 0) + { + update(in[inOff]); + + inOff++; + len--; + } + } + + public void finish() + { + long bitLength = (byteCount << 3); + + // + // add the pad bytes. + // + update((byte)128); + + while (xBufOff != 0) + { + update((byte)0); + } + + processLength(bitLength); + + processBlock(); + } + + public void reset() + { + byteCount = 0; + + xBufOff = 0; + for (int i = 0; i < xBuf.length; i++) + { + xBuf[i] = 0; + } + } + + protected abstract void processWord(byte[] in, int inOff); + + protected abstract void processLength(long bitLength); + + protected abstract void processBlock(); + } + + private static class SHA1Digest + extends GeneralDigest + { + private static final int DIGEST_LENGTH = 20; + + private int H1, H2, H3, H4, H5; + + private int[] X = new int[80]; + private int xOff; + + /** + * Standard constructor + */ + public SHA1Digest() + { + reset(); + } + + public String getAlgorithmName() + { + return "SHA-1"; + } + + public int getDigestSize() + { + return DIGEST_LENGTH; + } + + protected void processWord( + byte[] in, + int inOff) + { + // Note: Inlined for performance + // X[xOff] = Pack.bigEndianToInt(in, inOff); + int n = in[ inOff] << 24; + n |= (in[++inOff] & 0xff) << 16; + n |= (in[++inOff] & 0xff) << 8; + n |= (in[++inOff] & 0xff); + X[xOff] = n; + + if (++xOff == 16) + { + processBlock(); + } + } + + protected void processLength( + long bitLength) + { + if (xOff > 14) + { + processBlock(); + } + + X[14] = (int)(bitLength >>> 32); + X[15] = (int)(bitLength & 0xffffffff); + } + + public int doFinal( + byte[] out, + int outOff) + { + finish(); + + Pack.intToBigEndian(H1, out, outOff); + Pack.intToBigEndian(H2, out, outOff + 4); + Pack.intToBigEndian(H3, out, outOff + 8); + Pack.intToBigEndian(H4, out, outOff + 12); + Pack.intToBigEndian(H5, out, outOff + 16); + + reset(); + + return DIGEST_LENGTH; + } + + /** + * reset the chaining variables + */ + public void reset() + { + super.reset(); + + H1 = 0x67452301; + H2 = 0xefcdab89; + H3 = 0x98badcfe; + H4 = 0x10325476; + H5 = 0xc3d2e1f0; + + xOff = 0; + for (int i = 0; i != X.length; i++) + { + X[i] = 0; + } + } + + // + // Additive constants + // + private static final int Y1 = 0x5a827999; + private static final int Y2 = 0x6ed9eba1; + private static final int Y3 = 0x8f1bbcdc; + private static final int Y4 = 0xca62c1d6; + + private int f( + int u, + int v, + int w) + { + return ((u & v) | ((~u) & w)); + } + + private int h( + int u, + int v, + int w) + { + return (u ^ v ^ w); + } + + private int g( + int u, + int v, + int w) + { + return ((u & v) | (u & w) | (v & w)); + } + + protected void processBlock() + { + // + // expand 16 word block into 80 word block. + // + for (int i = 16; i < 80; i++) + { + int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]; + X[i] = t << 1 | t >>> 31; + } + + // + // set up working variables. + // + int A = H1; + int B = H2; + int C = H3; + int D = H4; + int E = H5; + + // + // round 1 + // + int idx = 0; + + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1; + C = C << 30 | C >>> 2; + } + + // + // round 2 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2; + C = C << 30 | C >>> 2; + } + + // + // round 3 + // + for (int j = 0; j < 4; j++) + { + // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3; + C = C << 30 | C >>> 2; + } + + // + // round 4 + // + for (int j = 0; j <= 3; j++) + { + // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4 + // B = rotateLeft(B, 30) + E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4; + B = B << 30 | B >>> 2; + + D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4; + A = A << 30 | A >>> 2; + + C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4; + E = E << 30 | E >>> 2; + + B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4; + D = D << 30 | D >>> 2; + + A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4; + C = C << 30 | C >>> 2; + } + + + H1 += A; + H2 += B; + H3 += C; + H4 += D; + H5 += E; + + // + // reset start of the buffer. + // + xOff = 0; + for (int i = 0; i < 16; i++) + { + X[i] = 0; + } + } + } } diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerator.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerator.java index 528c738..a38752c 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerator.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSAttributeTableGenerator.java @@ -1,18 +1,20 @@ package org.bouncycastle.cms; -import org.bouncycastle.asn1.cms.AttributeTable; - import java.util.Map; +import org.bouncycastle.asn1.cms.AttributeTable; + /** * Note: The SIGNATURE parameter is only available when generating unsigned attributes. */ public interface CMSAttributeTableGenerator { - static final String CONTENT_TYPE = "contentType"; - static final String DIGEST = "digest"; - static final String SIGNATURE = "encryptedDigest"; - static final String DIGEST_ALGORITHM_IDENTIFIER = "digestAlgID"; + String CONTENT_TYPE = "contentType"; + String DIGEST = "digest"; + String SIGNATURE = "encryptedDigest"; + String DIGEST_ALGORITHM_IDENTIFIER = "digestAlgID"; + String MAC_ALGORITHM_IDENTIFIER = "macAlgID"; + String SIGNATURE_ALGORITHM_IDENTIFIER = "signatureAlgID"; AttributeTable getAttributes(Map parameters) throws CMSAttributeTableGenerationException; diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java index 0c52082..7f6d4a2 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedData.java @@ -5,10 +5,15 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; +import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; @@ -20,9 +25,9 @@ import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.cms.ContentInfo; import org.bouncycastle.asn1.cms.SignedData; import org.bouncycastle.asn1.cms.SignerInfo; -import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder; +import org.bouncycastle.util.Encodable; import org.bouncycastle.util.Store; /** @@ -54,6 +59,7 @@ import org.bouncycastle.util.Store; * */ public class CMSSignedData + implements Encodable { private static final CMSSignedHelper HELPER = CMSSignedHelper.INSTANCE; @@ -182,11 +188,18 @@ public class CMSSignedData // this can happen if the signed message is sent simply to send a // certificate chain. // - if (signedData.getEncapContentInfo().getContent() != null) + ASN1Encodable content = signedData.getEncapContentInfo().getContent(); + if (content != null) { - this.signedContent = new CMSProcessableByteArray(signedData.getEncapContentInfo().getContentType(), - ((ASN1OctetString)(signedData.getEncapContentInfo() - .getContent())).getOctets()); + if (content instanceof ASN1OctetString) + { + this.signedContent = new CMSProcessableByteArray(signedData.getEncapContentInfo().getContentType(), + ((ASN1OctetString)content).getOctets()); + } + else + { + this.signedContent = new PKCS7ProcessableObject(signedData.getEncapContentInfo().getContentType(), content); + } } else { @@ -229,7 +242,6 @@ public class CMSSignedData { ASN1Set s = signedData.getSignerInfos(); List signerInfos = new ArrayList(); - SignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder(); for (int i = 0; i != s.size(); i++) { @@ -255,6 +267,26 @@ public class CMSSignedData return signerInfoStore; } + /** + * Return if this is object represents a detached signature. + * + * @return true if this message represents a detached signature, false otherwise. + */ + public boolean isDetachedSignature() + { + return signedData.getEncapContentInfo().getContent() == null && signedData.getSignerInfos().size() > 0; + } + + /** + * Return if this is object represents a certificate management message. + * + * @return true if the message has no signers or content, false otherwise. + */ + public boolean isCertificateManagementMessage() + { + return signedData.getEncapContentInfo().getContent() == null && signedData.getSignerInfos().size() == 0; + } + /** * Return any X.509 certificate objects in this SignedData structure as a Store of X509CertificateHolder objects. * @@ -300,6 +332,23 @@ public class CMSSignedData // } // END android-removed + /** + * Return the digest algorithm identifiers for the SignedData object + * + * @return the set of digest algorithm identifiers + */ + public Set getDigestAlgorithmIDs() + { + Set digests = new HashSet(signedData.getDigestAlgorithms().size()); + + for (Enumeration en = signedData.getDigestAlgorithms().getObjects(); en.hasMoreElements();) + { + digests.add(AlgorithmIdentifier.getInstance(en.nextElement())); + } + + return Collections.unmodifiableSet(digests); + } + /** * Return the a string representation of the OID associated with the * encapsulated content info structure carried in the signed data. @@ -347,7 +396,7 @@ public class CMSSignedData // { // return verifySignatures(verifierProvider, false); // } - // + // // /** // * Verify all the SignerInformation objects and optionally their associated counter signatures attached // * to this CMS SignedData object. @@ -361,30 +410,27 @@ public class CMSSignedData // throws CMSException // { // Collection signers = this.getSignerInfos().getSigners(); - // + // // for (Iterator it = signers.iterator(); it.hasNext();) // { // SignerInformation signer = (SignerInformation)it.next(); - // + // // try // { // SignerInformationVerifier verifier = verifierProvider.get(signer.getSID()); - // + // // if (!signer.verify(verifier)) // { // return false; // } - // + // // if (!ignoreCounterSignatures) // { // Collection counterSigners = signer.getCounterSignatures().getSigners(); - // + // // for (Iterator cIt = counterSigners.iterator(); cIt.hasNext();) // { - // SignerInformation counterSigner = (SignerInformation)cIt.next(); - // SignerInformationVerifier counterVerifier = verifierProvider.get(signer.getSID()); - // - // if (!counterSigner.verify(counterVerifier)) + // if (!verifyCounterSignature((SignerInformation)cIt.next(), verifierProvider)) // { // return false; // } @@ -396,7 +442,29 @@ public class CMSSignedData // throw new CMSException("failure in verifier provider: " + e.getMessage(), e); // } // } - // + // + // return true; + // } + // + // private boolean verifyCounterSignature(SignerInformation counterSigner, SignerInformationVerifierProvider verifierProvider) + // throws OperatorCreationException, CMSException + // { + // SignerInformationVerifier counterVerifier = verifierProvider.get(counterSigner.getSID()); + // + // if (!counterSigner.verify(counterVerifier)) + // { + // return false; + // } + // + // Collection counterSigners = counterSigner.getCounterSignatures().getSigners(); + // for (Iterator cIt = counterSigners.iterator(); cIt.hasNext();) + // { + // if (!verifyCounterSignature((SignerInformation)cIt.next(), verifierProvider)) + // { + // return false; + // } + // } + // // return true; // } // END android-removed @@ -475,7 +543,7 @@ public class CMSSignedData * @param signedData the signed data object to be used as a base. * @param certificates the new certificates to be used. * @param attrCerts the new attribute certificates to be used. - * @param crls the new CRLs to be used. + * @param revocations the new CRLs to be used - a collection of X509CRLHolder objects, OtherRevocationInfoFormat, or both. * @return a new signed data object. * @exception CMSException if there is an error processing the CertStore */ @@ -483,7 +551,7 @@ public class CMSSignedData CMSSignedData signedData, Store certificates, Store attrCerts, - Store crls) + Store revocations) throws CMSException { // @@ -492,7 +560,7 @@ public class CMSSignedData CMSSignedData cms = new CMSSignedData(signedData); // - // replace the certs and crls in the SignedData object + // replace the certs and revocations in the SignedData object // ASN1Set certSet = null; ASN1Set crlSet = null; @@ -518,9 +586,9 @@ public class CMSSignedData } } - if (crls != null) + if (revocations != null) { - ASN1Set set = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(crls)); + ASN1Set set = CMSUtils.createBerSetFromList(CMSUtils.getCRLsFromStore(revocations)); if (set.size() != 0) { diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java index eea8a1a..5417ce4 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java @@ -140,7 +140,7 @@ public class CMSSignedDataGenerator ASN1OctetString octs = null; - if (content != null) + if (content.getContent() != null) { ByteArrayOutputStream bOut = null; diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSUtils.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSUtils.java index d6126b6..7dd16e0 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSUtils.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/CMSUtils.java @@ -5,16 +5,20 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.BEROctetStringGenerator; import org.bouncycastle.asn1.BERSet; +import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; @@ -23,18 +27,65 @@ import org.bouncycastle.asn1.cms.ContentInfo; // import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat; // import org.bouncycastle.asn1.ocsp.OCSPResponse; // import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; +// import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +// import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; // END android-removed +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.cert.X509AttributeCertificateHolder; import org.bouncycastle.cert.X509CRLHolder; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.operator.DigestCalculator; import org.bouncycastle.util.Store; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.TeeInputStream; import org.bouncycastle.util.io.TeeOutputStream; class CMSUtils { + private static final Set des = new HashSet(); + + static + { + des.add("DES"); + des.add("DESEDE"); + // BEGIN android-removed + // des.add(OIWObjectIdentifiers.desCBC.getId()); + // des.add(PKCSObjectIdentifiers.des_EDE3_CBC.getId()); + // des.add(PKCSObjectIdentifiers.des_EDE3_CBC.getId()); + // des.add(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); + // END android-removed + } + + static boolean isDES(String algorithmID) + { + String name = Strings.toUpperCase(algorithmID); + + return des.contains(name); + } + + static boolean isEquivalent(AlgorithmIdentifier algId1, AlgorithmIdentifier algId2) + { + if (algId1 == null || algId2 == null) + { + return false; + } + + if (!algId1.getAlgorithm().equals(algId2.getAlgorithm())) + { + return false; + } + + ASN1Encodable params1 = algId1.getParameters(); + ASN1Encodable params2 = algId2.getParameters(); + if (params1 != null) + { + return params1.equals(params2) || (params1.equals(DERNull.INSTANCE) && params2 == null); + } + + return params2 == null || params2.equals(DERNull.INSTANCE); + } + static ContentInfo readContentInfo( byte[] input) throws CMSException @@ -99,18 +150,37 @@ class CMSUtils static List getCRLsFromStore(Store crlStore) throws CMSException { - List certs = new ArrayList(); + List crls = new ArrayList(); try { for (Iterator it = crlStore.getMatches(null).iterator(); it.hasNext();) { - X509CRLHolder c = (X509CRLHolder)it.next(); - - certs.add(c.toASN1Structure()); + Object rev = it.next(); + + if (rev instanceof X509CRLHolder) + { + X509CRLHolder c = (X509CRLHolder)rev; + + crls.add(c.toASN1Structure()); + } + // BEGIN android-removed + // else if (rev instanceof OtherRevocationInfoFormat) + // { + // OtherRevocationInfoFormat infoFormat = OtherRevocationInfoFormat.getInstance(rev); + // + // validateInfoFormat(infoFormat); + // + // crls.add(new DERTaggedObject(false, 1, infoFormat)); + // } + // END android-removed + else if (rev instanceof ASN1TaggedObject) + { + crls.add(rev); + } } - return certs; + return crls; } catch (ClassCastException e) { @@ -119,6 +189,19 @@ class CMSUtils } // BEGIN android-removed + // private static void validateInfoFormat(OtherRevocationInfoFormat infoFormat) + // { + // if (CMSObjectIdentifiers.id_ri_ocsp_response.equals(infoFormat.getInfoFormat())) + // { + // OCSPResponse resp = OCSPResponse.getInstance(infoFormat.getInfo()); + // + // if (resp.getResponseStatus().getValue().intValue() != OCSPResponseStatus.SUCCESSFUL) + // { + // throw new IllegalArgumentException("cannot add unsuccessful OCSP response to CMS SignedData"); + // } + // } + // } + // // static Collection getOthersFromStore(ASN1ObjectIdentifier otherRevocationInfoFormat, Store otherRevocationInfos) // { // List others = new ArrayList(); @@ -126,18 +209,10 @@ class CMSUtils // for (Iterator it = otherRevocationInfos.getMatches(null).iterator(); it.hasNext();) // { // ASN1Encodable info = (ASN1Encodable)it.next(); + // OtherRevocationInfoFormat infoFormat = new OtherRevocationInfoFormat(otherRevocationInfoFormat, info); + // validateInfoFormat(infoFormat); // - // if (CMSObjectIdentifiers.id_ri_ocsp_response.equals(otherRevocationInfoFormat)) - // { - // OCSPResponse resp = OCSPResponse.getInstance(info); - // - // if (resp.getResponseStatus().getValue().intValue() != OCSPResponseStatus.SUCCESSFUL) - // { - // throw new IllegalArgumentException("cannot add unsuccessful OCSP response to CMS SignedData"); - // } - // } - // - // others.add(new DERTaggedObject(false, 1, new OtherRevocationInfoFormat(otherRevocationInfoFormat, info))); + // others.add(new DERTaggedObject(false, 1, infoFormat)); // } // // return others; @@ -202,7 +277,7 @@ class CMSUtils throw new CMSException("Malformed content.", e); } } - + public static byte[] streamToByteArray( InputStream in) throws IOException diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java index a9997a4..2230c78 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java @@ -5,6 +5,7 @@ import java.util.Map; import org.bouncycastle.asn1.ASN1ObjectIdentifier; // BEGIN android-removed +// import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; // END android-removed import org.bouncycastle.asn1.eac.EACObjectIdentifiers; @@ -51,6 +52,11 @@ public class DefaultCMSSignatureAlgorithmNameGenerator addEntries(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256", "RSA"); addEntries(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384", "RSA"); addEntries(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512", "RSA"); + + addEntries(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128, "RIPEMD128", "RSA"); + addEntries(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160, "RIPEMD160", "RSA"); + addEntries(TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256, "RIPEMD256", "RSA"); + addEntries(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1", "ECDSA"); addEntries(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224", "ECDSA"); addEntries(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256", "ECDSA"); @@ -66,6 +72,14 @@ public class DefaultCMSSignatureAlgorithmNameGenerator addEntries(EACObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256", "RSA"); addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1", "RSAandMGF1"); addEntries(EACObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256", "RSAandMGF1"); + // BEGIN android-removed + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA1, "SHA1", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA224, "SHA224", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA256, "SHA256", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA384, "SHA384", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_SHA512, "SHA512", "PLAIN-ECDSA"); + // addEntries(BSIObjectIdentifiers.ecdsa_plain_RIPEMD160, "RIPEMD160", "PLAIN-ECDSA"); + // END android-removed encryptionAlgs.put(X9ObjectIdentifiers.id_dsa, "DSA"); encryptionAlgs.put(PKCSObjectIdentifiers.rsaEncryption, "RSA"); @@ -159,6 +173,13 @@ public class DefaultCMSSignatureAlgorithmNameGenerator public String getSignatureName(AlgorithmIdentifier digestAlg, AlgorithmIdentifier encryptionAlg) { + String digestName = getDigestAlgName(encryptionAlg.getAlgorithm()); + + if (!digestName.equals(encryptionAlg.getAlgorithm().getId())) + { + return digestName + "with" + getEncryptionAlgName(encryptionAlg.getAlgorithm()); + } + return getDigestAlgName(digestAlg.getAlgorithm()) + "with" + getEncryptionAlgName(encryptionAlg.getAlgorithm()); } } diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java index 837edd8..ddfd2eb 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/DefaultSignedAttributeTableGenerator.java @@ -10,8 +10,10 @@ import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.cms.Attribute; import org.bouncycastle.asn1.cms.AttributeTable; +import org.bouncycastle.asn1.cms.CMSAlgorithmProtection; import org.bouncycastle.asn1.cms.CMSAttributes; import org.bouncycastle.asn1.cms.Time; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; /** * Default signed attributes generator. @@ -93,6 +95,14 @@ public class DefaultSignedAttributeTableGenerator std.put(attr.getAttrType(), attr); } + if (!std.contains(CMSAttributes.cmsAlgorithmProtect)) + { + Attribute attr = new Attribute(CMSAttributes.cmsAlgorithmProtect, new DERSet(new CMSAlgorithmProtection( + (AlgorithmIdentifier)parameters.get(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER), + CMSAlgorithmProtection.SIGNATURE, (AlgorithmIdentifier)parameters.get(CMSAttributeTableGenerator.SIGNATURE_ALGORITHM_IDENTIFIER)))); + std.put(attr.getAttrType(), attr); + } + return std; } diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/PKCS7ProcessableObject.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/PKCS7ProcessableObject.java new file mode 100644 index 0000000..077b2dc --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/PKCS7ProcessableObject.java @@ -0,0 +1,65 @@ +package org.bouncycastle.cms; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Iterator; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Sequence; + +public class PKCS7ProcessableObject + implements CMSTypedData +{ + private final ASN1ObjectIdentifier type; + private final ASN1Encodable structure; + + public PKCS7ProcessableObject( + ASN1ObjectIdentifier type, + ASN1Encodable structure) + { + this.type = type; + this.structure = structure; + } + + public ASN1ObjectIdentifier getContentType() + { + return type; + } + + public void write(OutputStream cOut) + throws IOException, CMSException + { + if (structure instanceof ASN1Sequence) + { + ASN1Sequence s = ASN1Sequence.getInstance(structure); + + for (Iterator it = s.iterator(); it.hasNext();) + { + ASN1Encodable enc = (ASN1Encodable)it.next(); + + cOut.write(enc.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + } + else + { + byte[] encoded = structure.toASN1Primitive().getEncoded(ASN1Encoding.DER); + int index = 1; + + while ((encoded[index] & 0xff) > 127) + { + index++; + } + + index++; + + cOut.write(encoded, index, encoded.length - index); + } + } + + public Object getContent() + { + return structure; + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java new file mode 100644 index 0000000..7322fdc --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/PasswordRecipient.java @@ -0,0 +1,20 @@ +package org.bouncycastle.cms; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface PasswordRecipient + extends Recipient +{ + public static final int PKCS5_SCHEME2 = 0; + public static final int PKCS5_SCHEME2_UTF8 = 1; + + byte[] calculateDerivedKey(int schemeID, AlgorithmIdentifier derivationAlgorithm, int keySize) + throws CMSException; + + RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, AlgorithmIdentifier contentEncryptionAlgorithm, byte[] derivedKey, byte[] encryptedEncryptedContentKey) + throws CMSException; + + int getPasswordConversionScheme(); + + char[] getPassword(); +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/Recipient.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/Recipient.java new file mode 100644 index 0000000..88c88a6 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/Recipient.java @@ -0,0 +1,5 @@ +package org.bouncycastle.cms; + +public interface Recipient +{ +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/RecipientOperator.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/RecipientOperator.java new file mode 100644 index 0000000..7b3e3e5 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/RecipientOperator.java @@ -0,0 +1,48 @@ +package org.bouncycastle.cms; + +import java.io.InputStream; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.operator.InputDecryptor; +import org.bouncycastle.operator.MacCalculator; +import org.bouncycastle.util.io.TeeInputStream; + +public class RecipientOperator +{ + private final AlgorithmIdentifier algorithmIdentifier; + private final Object operator; + + public RecipientOperator(InputDecryptor decryptor) + { + this.algorithmIdentifier = decryptor.getAlgorithmIdentifier(); + this.operator = decryptor; + } + + public RecipientOperator(MacCalculator macCalculator) + { + this.algorithmIdentifier = macCalculator.getAlgorithmIdentifier(); + this.operator = macCalculator; + } + + public InputStream getInputStream(InputStream dataIn) + { + if (operator instanceof InputDecryptor) + { + return ((InputDecryptor)operator).getInputStream(dataIn); + } + else + { + return new TeeInputStream(dataIn, ((MacCalculator)operator).getOutputStream()); + } + } + + public boolean isMacBased() + { + return operator instanceof MacCalculator; + } + + public byte[] getMac() + { + return ((MacCalculator)operator).getMac(); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java index f264729..e1b0ce1 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInfoGenerator.java @@ -183,13 +183,15 @@ public class SignerInfoGenerator */ ASN1Set signedAttr = null; + AlgorithmIdentifier digestEncryptionAlgorithm = sigEncAlgFinder.findEncryptionAlgorithm(signer.getAlgorithmIdentifier()); + AlgorithmIdentifier digestAlg = null; if (sAttrGen != null) { digestAlg = digester.getAlgorithmIdentifier(); calculatedDigest = digester.getDigest(); - Map parameters = getBaseParameters(contentType, digester.getAlgorithmIdentifier(), calculatedDigest); + Map parameters = getBaseParameters(contentType, digester.getAlgorithmIdentifier(), digestEncryptionAlgorithm, calculatedDigest); AttributeTable signed = sAttrGen.getAttributes(Collections.unmodifiableMap(parameters)); signedAttr = getAttributeSet(signed); @@ -220,7 +222,7 @@ public class SignerInfoGenerator ASN1Set unsignedAttr = null; if (unsAttrGen != null) { - Map parameters = getBaseParameters(contentType, digestAlg, calculatedDigest); + Map parameters = getBaseParameters(contentType, digestAlg, digestEncryptionAlgorithm, calculatedDigest); parameters.put(CMSAttributeTableGenerator.SIGNATURE, Arrays.clone(sigBytes)); AttributeTable unsigned = unsAttrGen.getAttributes(Collections.unmodifiableMap(parameters)); @@ -228,8 +230,6 @@ public class SignerInfoGenerator unsignedAttr = getAttributeSet(unsigned); } - AlgorithmIdentifier digestEncryptionAlgorithm = sigEncAlgFinder.findEncryptionAlgorithm(signer.getAlgorithmIdentifier()); - return new SignerInfo(signerIdentifier, digestAlg, signedAttr, digestEncryptionAlgorithm, new DEROctetString(sigBytes), unsignedAttr); } @@ -255,7 +255,7 @@ public class SignerInfoGenerator return null; } - private Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, byte[] hash) + private Map getBaseParameters(ASN1ObjectIdentifier contentType, AlgorithmIdentifier digAlgId, AlgorithmIdentifier sigAlgId, byte[] hash) { Map param = new HashMap(); @@ -265,7 +265,9 @@ public class SignerInfoGenerator } param.put(CMSAttributeTableGenerator.DIGEST_ALGORITHM_IDENTIFIER, digAlgId); + param.put(CMSAttributeTableGenerator.SIGNATURE_ALGORITHM_IDENTIFIER, sigAlgId); param.put(CMSAttributeTableGenerator.DIGEST, Arrays.clone(hash)); + return param; } diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformation.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformation.java index 7e178d6..ac6dd0f 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformation.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformation.java @@ -18,6 +18,7 @@ import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.cms.Attribute; import org.bouncycastle.asn1.cms.AttributeTable; +import org.bouncycastle.asn1.cms.CMSAlgorithmProtection; import org.bouncycastle.asn1.cms.CMSAttributes; import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; import org.bouncycastle.asn1.cms.SignerIdentifier; @@ -38,21 +39,22 @@ import org.bouncycastle.util.io.TeeOutputStream; */ public class SignerInformation { - private SignerId sid; - private SignerInfo info; - private AlgorithmIdentifier digestAlgorithm; - private AlgorithmIdentifier encryptionAlgorithm; - private final ASN1Set signedAttributeSet; - private final ASN1Set unsignedAttributeSet; - private CMSProcessable content; - private byte[] signature; - private ASN1ObjectIdentifier contentType; - private byte[] resultDigest; + private final SignerId sid; + private final CMSProcessable content; + private final byte[] signature; + private final ASN1ObjectIdentifier contentType; + private final boolean isCounterSignature; // Derived - private AttributeTable signedAttributeValues; - private AttributeTable unsignedAttributeValues; - private boolean isCounterSignature; + private AttributeTable signedAttributeValues; + private AttributeTable unsignedAttributeValues; + private byte[] resultDigest; + + protected final SignerInfo info; + protected final AlgorithmIdentifier digestAlgorithm; + protected final AlgorithmIdentifier encryptionAlgorithm; + protected final ASN1Set signedAttributeSet; + protected final ASN1Set unsignedAttributeSet; SignerInformation( SignerInfo info, @@ -89,6 +91,28 @@ public class SignerInformation this.resultDigest = resultDigest; } + /** + * Protected constructor. In some cases clients have their own idea about how to encode + * the signed attributes and calculate the signature. This constructor is to allow developers + * to deal with that by extending off the class and overridng methods like getSignedAttributes(). + * + * @param baseInfo the SignerInformation to base this one on. + */ + protected SignerInformation(SignerInformation baseInfo) + { + this.info = baseInfo.info; + this.contentType = baseInfo.contentType; + this.isCounterSignature = baseInfo.isCounterSignature(); + this.sid = baseInfo.getSID(); + this.digestAlgorithm = info.getDigestAlgorithm(); + this.signedAttributeSet = info.getAuthenticatedAttributes(); + this.unsignedAttributeSet = info.getUnauthenticatedAttributes(); + this.encryptionAlgorithm = info.getDigestEncryptionAlgorithm(); + this.signature = info.getEncryptedDigest().getOctets(); + this.content = baseInfo.content; + this.resultDigest = baseInfo.resultDigest; + } + public boolean isCounterSignature() { return isCounterSignature; @@ -302,7 +326,7 @@ public class SignerInformation { if (signedAttributeSet != null) { - return signedAttributeSet.getEncoded(); + return signedAttributeSet.getEncoded(ASN1Encoding.DER); } return null; @@ -428,6 +452,46 @@ public class SignerInformation } } + AttributeTable signedAttrTable = this.getSignedAttributes(); + + // RFC 6211 Validate Algorithm Identifier protection attribute if present + { + AttributeTable unsignedAttrTable = this.getUnsignedAttributes(); + if (unsignedAttrTable != null && unsignedAttrTable.getAll(CMSAttributes.cmsAlgorithmProtect).size() > 0) + { + throw new CMSException("A cmsAlgorithmProtect attribute MUST be a signed attribute"); + } + if (signedAttrTable != null) + { + ASN1EncodableVector protectionAttributes = signedAttrTable.getAll(CMSAttributes.cmsAlgorithmProtect); + if (protectionAttributes.size() > 1) + { + throw new CMSException("Only one instance of a cmsAlgorithmProtect attribute can be present"); + } + + if (protectionAttributes.size() > 0) + { + Attribute attr = Attribute.getInstance(protectionAttributes.get(0)); + if (attr.getAttrValues().size() != 1) + { + throw new CMSException("A cmsAlgorithmProtect attribute MUST contain exactly one value"); + } + + CMSAlgorithmProtection algorithmProtection = CMSAlgorithmProtection.getInstance(attr.getAttributeValues()[0]); + + if (!CMSUtils.isEquivalent(algorithmProtection.getDigestAlgorithm(), info.getDigestAlgorithm())) + { + throw new CMSException("CMS Algorithm Identifier Protection check failed for digestAlgorithm"); + } + + if (!CMSUtils.isEquivalent(algorithmProtection.getSignatureAlgorithm(), info.getDigestEncryptionAlgorithm())) + { + throw new CMSException("CMS Algorithm Identifier Protection check failed for signatureAlgorithm"); + } + } + } + } + // RFC 3852 11.2 Check the message-digest attribute is correct { ASN1Primitive validMessageDigest = getSingleValuedSignedAttribute( @@ -457,7 +521,6 @@ public class SignerInformation // RFC 3852 11.4 Validate countersignature attribute(s) { - AttributeTable signedAttrTable = this.getSignedAttributes(); if (signedAttrTable != null && signedAttrTable.getAll(CMSAttributes.counterSignature).size() > 0) { @@ -470,7 +533,7 @@ public class SignerInformation ASN1EncodableVector csAttrs = unsignedAttrTable.getAll(CMSAttributes.counterSignature); for (int i = 0; i < csAttrs.size(); ++i) { - Attribute csAttr = (Attribute)csAttrs.get(i); + Attribute csAttr = Attribute.getInstance(csAttrs.get(i)); if (csAttr.getAttrValues().size() < 1) { throw new CMSException("A countersignature attribute MUST contain at least one AttributeValue"); diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformationStore.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformationStore.java index b65ab5e..79ec0a0 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformationStore.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/cms/SignerInformationStore.java @@ -7,13 +7,37 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import org.bouncycastle.util.Iterable; + public class SignerInformationStore + implements Iterable { private List all = new ArrayList(); private Map table = new HashMap(); + /** + * Create a store containing a single SignerInformation object. + * + * @param signerInfo the signer information to contain. + */ + public SignerInformationStore( + SignerInformation signerInfo) + { + this.all = new ArrayList(1); + this.all.add(signerInfo); + + SignerId sid = signerInfo.getSID(); + + table.put(sid, all); + } + + /** + * Create a store containing a collection of SignerInformation objects. + * + * @param signerInfos a collection signer information objects to contain. + */ public SignerInformationStore( - Collection signerInfos) + Collection signerInfos) { Iterator it = signerInfos.iterator(); @@ -65,7 +89,7 @@ public class SignerInformationStore * * @return a collection of signers. */ - public Collection getSigners() + public Collection getSigners() { return new ArrayList(all); } @@ -76,7 +100,7 @@ public class SignerInformationStore * @param selector a signer id to select against. * @return a collection of SignerInformation objects. */ - public Collection getSigners( + public Collection getSigners( SignerId selector) { if (selector.getIssuer() != null && selector.getSubjectKeyIdentifier() != null) @@ -106,4 +130,12 @@ public class SignerInformationStore return list == null ? new ArrayList() : new ArrayList(list); } } + + /** + * Support method for Iterable where available. + */ + public Iterator iterator() + { + return getSigners().iterator(); + } } diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/openssl/CertificateTrustBlock.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/openssl/CertificateTrustBlock.java new file mode 100644 index 0000000..9a76084 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/openssl/CertificateTrustBlock.java @@ -0,0 +1,132 @@ +package org.bouncycastle.openssl; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.DERUTF8String; + +public class CertificateTrustBlock +{ + private ASN1Sequence uses; + private ASN1Sequence prohibitions; + private String alias; + + public CertificateTrustBlock(Set uses) + { + this(null, uses, null); + } + + public CertificateTrustBlock(String alias, Set uses) + { + this(alias, uses, null); + } + + public CertificateTrustBlock(String alias, Set uses, Set prohibitions) + { + this.alias = alias; + this.uses = toSequence(uses); + this.prohibitions = toSequence(prohibitions); + } + + CertificateTrustBlock(byte[] encoded) + { + ASN1Sequence seq = ASN1Sequence.getInstance(encoded); + + for (Enumeration en = seq.getObjects(); en.hasMoreElements();) + { + ASN1Encodable obj = (ASN1Encodable)en.nextElement(); + + if (obj instanceof ASN1Sequence) + { + this.uses = ASN1Sequence.getInstance(obj); + } + else if (obj instanceof ASN1TaggedObject) + { + this.prohibitions = ASN1Sequence.getInstance((ASN1TaggedObject)obj, false); + } + else if (obj instanceof DERUTF8String) + { + this.alias = DERUTF8String.getInstance(obj).getString(); + } + } + } + + public String getAlias() + { + return alias; + } + + public Set getUses() + { + return toSet(uses); + } + + public Set getProhibitions() + { + return toSet(prohibitions); + } + + private Set toSet(ASN1Sequence seq) + { + if (seq != null) + { + Set oids = new HashSet(seq.size()); + + for (Enumeration en = seq.getObjects(); en.hasMoreElements(); ) + { + oids.add(ASN1ObjectIdentifier.getInstance(en.nextElement())); + } + + return oids; + } + + return Collections.EMPTY_SET; + } + + private ASN1Sequence toSequence(Set oids) + { + if (oids == null || oids.isEmpty()) + { + return null; + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + for (Iterator it = oids.iterator(); it.hasNext();) + { + v.add((ASN1Encodable)it.next()); + } + + return new DERSequence(v); + } + + ASN1Sequence toASN1Sequence() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (uses != null) + { + v.add(uses); + } + if (prohibitions != null) + { + v.add(new DERTaggedObject(false, 0, prohibitions)); + } + if (alias != null) + { + v.add(new DERUTF8String(alias)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java index 293370f..dc2c431 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java @@ -72,6 +72,20 @@ public class DefaultDigestAlgorithmIdentifierFinder digestNameToOids.put("SHA-512", NISTObjectIdentifiers.id_sha512); // BEGIN android-removed + // digestNameToOids.put("SHA1", OIWObjectIdentifiers.idSHA1); + // digestNameToOids.put("SHA224", NISTObjectIdentifiers.id_sha224); + // digestNameToOids.put("SHA256", NISTObjectIdentifiers.id_sha256); + // digestNameToOids.put("SHA384", NISTObjectIdentifiers.id_sha384); + // digestNameToOids.put("SHA512", NISTObjectIdentifiers.id_sha512); + + // digestNameToOids.put("SHA3-224", NISTObjectIdentifiers.id_sha3_224); + // digestNameToOids.put("SHA3-256", NISTObjectIdentifiers.id_sha3_256); + // digestNameToOids.put("SHA3-384", NISTObjectIdentifiers.id_sha3_384); + // digestNameToOids.put("SHA3-512", NISTObjectIdentifiers.id_sha3_512); + // + // digestNameToOids.put("SHAKE-128", NISTObjectIdentifiers.id_shake128); + // digestNameToOids.put("SHAKE-256", NISTObjectIdentifiers.id_shake256); + // // digestNameToOids.put("GOST3411", CryptoProObjectIdentifiers.gostR3411); // // digestNameToOids.put("MD2", PKCSObjectIdentifiers.md2); @@ -106,4 +120,4 @@ public class DefaultDigestAlgorithmIdentifierFinder { return new AlgorithmIdentifier((ASN1ObjectIdentifier)digestNameToOids.get(digAlgName), DERNull.INSTANCE); } -} \ No newline at end of file +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java index 808eb4e..f6a5482 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java @@ -10,7 +10,9 @@ import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERNull; // BEGIN android-removed +// import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// import org.bouncycastle.asn1.eac.EACObjectIdentifiers; // END android-removed import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; @@ -88,8 +90,18 @@ public class DefaultSignatureAlgorithmIdentifierFinder // algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); // algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); // algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001); + // algorithms.put("SHA1WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA1); + // algorithms.put("SHA224WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA224); + // algorithms.put("SHA256WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA256); + // algorithms.put("SHA384WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA384); + // algorithms.put("SHA512WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_SHA512); + // algorithms.put("RIPEMD160WITHPLAIN-ECDSA", BSIObjectIdentifiers.ecdsa_plain_RIPEMD160); + // algorithms.put("SHA1WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1); + // algorithms.put("SHA224WITHPCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_224); + // algorithms.put("SHA256WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_256); + // algorithms.put("SHA384WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384); + // algorithms.put("SHA512WITHCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512); // END android-removed - // // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field. // The parameters field SHALL be NULL for RSA based signature algorithms. @@ -227,4 +239,4 @@ public class DefaultSignatureAlgorithmIdentifierFinder { return generate(sigAlgName); } -} \ No newline at end of file +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/GenericKey.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/GenericKey.java new file mode 100644 index 0000000..c637b66 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/GenericKey.java @@ -0,0 +1,41 @@ +package org.bouncycastle.operator; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class GenericKey +{ + private AlgorithmIdentifier algorithmIdentifier; + private Object representation; + + /** + * @deprecated provide an AlgorithmIdentifier. + * @param representation key data + */ + public GenericKey(Object representation) + { + this.algorithmIdentifier = null; + this.representation = representation; + } + + public GenericKey(AlgorithmIdentifier algorithmIdentifier, byte[] representation) + { + this.algorithmIdentifier = algorithmIdentifier; + this.representation = representation; + } + + protected GenericKey(AlgorithmIdentifier algorithmIdentifier, Object representation) + { + this.algorithmIdentifier = algorithmIdentifier; + this.representation = representation; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmIdentifier; + } + + public Object getRepresentation() + { + return representation; + } +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/InputDecryptor.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/InputDecryptor.java new file mode 100644 index 0000000..80d7d82 --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/InputDecryptor.java @@ -0,0 +1,29 @@ +package org.bouncycastle.operator; + +import java.io.InputStream; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * General interface for an operator that is able to produce + * an InputStream that will decrypt a stream of encrypted data. + */ +public interface InputDecryptor +{ + /** + * Return the algorithm identifier describing the encryption + * algorithm and parameters this decryptor can process. + * + * @return algorithm oid and parameters. + */ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Wrap the passed in input stream encIn, returning an input stream + * that decrypts what it reads from encIn before returning it. + * + * @param encIn InputStream containing encrypted input. + * @return an decrypting InputStream + */ + InputStream getInputStream(InputStream encIn); +} diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/MacCalculator.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/MacCalculator.java new file mode 100644 index 0000000..0572afc --- /dev/null +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/MacCalculator.java @@ -0,0 +1,34 @@ +package org.bouncycastle.operator; + +import java.io.OutputStream; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public interface MacCalculator +{ + AlgorithmIdentifier getAlgorithmIdentifier(); + + /** + * Returns a stream that will accept data for the purpose of calculating + * the MAC for later verification. Use org.bouncycastle.util.io.TeeOutputStream if you want to accumulate + * the data on the fly as well. + * + * @return an OutputStream + */ + OutputStream getOutputStream(); + + /** + * Return the calculated MAC based on what has been written to the stream. + * + * @return calculated MAC. + */ + byte[] getMac(); + + + /** + * Return the key used for calculating the MAC. + * + * @return the MAC key. + */ + GenericKey getKey(); +} \ No newline at end of file diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java index 04885c0..31af916 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java @@ -10,9 +10,9 @@ import java.security.Signature; import java.security.SignatureException; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.NamedJcaJceHelper; -import org.bouncycastle.jcajce.ProviderJcaJceHelper; +import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import org.bouncycastle.jcajce.util.NamedJcaJceHelper; +import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; import org.bouncycastle.operator.OperatorCreationException; diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java index 87a6699..5f82d40 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java @@ -15,9 +15,9 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; -import org.bouncycastle.jcajce.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.NamedJcaJceHelper; -import org.bouncycastle.jcajce.ProviderJcaJceHelper; +import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import org.bouncycastle.jcajce.util.NamedJcaJceHelper; +import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; import org.bouncycastle.operator.ContentVerifier; import org.bouncycastle.operator.ContentVerifierProvider; import org.bouncycastle.operator.OperatorCreationException; @@ -190,9 +190,10 @@ public class JcaContentVerifierProviderBuilder private class SigVerifier implements ContentVerifier { - private SignatureOutputStream stream; private AlgorithmIdentifier algorithm; + protected SignatureOutputStream stream; + SigVerifier(AlgorithmIdentifier algorithm, SignatureOutputStream stream) { this.algorithm = algorithm; @@ -239,6 +240,27 @@ public class JcaContentVerifierProviderBuilder this.rawSignature = rawSignature; } + public boolean verify(byte[] expected) + { + try + { + return super.verify(expected); + } + finally + { + // we need to do this as in some PKCS11 implementations the session associated with the init of the + // raw signature will not be freed if verify is not called on it. + try + { + rawSignature.verify(expected); + } + catch (Exception e) + { + // ignore + } + } + } + public boolean verify(byte[] digest, byte[] expected) { try @@ -251,6 +273,19 @@ public class JcaContentVerifierProviderBuilder { throw new RuntimeOperatorException("exception obtaining raw signature: " + e.getMessage(), e); } + finally + { + // we need to do this as in some PKCS11 implementations the session associated with the init of the + // standard signature will not be freed if verify is not called on it. + try + { + stream.verify(expected); + } + catch (Exception e) + { + // ignore + } + } } } diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java index 6f59cd0..e356796 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/JcaDigestCalculatorProviderBuilder.java @@ -7,9 +7,9 @@ import java.security.MessageDigest; import java.security.Provider; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.DefaultJcaJceHelper; -import org.bouncycastle.jcajce.NamedJcaJceHelper; -import org.bouncycastle.jcajce.ProviderJcaJceHelper; +import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import org.bouncycastle.jcajce.util.NamedJcaJceHelper; +import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; import org.bouncycastle.operator.DigestCalculator; import org.bouncycastle.operator.DigestCalculatorProvider; import org.bouncycastle.operator.OperatorCreationException; diff --git a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java index 74c1b28..19d46ec 100644 --- a/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java +++ b/bouncycastle/bcpkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java @@ -25,7 +25,9 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERNull; // BEGIN android-removed +// import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +// import org.bouncycastle.asn1.eac.EACObjectIdentifiers; // END android-removed import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; @@ -38,9 +40,11 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.jcajce.JcaJceHelper; -import org.bouncycastle.jcajce.JcaJceUtils; +import org.bouncycastle.jcajce.util.AlgorithmParametersUtils; +import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.jcajce.util.MessageDigestUtils; import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.util.Integers; class OperatorHelper { @@ -48,6 +52,7 @@ class OperatorHelper private static final Map asymmetricWrapperAlgNames = new HashMap(); private static final Map symmetricWrapperAlgNames = new HashMap(); private static final Map symmetricKeyAlgNames = new HashMap(); + private static final Map symmetricWrapperKeySizes = new HashMap(); static { @@ -62,6 +67,17 @@ class OperatorHelper // BEGIN android-removed // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410"); // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA1, "SHA1WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA224, "SHA224WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA256, "SHA256WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA384, "SHA384WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_SHA512, "SHA512WITHPLAIN-ECDSA"); + // oids.put(BSIObjectIdentifiers.ecdsa_plain_RIPEMD160, "RIPEMD160WITHPLAIN-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_1, "SHA1WITHCVC-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_224, "SHA224WITHCVC-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_256, "SHA256WITHCVC-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_384, "SHA384WITHCVC-ECDSA"); + // oids.put(EACObjectIdentifiers.id_TA_ECDSA_SHA_512, "SHA512WITHCVC-ECDSA"); // END android-removed oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA"); @@ -84,9 +100,9 @@ class OperatorHelper oids.put(NISTObjectIdentifiers.id_sha256, "SHA-256"); oids.put(NISTObjectIdentifiers.id_sha384, "SHA-384"); oids.put(NISTObjectIdentifiers.id_sha512, "SHA-512"); - oids.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD-128"); - oids.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD-160"); - oids.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD-256"); + oids.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD128"); + oids.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD160"); + oids.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD256"); asymmetricWrapperAlgNames.put(PKCSObjectIdentifiers.rsaEncryption, "RSA/ECB/PKCS1Padding"); @@ -101,6 +117,16 @@ class OperatorHelper symmetricWrapperAlgNames.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, "SEEDWrap"); symmetricWrapperAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede"); + symmetricWrapperKeySizes.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap, Integers.valueOf(192)); + symmetricWrapperKeySizes.put(NISTObjectIdentifiers.id_aes128_wrap, Integers.valueOf(128)); + symmetricWrapperKeySizes.put(NISTObjectIdentifiers.id_aes192_wrap, Integers.valueOf(192)); + symmetricWrapperKeySizes.put(NISTObjectIdentifiers.id_aes256_wrap, Integers.valueOf(256)); + symmetricWrapperKeySizes.put(NTTObjectIdentifiers.id_camellia128_wrap, Integers.valueOf(128)); + symmetricWrapperKeySizes.put(NTTObjectIdentifiers.id_camellia192_wrap, Integers.valueOf(192)); + symmetricWrapperKeySizes.put(NTTObjectIdentifiers.id_camellia256_wrap, Integers.valueOf(256)); + symmetricWrapperKeySizes.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap, Integers.valueOf(128)); + symmetricWrapperKeySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192)); + symmetricKeyAlgNames.put(NISTObjectIdentifiers.aes, "AES"); symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes128_CBC, "AES"); symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes192_CBC, "AES"); @@ -116,6 +142,16 @@ class OperatorHelper this.helper = helper; } + String getWrappingAlgorithmName(ASN1ObjectIdentifier algOid) + { + return (String)symmetricWrapperAlgNames.get(algOid); + } + + int getKeySizeInBits(ASN1ObjectIdentifier algOid) + { + return ((Integer)symmetricWrapperKeySizes.get(algOid)).intValue(); + } + Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames) throws OperatorCreationException { @@ -235,7 +271,7 @@ class OperatorHelper try { - dig = helper.createDigest(getDigestAlgName(digAlgId.getAlgorithm())); + dig = helper.createDigest(MessageDigestUtils.getDigestName(digAlgId.getAlgorithm())); } catch (NoSuchAlgorithmException e) { @@ -305,7 +341,7 @@ class OperatorHelper { AlgorithmParameters params = helper.createAlgorithmParameters(algName); - JcaJceUtils.loadParameters(params, algorithm.getParameters()); + AlgorithmParametersUtils.loadParameters(params, algorithm.getParameters()); PSSParameterSpec spec = (PSSParameterSpec)params.getParameterSpec(PSSParameterSpec.class); sig.setParameter(spec); @@ -329,7 +365,7 @@ class OperatorHelper if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) { RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); - return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1"; + return getDigestName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1"; } } @@ -341,55 +377,18 @@ class OperatorHelper return sigAlgId.getAlgorithm().getId(); } - private static String getDigestAlgName( - ASN1ObjectIdentifier digestAlgOID) + // we need to remove the - to create a correct signature name + private static String getDigestName(ASN1ObjectIdentifier oid) { - if (PKCSObjectIdentifiers.md5.equals(digestAlgOID)) - { - return "MD5"; - } - else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID)) - { - return "SHA1"; - } - else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID)) - { - return "SHA224"; - } - else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID)) - { - return "SHA256"; - } - else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID)) - { - return "SHA384"; - } - else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID)) - { - return "SHA512"; - } - // BEGIN android-removed - // else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID)) - // { - // return "RIPEMD128"; - // } - // else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID)) - // { - // return "RIPEMD160"; - // } - // else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID)) - // { - // return "RIPEMD256"; - // } - // else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID)) - // { - // return "GOST3411"; - // } - // END android-removed - else + String name = MessageDigestUtils.getDigestName(oid); + + int dIndex = name.indexOf('-'); + if (dIndex > 0) { - return digestAlgOID.getId(); + return name.substring(0, dIndex) + name.substring(dIndex + 1); } + + return MessageDigestUtils.getDigestName(oid); } public X509Certificate convertCertificate(X509CertificateHolder certHolder) @@ -406,10 +405,6 @@ class OperatorHelper { throw new OpCertificateException("cannot get encoded form of certificate: " + e.getMessage(), e); } - catch (NoSuchAlgorithmException e) - { - throw new OpCertificateException("cannot create certificate factory: " + e.getMessage(), e); - } catch (NoSuchProviderException e) { throw new OpCertificateException("cannot find factory provider: " + e.getMessage(), e); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java new file mode 100644 index 0000000..fca4e01 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecific.java @@ -0,0 +1,226 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +/** + * Base class for an application specific object + */ +public abstract class ASN1ApplicationSpecific + extends ASN1Primitive +{ + protected final boolean isConstructed; + protected final int tag; + protected final byte[] octets; + + ASN1ApplicationSpecific( + boolean isConstructed, + int tag, + byte[] octets) + { + this.isConstructed = isConstructed; + this.tag = tag; + this.octets = octets; + } + + /** + * Return an ASN1ApplicationSpecific from the passed in object, which may be a byte array, or null. + * + * @param obj the object to be converted. + * @return obj's representation as an ASN1ApplicationSpecific object. + */ + public static ASN1ApplicationSpecific getInstance(Object obj) + { + if (obj == null || obj instanceof ASN1ApplicationSpecific) + { + return (ASN1ApplicationSpecific)obj; + } + else if (obj instanceof byte[]) + { + try + { + return ASN1ApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("Failed to construct object from byte[]: " + e.getMessage()); + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + protected static int getLengthOfHeader(byte[] data) + { + int length = data[1] & 0xff; // TODO: assumes 1 byte tag + + if (length == 0x80) + { + return 2; // indefinite-length encoding + } + + if (length > 127) + { + int size = length & 0x7f; + + // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here + if (size > 4) + { + throw new IllegalStateException("DER length more than 4 bytes: " + size); + } + + return size + 2; + } + + return 2; + } + + /** + * Return true if the object is marked as constructed, false otherwise. + * + * @return true if constructed, otherwise false. + */ + public boolean isConstructed() + { + return isConstructed; + } + + /** + * Return the contents of this object as a byte[] + * + * @return the encoded contents of the object. + */ + public byte[] getContents() + { + return octets; + } + + /** + * Return the tag number associated with this object, + * + * @return the application tag number. + */ + public int getApplicationTag() + { + return tag; + } + + /** + * Return the enclosed object assuming explicit tagging. + * + * @return the resulting object + * @throws IOException if reconstruction fails. + */ + public ASN1Primitive getObject() + throws IOException + { + return new ASN1InputStream(getContents()).readObject(); + } + + /** + * Return the enclosed object assuming implicit tagging. + * + * @param derTagNo the type tag that should be applied to the object's contents. + * @return the resulting object + * @throws IOException if reconstruction fails. + */ + public ASN1Primitive getObject(int derTagNo) + throws IOException + { + if (derTagNo >= 0x1f) + { + throw new IOException("unsupported tag number"); + } + + byte[] orig = this.getEncoded(); + byte[] tmp = replaceTagNumber(derTagNo, orig); + + if ((orig[0] & BERTags.CONSTRUCTED) != 0) + { + tmp[0] |= BERTags.CONSTRUCTED; + } + + return new ASN1InputStream(tmp).readObject(); + } + + int encodedLength() + throws IOException + { + return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length; + } + + /* (non-Javadoc) + * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream) + */ + void encode(ASN1OutputStream out) throws IOException + { + int classBits = BERTags.APPLICATION; + if (isConstructed) + { + classBits |= BERTags.CONSTRUCTED; + } + + out.writeEncoded(classBits, tag, octets); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1ApplicationSpecific)) + { + return false; + } + + ASN1ApplicationSpecific other = (ASN1ApplicationSpecific)o; + + return isConstructed == other.isConstructed + && tag == other.tag + && Arrays.areEqual(octets, other.octets); + } + + public int hashCode() + { + return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets); + } + + private byte[] replaceTagNumber(int newTag, byte[] input) + throws IOException + { + int tagNo = input[0] & 0x1f; + int index = 1; + // + // with tagged object tag number is bottom 5 bits, or stored at the start of the content + // + if (tagNo == 0x1f) + { + tagNo = 0; + + int b = input[index++] & 0xff; + + // X.690-0207 8.1.2.4.2 + // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." + if ((b & 0x7f) == 0) // Note: -1 will pass + { + throw new ASN1ParsingException("corrupted stream - invalid high tag number found"); + } + + while ((b >= 0) && ((b & 0x80) != 0)) + { + tagNo |= (b & 0x7f); + tagNo <<= 7; + b = input[index++] & 0xff; + } + +// tagNo |= (b & 0x7f); + } + + byte[] tmp = new byte[input.length - index + 1]; + + System.arraycopy(input, index, tmp, 1, tmp.length - 1); + + tmp[0] = (byte)newTag; + + return tmp; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java index d7216a6..8816b2b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java @@ -2,9 +2,18 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * Interface to parse ASN.1 application specific objects. + */ public interface ASN1ApplicationSpecificParser extends ASN1Encodable, InMemoryRepresentable { + /** + * Read the next object in the parser. + * + * @return an ASN1Encodable + * @throws IOException on a parsing or decoding error. + */ ASN1Encodable readObject() throws IOException; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1BitString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1BitString.java new file mode 100644 index 0000000..513d4e5 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1BitString.java @@ -0,0 +1,291 @@ +package org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +/** + * Base class for BIT STRING objects + */ +public abstract class ASN1BitString + extends ASN1Primitive + implements ASN1String +{ + private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + + protected final byte[] data; + protected final int padBits; + + /** + * @param bitString an int containing the BIT STRING + * @return the correct number of pad bits for a bit string defined in + * a 32 bit constant + */ + static protected int getPadBits( + int bitString) + { + int val = 0; + for (int i = 3; i >= 0; i--) + { + // + // this may look a little odd, but if it isn't done like this pre jdk1.2 + // JVM's break! + // + if (i != 0) + { + if ((bitString >> (i * 8)) != 0) + { + val = (bitString >> (i * 8)) & 0xFF; + break; + } + } + else + { + if (bitString != 0) + { + val = bitString & 0xFF; + break; + } + } + } + + if (val == 0) + { + return 0; + } + + int bits = 1; + + while (((val <<= 1) & 0xFF) != 0) + { + bits++; + } + + return 8 - bits; + } + + /** + * @param bitString an int containing the BIT STRING + * @return the correct number of bytes for a bit string defined in + * a 32 bit constant + */ + static protected byte[] getBytes(int bitString) + { + if (bitString == 0) + { + return new byte[0]; + } + + int bytes = 4; + for (int i = 3; i >= 1; i--) + { + if ((bitString & (0xFF << (i * 8))) != 0) + { + break; + } + bytes--; + } + + byte[] result = new byte[bytes]; + for (int i = 0; i < bytes; i++) + { + result[i] = (byte) ((bitString >> (i * 8)) & 0xFF); + } + + return result; + } + + /** + * Base constructor. + * + * @param data the octets making up the bit string. + * @param padBits the number of extra bits at the end of the string. + */ + public ASN1BitString( + byte[] data, + int padBits) + { + if (data == null) + { + throw new NullPointerException("data cannot be null"); + } + if (data.length == 0 && padBits != 0) + { + throw new IllegalArgumentException("zero length data with non-zero pad bits"); + } + if (padBits > 7 || padBits < 0) + { + throw new IllegalArgumentException("pad bits cannot be greater than 7 or less than 0"); + } + + this.data = Arrays.clone(data); + this.padBits = padBits; + } + + /** + * Return a String representation of this BIT STRING + * + * @return a String representation. + */ + public String getString() + { + StringBuffer buf = new StringBuffer("#"); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + try + { + aOut.writeObject(this); + } + catch (IOException e) + { + throw new ASN1ParsingException("Internal error encoding BitString: " + e.getMessage(), e); + } + + byte[] string = bOut.toByteArray(); + + for (int i = 0; i != string.length; i++) + { + buf.append(table[(string[i] >>> 4) & 0xf]); + buf.append(table[string[i] & 0xf]); + } + + return buf.toString(); + } + + /** + * @return the value of the bit string as an int (truncating if necessary) + */ + public int intValue() + { + int value = 0; + byte[] string = data; + + if (padBits > 0 && data.length <= 4) + { + string = derForm(data, padBits); + } + + for (int i = 0; i != string.length && i != 4; i++) + { + value |= (string[i] & 0xff) << (8 * i); + } + + return value; + } + + /** + * Return the octets contained in this BIT STRING, checking that this BIT STRING really + * does represent an octet aligned string. Only use this method when the standard you are + * following dictates that the BIT STRING will be octet aligned. + * + * @return a copy of the octet aligned data. + */ + public byte[] getOctets() + { + if (padBits != 0) + { + throw new IllegalStateException("attempt to get non-octet aligned data from BIT STRING"); + } + + return Arrays.clone(data); + } + + public byte[] getBytes() + { + return derForm(data, padBits); + } + + public int getPadBits() + { + return padBits; + } + + public String toString() + { + return getString(); + } + + public int hashCode() + { + return padBits ^ Arrays.hashCode(this.getBytes()); + } + + protected boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1BitString)) + { + return false; + } + + ASN1BitString other = (ASN1BitString)o; + + return this.padBits == other.padBits + && Arrays.areEqual(this.getBytes(), other.getBytes()); + } + + protected static byte[] derForm(byte[] data, int padBits) + { + byte[] rv = Arrays.clone(data); + // DER requires pad bits be zero + if (padBits > 0) + { + rv[data.length - 1] &= 0xff << padBits; + } + + return rv; + } + + static ASN1BitString fromInputStream(int length, InputStream stream) + throws IOException + { + if (length < 1) + { + throw new IllegalArgumentException("truncated BIT STRING detected"); + } + + int padBits = stream.read(); + byte[] data = new byte[length - 1]; + + if (data.length != 0) + { + if (Streams.readFully(stream, data) != data.length) + { + throw new EOFException("EOF encountered in middle of BIT STRING"); + } + + if (padBits > 0 && padBits < 8) + { + if (data[data.length - 1] != (byte)(data[data.length - 1] & (0xff << padBits))) + { + return new DLBitString(data, padBits); + } + } + } + + return new DERBitString(data, padBits); + } + + public ASN1Primitive getLoadedObject() + { + return this.toASN1Primitive(); + } + + ASN1Primitive toDERObject() + { + return new DERBitString(data, padBits); + } + + ASN1Primitive toDLObject() + { + return new DLBitString(data, padBits); + } + + abstract void encode(ASN1OutputStream out) + throws IOException; +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java index 1360e8b..d883a73 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java @@ -1,15 +1,220 @@ package org.bouncycastle.asn1; +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +/** + * Public facade of ASN.1 Boolean data. + *

+ * Use following to place a new instance of ASN.1 Boolean in your dataset: + *

    + *
  • ASN1Boolean.TRUE literal
  • + *
  • ASN1Boolean.FALSE literal
  • + *
  • {@link ASN1Boolean#getInstance(boolean) ASN1Boolean.getInstance(boolean)}
  • + *
  • {@link ASN1Boolean#getInstance(int) ASN1Boolean.getInstance(int)}
  • + *
+ *

+ */ public class ASN1Boolean - extends DERBoolean + extends ASN1Primitive { - public ASN1Boolean(boolean value) + private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff }; + private static final byte[] FALSE_VALUE = new byte[] { 0 }; + + private final byte[] value; + + public static final ASN1Boolean FALSE = new ASN1Boolean(false); + public static final ASN1Boolean TRUE = new ASN1Boolean(true); + + /** + * return a boolean from the passed in object. + * + * @param obj an ASN1Boolean or an object that can be converted into one. + * @exception IllegalArgumentException if the object cannot be converted. + * @return an ASN1Boolean instance. + */ + public static ASN1Boolean getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Boolean) + { + return (ASN1Boolean)obj; + } + + if (obj instanceof byte[]) + { + byte[] enc = (byte[])obj; + try + { + return (ASN1Boolean)fromByteArray(enc); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct boolean from byte[]: " + e.getMessage()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an ASN1Boolean from the passed in boolean. + * @param value true or false depending on the ASN1Boolean wanted. + * @return an ASN1Boolean instance. + */ + public static ASN1Boolean getInstance( + boolean value) + { + return (value ? TRUE : FALSE); + } + + /** + * return an ASN1Boolean from the passed in value. + * @param value non-zero (true) or zero (false) depending on the ASN1Boolean wanted. + * @return an ASN1Boolean instance. + */ + public static ASN1Boolean getInstance( + int value) { - super(value); + return (value != 0 ? TRUE : FALSE); } - ASN1Boolean(byte[] value) + // BEGIN android-added + /** + * return a ASN1Boolean from the passed in array. + */ + public static ASN1Boolean getInstance( + byte[] octets) { - super(value); + return (octets[0] != 0) ? TRUE : FALSE; + } + + // END android-added + /** + * return a Boolean from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + * @return an ASN1Boolean instance. + */ + public static ASN1Boolean getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1Boolean) + { + return getInstance(o); + } + else + { + return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets()); + } + } + + // BEGIN android-changed + protected ASN1Boolean( + // END android-changed + byte[] value) + { + if (value.length != 1) + { + throw new IllegalArgumentException("byte value should have 1 byte in it"); + } + + if (value[0] == 0) + { + this.value = FALSE_VALUE; + } + else if ((value[0] & 0xff) == 0xff) + { + this.value = TRUE_VALUE; + } + else + { + this.value = Arrays.clone(value); + } + } + + /** + * @deprecated use getInstance(boolean) method. + * @param value true or false. + */ + // BEGIN android-changed + protected ASN1Boolean( + boolean value) + // END android-changed + { + this.value = (value) ? TRUE_VALUE : FALSE_VALUE; + } + + public boolean isTrue() + { + return (value[0] != 0); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 3; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.BOOLEAN, value); + } + + protected boolean asn1Equals( + ASN1Primitive o) + { + if (o instanceof ASN1Boolean) + { + return (value[0] == ((ASN1Boolean)o).value[0]); + } + + return false; + } + + public int hashCode() + { + return value[0]; + } + + + public String toString() + { + return (value[0] != 0) ? "TRUE" : "FALSE"; + } + + static ASN1Boolean fromOctetString(byte[] value) + { + if (value.length != 1) + { + throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it"); + } + + if (value[0] == 0) + { + return FALSE; + } + else if ((value[0] & 0xff) == 0xff) + { + return TRUE; + } + else + { + return new ASN1Boolean(value); + } } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java index 603131d..3ca8890 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java @@ -5,8 +5,22 @@ package org.bouncycastle.asn1; * own object any attempt to tag the object implicitly will convert the tag to * an explicit one as the encoding rules require. *

- * If you use this interface your class should also implement the getInstance - * pattern which takes a tag object and the tagging mode used. + * If you use this interface your class should also implement the getInstance() + * pattern which takes a tag object and the tagging mode used. + *

+ *
+ *

X.690

+ *

8: Basic encoding rules

+ *

8.13 Encoding of a choice value

+ *

+ * The encoding of a choice value shall be the same as the encoding of a value of the chosen type. + *

+ * NOTE 1 — The encoding may be primitive or constructed depending on the chosen type. + *
+ * NOTE 2 — The tag used in the identifier octets is the tag of the chosen type, + * as specified in the ASN.1 definition of the choice type. + *
+ *

*/ public interface ASN1Choice { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java index f5738bf..aa8825c 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java @@ -1,6 +1,13 @@ package org.bouncycastle.asn1; +/** + * Basic interface to produce serialisers for ASN.1 encodings. + */ public interface ASN1Encodable { + /** + * Return an object, possibly constructed, of ASN.1 primitives + * @return an ASN.1 primitive. + */ ASN1Primitive toASN1Primitive(); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java index 2819a8d..2828541 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java @@ -3,19 +3,35 @@ package org.bouncycastle.asn1; import java.util.Enumeration; import java.util.Vector; +/** + * Mutable class for building ASN.1 constructed objects. + */ public class ASN1EncodableVector { - Vector v = new Vector(); + private final Vector v = new Vector(); + /** + * Base constructor. + */ public ASN1EncodableVector() { } + /** + * Add an encodable to the vector. + * + * @param obj the encodable to add. + */ public void add(ASN1Encodable obj) { v.addElement(obj); } + /** + * Add the contents of another vector. + * + * @param other the vector to add. + */ public void addAll(ASN1EncodableVector other) { for (Enumeration en = other.v.elements(); en.hasMoreElements();) @@ -24,11 +40,22 @@ public class ASN1EncodableVector } } + /** + * Return the object at position i in this vector. + * + * @param i the index of the object of interest. + * @return the object at position i. + */ public ASN1Encodable get(int i) { return (ASN1Encodable)v.elementAt(i); } + /** + * Return the size of the vector. + * + * @return the object count in the vector. + */ public int size() { return v.size(); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java index 821d3b9..94a8842 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java @@ -1,8 +1,22 @@ package org.bouncycastle.asn1; +/** + * Supported encoding formats. + */ public interface ASN1Encoding { + /** + * DER - distinguished encoding rules. + */ static final String DER = "DER"; + + /** + * DL - definite length encoding. + */ static final String DL = "DL"; + + /** + * BER - basic encoding rules. + */ static final String BER = "BER"; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java index d93fd91..195b924 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java @@ -1,22 +1,174 @@ package org.bouncycastle.asn1; +import java.io.IOException; import java.math.BigInteger; +import org.bouncycastle.util.Arrays; + +/** + * Class representing the ASN.1 ENUMERATED type. + */ public class ASN1Enumerated - extends DEREnumerated + extends ASN1Primitive { - ASN1Enumerated(byte[] bytes) + private final byte[] bytes; + + /** + * return an enumerated from the passed in object + * + * @param obj an ASN1Enumerated or an object that can be converted into one. + * @exception IllegalArgumentException if the object cannot be converted. + * @return an ASN1Enumerated instance, or null. + */ + public static ASN1Enumerated getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Enumerated) + { + return (ASN1Enumerated)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (ASN1Enumerated)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Enumerated from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + * @return an ASN1Enumerated instance, or null. + */ + public static ASN1Enumerated getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1Enumerated) + { + return getInstance(o); + } + else + { + return fromOctetString(((ASN1OctetString)o).getOctets()); + } + } + + /** + * Constructor from int. + * + * @param value the value of this enumerated. + */ + public ASN1Enumerated( + int value) + { + bytes = BigInteger.valueOf(value).toByteArray(); + } + + /** + * Constructor from BigInteger + * + * @param value the value of this enumerated. + */ + public ASN1Enumerated( + BigInteger value) + { + bytes = value.toByteArray(); + } + + /** + * Constructor from encoded BigInteger. + * + * @param bytes the value of this enumerated as an encoded BigInteger (signed). + */ + public ASN1Enumerated( + byte[] bytes) + { + this.bytes = bytes; + } + + public BigInteger getValue() { - super(bytes); + return new BigInteger(bytes); } - public ASN1Enumerated(BigInteger value) + boolean isConstructed() { - super(value); + return false; } - public ASN1Enumerated(int value) + int encodedLength() { - super(value); + return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.ENUMERATED, bytes); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1Enumerated)) + { + return false; + } + + ASN1Enumerated other = (ASN1Enumerated)o; + + return Arrays.areEqual(this.bytes, other.bytes); + } + + public int hashCode() + { + return Arrays.hashCode(bytes); + } + + private static ASN1Enumerated[] cache = new ASN1Enumerated[12]; + + static ASN1Enumerated fromOctetString(byte[] enc) + { + if (enc.length > 1) + { + return new ASN1Enumerated(Arrays.clone(enc)); + } + + if (enc.length == 0) + { + throw new IllegalArgumentException("ENUMERATED has zero length"); + } + int value = enc[0] & 0xff; + + if (value >= cache.length) + { + return new ASN1Enumerated(Arrays.clone(enc)); + } + + ASN1Enumerated possibleMatch = cache[value]; + + if (possibleMatch == null) + { + possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc)); + } + + return possibleMatch; } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java index 0088a53..0e2be64 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java @@ -1,22 +1,401 @@ package org.bouncycastle.asn1; +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; +import java.util.Locale; +import java.util.SimpleTimeZone; +import java.util.TimeZone; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** + * Base class representing the ASN.1 GeneralizedTime type. + *

+ * The main difference between these and UTC time is a 4 digit year. + *

+ */ public class ASN1GeneralizedTime - extends DERGeneralizedTime + extends ASN1Primitive { - ASN1GeneralizedTime(byte[] bytes) + private byte[] time; + + /** + * return a generalized time from the passed in object + * + * @param obj an ASN1GeneralizedTime or an object that can be converted into one. + * @return an ASN1GeneralizedTime instance, or null. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static ASN1GeneralizedTime getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1GeneralizedTime) + { + return (ASN1GeneralizedTime)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (ASN1GeneralizedTime)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Generalized Time object from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @return an ASN1GeneralizedTime instance. + * @throws IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1GeneralizedTime getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1GeneralizedTime) + { + return getInstance(o); + } + else + { + return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets()); + } + } + + /** + * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z + * for local time, or Z+-HHMM on the end, for difference between local + * time and UTC time. The fractional second amount f must consist of at + * least one number with trailing zeroes removed. + * + * @param time the time string. + * @throws IllegalArgumentException if String is an illegal format. + */ + public ASN1GeneralizedTime( + String time) + { + this.time = Strings.toByteArray(time); + try + { + this.getDate(); + } + catch (ParseException e) + { + throw new IllegalArgumentException("invalid date string: " + e.getMessage()); + } + } + + /** + * Base constructor from a java.util.date object + * + * @param time a date object representing the time of interest. + */ + public ASN1GeneralizedTime( + Date time) + { + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US); + // END android-changed + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + + this.time = Strings.toByteArray(dateF.format(time)); + } + + /** + * Base constructor from a java.util.date and Locale - you may need to use this if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param time a date object representing the time of interest. + * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. + */ + public ASN1GeneralizedTime( + Date time, + Locale locale) + { + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", locale); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US); + dateF.setCalendar(Calendar.getInstance(Locale.US)); + // END android-changed + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + + this.time = Strings.toByteArray(dateF.format(time)); + } + + ASN1GeneralizedTime( + byte[] bytes) + { + this.time = bytes; + } + + /** + * Return the time. + * + * @return The time string as it appeared in the encoded object. + */ + public String getTimeString() + { + return Strings.fromByteArray(time); + } + + /** + * return the time - always in the form of + * YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm). + *

+ * Normally in a certificate we would expect "Z" rather than "GMT", + * however adding the "GMT" means we can just use: + *

+     *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+     * 
+ * To read in the time and get a date which is compatible with our local + * time zone. + *

+ * @return a String representation of the time. + */ + public String getTime() + { + String stime = Strings.fromByteArray(time); + + // + // standardise the format. + // + if (stime.charAt(stime.length() - 1) == 'Z') + { + return stime.substring(0, stime.length() - 1) + "GMT+00:00"; + } + else + { + int signPos = stime.length() - 5; + char sign = stime.charAt(signPos); + if (sign == '-' || sign == '+') + { + return stime.substring(0, signPos) + + "GMT" + + stime.substring(signPos, signPos + 3) + + ":" + + stime.substring(signPos + 3); + } + else + { + signPos = stime.length() - 3; + sign = stime.charAt(signPos); + if (sign == '-' || sign == '+') + { + return stime.substring(0, signPos) + + "GMT" + + stime.substring(signPos) + + ":00"; + } + } + } + return stime + calculateGMTOffset(); + } + + private String calculateGMTOffset() + { + String sign = "+"; + TimeZone timeZone = TimeZone.getDefault(); + int offset = timeZone.getRawOffset(); + if (offset < 0) + { + sign = "-"; + offset = -offset; + } + int hours = offset / (60 * 60 * 1000); + int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000); + + try + { + if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate())) + { + hours += sign.equals("+") ? 1 : -1; + } + } + catch (ParseException e) + { + // we'll do our best and ignore daylight savings + } + + return "GMT" + sign + convert(hours) + ":" + convert(minutes); + } + + private String convert(int time) + { + if (time < 10) + { + return "0" + time; + } + + return Integer.toString(time); + } + + public Date getDate() + throws ParseException + { + SimpleDateFormat dateF; + String stime = Strings.fromByteArray(time); + String d = stime; + + if (stime.endsWith("Z")) + { + if (hasFractionalSeconds()) + { + // BEGIN android-changed + // Was: dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'"); + dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'", Locale.US); + // END android-changed + } + else + { + // BEGIN android-changed + // Was: dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); + dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'", Locale.US); + // END android-changed + } + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + } + else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0) + { + d = this.getTime(); + if (hasFractionalSeconds()) + { + // BEGIN android-changed + // Was: dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz"); + dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz", Locale.US); + // END android-changed + } + else + { + // BEGIN android-changed + // Was: dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); + dateF = new SimpleDateFormat("yyyyMMddHHmmssz", Locale.US); + // END android-changed + } + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + } + else + { + if (hasFractionalSeconds()) + { + // BEGIN android-changed + // dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); + dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS", Locale.US); + // END android-changed + } + else + { + // BEGIN android-changed + // Was: dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); + // END android-changed + } + + dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID())); + } + + if (hasFractionalSeconds()) + { + // java misinterprets extra digits as being milliseconds... + String frac = d.substring(14); + int index; + for (index = 1; index < frac.length(); index++) + { + char ch = frac.charAt(index); + if (!('0' <= ch && ch <= '9')) + { + break; + } + } + + if (index - 1 > 3) + { + frac = frac.substring(0, 4) + frac.substring(index); + d = d.substring(0, 14) + frac; + } + else if (index - 1 == 1) + { + frac = frac.substring(0, index) + "00" + frac.substring(index); + d = d.substring(0, 14) + frac; + } + else if (index - 1 == 2) + { + frac = frac.substring(0, index) + "0" + frac.substring(index); + d = d.substring(0, 14) + frac; + } + } + + return dateF.parse(d); + } + + private boolean hasFractionalSeconds() + { + for (int i = 0; i != time.length; i++) + { + if (time[i] == '.') + { + if (i == 14) + { + return true; + } + } + } + return false; + } + + boolean isConstructed() { - super(bytes); + return false; } - public ASN1GeneralizedTime(Date time) + int encodedLength() { - super(time); + int length = time.length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.GENERALIZED_TIME, time); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1GeneralizedTime)) + { + return false; + } + + return Arrays.areEqual(time, ((ASN1GeneralizedTime)o).time); } - public ASN1GeneralizedTime(String time) + public int hashCode() { - super(time); + return Arrays.hashCode(time); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java index 4471433..0c63a1a 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java @@ -124,6 +124,12 @@ public class ASN1InputStream /** * build an object given its tag and the number of bytes to construct it from. + * + * @param tag the full tag details. + * @param tagNo the tagNo defined. + * @param length the length of the object. + * @return the resulting primitive. + * @throws java.io.IOException on processing exception. */ protected ASN1Primitive buildObject( int tag, @@ -230,11 +236,11 @@ public class ASN1InputStream // int length = readLength(); - if (length < 0) // indefinite length method + if (length < 0) // indefinite-length method { if (!isConstructed) { - throw new IOException("indefinite length primitive encoding encountered"); + throw new IOException("indefinite-length primitive encoding encountered"); } IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit); @@ -424,7 +430,7 @@ public class ASN1InputStream switch (tagNo) { case BIT_STRING: - return DERBitString.fromInputStream(defIn.getRemaining(), defIn); + return ASN1BitString.fromInputStream(defIn.getRemaining(), defIn); case BMP_STRING: return new DERBMPString(getBMPCharBuffer(defIn)); case BOOLEAN: @@ -438,7 +444,7 @@ public class ASN1InputStream case IA5_STRING: return new DERIA5String(defIn.toByteArray()); case INTEGER: - return new ASN1Integer(defIn.toByteArray()); + return new ASN1Integer(defIn.toByteArray(), false); case NULL: return DERNull.INSTANCE; // actual content is ignored (enforce 0 length?) case NUMERIC_STRING: @@ -459,6 +465,10 @@ public class ASN1InputStream return new DERUTF8String(defIn.toByteArray()); case VISIBLE_STRING: return new DERVisibleString(defIn.toByteArray()); + case GRAPHIC_STRING: + return new DERGraphicString(defIn.toByteArray()); + case VIDEOTEX_STRING: + return new DERVideotexString(defIn.toByteArray()); default: throw new IOException("unknown tag " + tagNo + " encountered"); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java index d60c6a8..c3c3f9c 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java @@ -1,22 +1,157 @@ package org.bouncycastle.asn1; +import java.io.IOException; import java.math.BigInteger; +import org.bouncycastle.util.Arrays; + +/** + * Class representing the ASN.1 INTEGER type. + */ public class ASN1Integer - extends DERInteger + extends ASN1Primitive { - ASN1Integer(byte[] bytes) + private final byte[] bytes; + + /** + * return an integer from the passed in object + * + * @param obj an ASN1Integer or an object that can be converted into one. + * @throws IllegalArgumentException if the object cannot be converted. + * @return an ASN1Integer instance. + */ + public static ASN1Integer getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Integer) + { + return (ASN1Integer)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (ASN1Integer)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Integer from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @throws IllegalArgumentException if the tagged object cannot + * be converted. + * @return an ASN1Integer instance. + */ + public static ASN1Integer getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1Integer) + { + return getInstance(o); + } + else + { + return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } + } + + public ASN1Integer( + long value) { - super(bytes); + bytes = BigInteger.valueOf(value).toByteArray(); } - public ASN1Integer(BigInteger value) + public ASN1Integer( + BigInteger value) { - super(value); + bytes = value.toByteArray(); } - public ASN1Integer(long value) + public ASN1Integer( + byte[] bytes) { - super(value); + this(bytes, true); } + + ASN1Integer(byte[] bytes, boolean clone) + { + this.bytes = (clone) ? Arrays.clone(bytes) : bytes; + } + + public BigInteger getValue() + { + return new BigInteger(bytes); + } + + /** + * in some cases positive values get crammed into a space, + * that's not quite big enough... + * @return the BigInteger that results from treating this ASN.1 INTEGER as unsigned. + */ + public BigInteger getPositiveValue() + { + return new BigInteger(1, bytes); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.INTEGER, bytes); + } + + public int hashCode() + { + int value = 0; + + for (int i = 0; i != bytes.length; i++) + { + value ^= (bytes[i] & 0xff) << (i % 4); + } + + return value; + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1Integer)) + { + return false; + } + + ASN1Integer other = (ASN1Integer)o; + + return Arrays.areEqual(bytes, other.bytes); + } + + public String toString() + { + return getValue().toString(); + } + } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java index 84814c5..f1098e7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java @@ -3,20 +3,32 @@ package org.bouncycastle.asn1; import java.io.IOException; /** - * A NULL object. + * A NULL object - use DERNull.INSTANCE for populating structures. */ public abstract class ASN1Null extends ASN1Primitive { - /** - * @deprecated use DERNull.INSTANCE - */ - // BEGIN android-changed + // BEGIN android-added /*package*/ ASN1Null() { } - // END android-changed + // END android-added + /** + * Return an instance of ASN.1 NULL from the passed in object. + *

+ * Accepted inputs: + *

    + *
  • null → null + *
  • {@link ASN1Null} object + *
  • a byte[] containing ASN.1 NULL object + *
+ *

+ * + * @param o object to be converted. + * @return an instance of ASN1Null, or null. + * @exception IllegalArgumentException if the object cannot be converted. + */ public static ASN1Null getInstance(Object o) { if (o instanceof ASN1Null) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Object.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Object.java index 956fb7d..304866f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Object.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Object.java @@ -3,8 +3,13 @@ package org.bouncycastle.asn1; import java.io.ByteArrayOutputStream; import java.io.IOException; +import org.bouncycastle.util.Encodable; + +/** + * Base class for defining an ASN.1 object. + */ public abstract class ASN1Object - implements ASN1Encodable + implements ASN1Encodable, Encodable { /** * Return the default BER or DER encoding for this object. @@ -88,10 +93,21 @@ public abstract class ASN1Object return this.toASN1Primitive(); } + /** + * Return true if obj is a byte array and represents an object with the given tag value. + * + * @param obj object of interest. + * @param tagValue tag value to check for. + * @return true if obj is a byte encoding starting with the given tag value, false otherwise. + */ protected static boolean hasEncodedTagValue(Object obj, int tagValue) { return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue; } + /** + * Method providing a primitive representation of this object suitable for encoding. + * @return a primitive representation of this object. + */ public abstract ASN1Primitive toASN1Primitive(); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java index 98f46a6..ac65d96 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java @@ -1,21 +1,219 @@ package org.bouncycastle.asn1; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.util.Arrays; + +/** + * Class representing the ASN.1 OBJECT IDENTIFIER type. + */ public class ASN1ObjectIdentifier - extends DERObjectIdentifier + extends ASN1Primitive { - public ASN1ObjectIdentifier(String identifier) + private final String identifier; + + private byte[] body; + + /** + * return an OID from the passed in object + * @param obj an ASN1ObjectIdentifier or an object that can be converted into one. + * @throws IllegalArgumentException if the object cannot be converted. + * @return an ASN1ObjectIdentifier instance, or null. + */ + public static ASN1ObjectIdentifier getInstance( + Object obj) { - super(identifier); + if (obj == null || obj instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)obj; + } + + if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); + } + + if (obj instanceof byte[]) + { + byte[] enc = (byte[])obj; + try + { + return (ASN1ObjectIdentifier)fromByteArray(enc); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct object identifier from byte[]: " + e.getMessage()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); } - ASN1ObjectIdentifier(byte[] bytes) + /** + * return an Object Identifier from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @throws IllegalArgumentException if the tagged object cannot + * be converted. + * @return an ASN1ObjectIdentifier instance, or null. + */ + public static ASN1ObjectIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) { - super(bytes); + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1ObjectIdentifier) + { + return getInstance(o); + } + else + { + return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } } - ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch) + private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f; + + ASN1ObjectIdentifier( + byte[] bytes) { - super(oid, branch); + StringBuffer objId = new StringBuffer(); + long value = 0; + BigInteger bigValue = null; + boolean first = true; + + for (int i = 0; i != bytes.length; i++) + { + int b = bytes[i] & 0xff; + + if (value <= LONG_LIMIT) + { + value += (b & 0x7f); + if ((b & 0x80) == 0) // end of number reached + { + if (first) + { + if (value < 40) + { + objId.append('0'); + } + else if (value < 80) + { + objId.append('1'); + value -= 40; + } + else + { + objId.append('2'); + value -= 80; + } + first = false; + } + + objId.append('.'); + objId.append(value); + value = 0; + } + else + { + value <<= 7; + } + } + else + { + if (bigValue == null) + { + bigValue = BigInteger.valueOf(value); + } + bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); + if ((b & 0x80) == 0) + { + if (first) + { + objId.append('2'); + bigValue = bigValue.subtract(BigInteger.valueOf(80)); + first = false; + } + + objId.append('.'); + objId.append(bigValue); + bigValue = null; + value = 0; + } + else + { + bigValue = bigValue.shiftLeft(7); + } + } + } + + // BEGIN android-changed + /* + * Intern the identifier so there aren't hundreds of duplicates + * (in practice). + */ + this.identifier = objId.toString().intern(); + // END android-changed + this.body = Arrays.clone(bytes); + } + + /** + * Create an OID based on the passed in String. + * + * @param identifier a string representation of an OID. + */ + public ASN1ObjectIdentifier( + String identifier) + { + if (identifier == null) + { + throw new IllegalArgumentException("'identifier' cannot be null"); + } + if (!isValidIdentifier(identifier)) + { + throw new IllegalArgumentException("string " + identifier + " not an OID"); + } + + // BEGIN android-changed + /* + * Intern the identifier so there aren't hundreds of duplicates + * (in practice). + */ + this.identifier = identifier.intern(); + // END android-changed + } + + /** + * Create an OID that creates a branch under the current one. + * + * @param branchID node numbers for the new branch. + * @return the OID for the new created branch. + */ + ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branchID) + { + if (!isValidBranchID(branchID, 0)) + { + throw new IllegalArgumentException("string " + branchID + " not a valid OID branch"); + } + + this.identifier = oid.getId() + "." + branchID; + } + + /** + * Return the OID as a string. + * + * @return the string representation of the OID carried by this object. + */ + public String getId() + { + return identifier; } /** @@ -31,12 +229,268 @@ public class ASN1ObjectIdentifier /** * Return true if this oid is an extension of the passed in branch, stem. + * * @param stem the arc or branch that is a possible parent. - * @return true if the branch is on the passed in stem, false otherwise. + * @return true if the branch is on the passed in stem, false otherwise. */ public boolean on(ASN1ObjectIdentifier stem) { String id = getId(), stemId = stem.getId(); return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId); } + + private void writeField( + ByteArrayOutputStream out, + long fieldValue) + { + byte[] result = new byte[9]; + int pos = 8; + result[pos] = (byte)((int)fieldValue & 0x7f); + while (fieldValue >= (1L << 7)) + { + fieldValue >>= 7; + result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80); + } + out.write(result, pos, 9 - pos); + } + + private void writeField( + ByteArrayOutputStream out, + BigInteger fieldValue) + { + int byteCount = (fieldValue.bitLength() + 6) / 7; + if (byteCount == 0) + { + out.write(0); + } + else + { + BigInteger tmpValue = fieldValue; + byte[] tmp = new byte[byteCount]; + for (int i = byteCount - 1; i >= 0; i--) + { + tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80); + tmpValue = tmpValue.shiftRight(7); + } + tmp[byteCount - 1] &= 0x7f; + out.write(tmp, 0, tmp.length); + } + } + + private void doOutput(ByteArrayOutputStream aOut) + { + OIDTokenizer tok = new OIDTokenizer(identifier); + int first = Integer.parseInt(tok.nextToken()) * 40; + + String secondToken = tok.nextToken(); + if (secondToken.length() <= 18) + { + writeField(aOut, first + Long.parseLong(secondToken)); + } + else + { + writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first))); + } + + while (tok.hasMoreTokens()) + { + String token = tok.nextToken(); + if (token.length() <= 18) + { + writeField(aOut, Long.parseLong(token)); + } + else + { + writeField(aOut, new BigInteger(token)); + } + } + } + + private synchronized byte[] getBody() + { + if (body == null) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + doOutput(bOut); + + body = bOut.toByteArray(); + } + + return body; + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + throws IOException + { + int length = getBody().length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + byte[] enc = getBody(); + + out.write(BERTags.OBJECT_IDENTIFIER); + out.writeLength(enc.length); + out.write(enc); + } + + public int hashCode() + { + return identifier.hashCode(); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof ASN1ObjectIdentifier)) + { + return false; + } + + return identifier.equals(((ASN1ObjectIdentifier)o).identifier); + } + + public String toString() + { + return getId(); + } + + private static boolean isValidBranchID( + String branchID, int start) + { + boolean periodAllowed = false; + + int pos = branchID.length(); + while (--pos >= start) + { + char ch = branchID.charAt(pos); + + // TODO Leading zeroes? + if ('0' <= ch && ch <= '9') + { + periodAllowed = true; + continue; + } + + if (ch == '.') + { + if (!periodAllowed) + { + return false; + } + + periodAllowed = false; + continue; + } + + return false; + } + + return periodAllowed; + } + + private static boolean isValidIdentifier( + String identifier) + { + if (identifier.length() < 3 || identifier.charAt(1) != '.') + { + return false; + } + + char first = identifier.charAt(0); + if (first < '0' || first > '2') + { + return false; + } + + return isValidBranchID(identifier, 2); + } + + /** + * Intern will return a reference to a pooled version of this object, unless it + * is not present in which case intern will add it. + *

+ * The pool is also used by the ASN.1 parsers to limit the number of duplicated OID + * objects in circulation. + *

+ * @return a reference to the identifier in the pool. + */ + public ASN1ObjectIdentifier intern() + { + synchronized (pool) + { + OidHandle hdl = new OidHandle(getBody()); + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)pool.get(hdl); + + if (oid != null) + { + return oid; + } + else + { + pool.put(hdl, this); + return this; + } + } + } + + private static final Map pool = new HashMap(); + + private static class OidHandle + { + private int key; + private final byte[] enc; + + OidHandle(byte[] enc) + { + this.key = Arrays.hashCode(enc); + this.enc = enc; + } + + public int hashCode() + { + return key; + } + + public boolean equals(Object o) + { + if (o instanceof OidHandle) + { + return Arrays.areEqual(enc, ((OidHandle)o).enc); + } + + return false; + } + } + + static ASN1ObjectIdentifier fromOctetString(byte[] enc) + { + OidHandle hdl = new OidHandle(enc); + + synchronized (pool) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)pool.get(hdl); + if (oid != null) + { + return oid; + } + } + + return new ASN1ObjectIdentifier(enc); + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java index 703b858..a3fa4a4 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java @@ -7,6 +7,96 @@ import java.io.InputStream; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; +/** + * Abstract base for the ASN.1 OCTET STRING data type + *

+ * This supports BER, and DER forms of the data. + *

+ * DER form is always primitive single OCTET STRING, while + * BER support includes the constructed forms. + *

+ *
+ *

X.690

+ *

8: Basic encoding rules

+ *

8.7 Encoding of an octetstring value

+ *

+ * 8.7.1 The encoding of an octetstring value shall be + * either primitive or constructed at the option of the sender. + *

+ * NOTE — Where it is necessary to transfer part of an octet string + * before the entire OCTET STRING is available, the constructed encoding + * is used. + *
+ *

+ * 8.7.2 The primitive encoding contains zero, + * one or more contents octets equal in value to the octets + * in the data value, in the order they appear in the data value, + * and with the most significant bit of an octet of the data value + * aligned with the most significant bit of an octet of the contents octets. + *

+ *

+ * 8.7.3 The contents octets for the constructed encoding shall consist + * of zero, one, or more encodings. + *

+ * NOTE — Each such encoding includes identifier, length, and contents octets, + * and may include end-of-contents octets if it is constructed. + *
+ *

+ *

+ * 8.7.3.1 To encode an octetstring value in this way, + * it is segmented. Each segment shall consist of a series of + * consecutive octets of the value. There shall be no significance + * placed on the segment boundaries. + *

+ * NOTE — A segment may be of size zero, i.e. contain no octets. + *
+ *

+ *

+ * 8.7.3.2 Each encoding in the contents octets shall represent + * a segment of the overall octetstring, the encoding arising from + * a recursive application of this subclause. + * In this recursive application, each segment is treated as if it were + * a octetstring value. The encodings of the segments shall appear in the contents + * octets in the order in which their octets appear in the overall value. + *

+ * NOTE 1 — As a consequence of this recursion, + * each encoding in the contents octets may itself + * be primitive or constructed. + * However, such encodings will usually be primitive. + *
+ * NOTE 2 — In particular, the tags in the contents octets are always universal class, number 4. + *
+ *

+ *

9: Canonical encoding rules

+ *

9.1 Length forms

+ *

+ * If the encoding is constructed, it shall employ the indefinite-length form. + * If the encoding is primitive, it shall include the fewest length octets necessary. + * [Contrast with 8.1.3.2 b).] + *

+ *

9.2 String encoding forms

+ *

+ * BIT STRING, OCTET STRING,and restricted character string + * values shall be encoded with a primitive encoding if they would + * require no more than 1000 contents octets, and as a constructed + * encoding otherwise. The string fragments contained in + * the constructed encoding shall be encoded with a primitive encoding. + * The encoding of each fragment, except possibly + * the last, shall have 1000 contents octets. (Contrast with 8.21.6.) + *

+ * 10: Distinguished encoding rules + *

+ * 10.1 Length forms + * The definite form of length encoding shall be used, + * encoded in the minimum number of octets. + * [Contrast with 8.1.3.2 b).] + *

+ * 10.2 String encoding forms + * For BIT STRING, OCTET STRING and restricted character string types, + * the constructed form of encoding shall not be used. + * (Contrast with 8.21.6.) + *

+ */ public abstract class ASN1OctetString extends ASN1Primitive implements ASN1OctetStringParser @@ -76,6 +166,8 @@ public abstract class ASN1OctetString } /** + * Base constructor. + * * @param string the octets making up the octet string. */ public ASN1OctetString( @@ -88,16 +180,31 @@ public abstract class ASN1OctetString this.string = string; } + /** + * Return the content of the OCTET STRING as an InputStream. + * + * @return an InputStream representing the OCTET STRING's content. + */ public InputStream getOctetStream() { return new ByteArrayInputStream(string); } + /** + * Return the parser associated with this object. + * + * @return a parser based on this OCTET STRING + */ public ASN1OctetStringParser parser() { return this; } + /** + * Return the content of the OCTET STRING as a byte array. + * + * @return the byte[] representing the OCTET STRING's content. + */ public byte[] getOctets() { return string; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java index 0042317..122331f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java @@ -2,8 +2,16 @@ package org.bouncycastle.asn1; import java.io.InputStream; +/** + * A basic parser for an OCTET STRING object + */ public interface ASN1OctetStringParser extends ASN1Encodable, InMemoryRepresentable { + /** + * Return the content of the OCTET STRING as an InputStream. + * + * @return an InputStream representing the OCTET STRING's content. + */ public InputStream getOctetStream(); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java index e6fe137..db72d6a 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java @@ -2,6 +2,9 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * Base class for ASN.1 primitive objects. These are the actual objects used to generate byte encodings. + */ public abstract class ASN1Primitive extends ASN1Object { @@ -15,7 +18,7 @@ public abstract class ASN1Primitive * * @param data the byte stream to parse. * @return the base ASN.1 object represented by the byte stream. - * @exception IOException if there is a problem parsing the data. + * @exception IOException if there is a problem parsing the data, or parsing the stream did not exhaust the available data. */ public static ASN1Primitive fromByteArray(byte[] data) throws IOException @@ -24,7 +27,14 @@ public abstract class ASN1Primitive try { - return aIn.readObject(); + ASN1Primitive o = aIn.readObject(); + + if (aIn.available() != 0) + { + throw new IOException("Extra data detected in stream"); + } + + return o; } catch (ClassCastException e) { @@ -47,11 +57,21 @@ public abstract class ASN1Primitive return this; } + /** + * Return the current object as one which encodes using Distinguished Encoding Rules. + * + * @return a DER version of this. + */ ASN1Primitive toDERObject() { return this; } + /** + * Return the current object as one which encodes using Definite Length encoding. + * + * @return a DL version of this. + */ ASN1Primitive toDLObject() { return this; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java index 0507a2b..0ca4d8f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java @@ -2,18 +2,70 @@ package org.bouncycastle.asn1; import java.io.IOException; import java.util.Enumeration; +import java.util.Iterator; import java.util.Vector; +import org.bouncycastle.util.Arrays; + +/** + * ASN.1 SEQUENCE and SEQUENCE OF constructs. + *

+ * DER form is always definite form length fields, while + * BER support uses indefinite form. + *


+ *

X.690

+ *

8: Basic encoding rules

+ *

8.9 Encoding of a sequence value

+ * 8.9.1 The encoding of a sequence value shall be constructed. + *

+ * 8.9.2 The contents octets shall consist of the complete + * encoding of one data value from each of the types listed in + * the ASN.1 definition of the sequence type, in the order of + * their appearance in the definition, unless the type was referenced + * with the keyword OPTIONAL or the keyword DEFAULT. + *

+ * 8.9.3 The encoding of a data value may, but need not, + * be present for a type which was referenced with the keyword + * OPTIONAL or the keyword DEFAULT. + * If present, it shall appear in the encoding at the point + * corresponding to the appearance of the type in the ASN.1 definition. + *

+ * 8.10 Encoding of a sequence-of value + *

+ * 8.10.1 The encoding of a sequence-of value shall be constructed. + *

+ * 8.10.2 The contents octets shall consist of zero, + * one or more complete encodings of data values from the type listed in + * the ASN.1 definition. + *

+ * 8.10.3 The order of the encodings of the data values shall be + * the same as the order of the data values in the sequence-of value to + * be encoded. + *

+ *

9: Canonical encoding rules

+ *

9.1 Length forms

+ * If the encoding is constructed, it shall employ the indefinite-length form. + * If the encoding is primitive, it shall include the fewest length octets necessary. + * [Contrast with 8.1.3.2 b).] + * + *

11: Restrictions on BER employed by both CER and DER

+ *

11.5 Set and sequence components with default value

+ * The encoding of a set value or sequence value shall not include + * an encoding for any component value which is equal to + * its default value. + */ public abstract class ASN1Sequence extends ASN1Primitive + implements org.bouncycastle.util.Iterable { protected Vector seq = new Vector(); /** - * return an ASN1Sequence from the given object. + * Return an ASN1Sequence from the given object. * * @param obj the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. + * @return an ASN1Sequence instance, or null. */ public static ASN1Sequence getInstance( Object obj) @@ -65,6 +117,7 @@ public abstract class ASN1Sequence * false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return an ASN1Sequence instance. */ public static ASN1Sequence getInstance( ASN1TaggedObject obj, @@ -110,14 +163,15 @@ public abstract class ASN1Sequence } /** - * create an empty sequence + * Create an empty sequence */ protected ASN1Sequence() { } /** - * create a sequence containing one object + * Create a sequence containing one object + * @param obj the object to be put in the SEQUENCE. */ protected ASN1Sequence( ASN1Encodable obj) @@ -126,7 +180,8 @@ public abstract class ASN1Sequence } /** - * create a sequence containing a vector of objects. + * Create a sequence containing a vector of objects. + * @param v the vector of objects to be put in the SEQUENCE */ protected ASN1Sequence( ASN1EncodableVector v) @@ -137,8 +192,8 @@ public abstract class ASN1Sequence } } - /** - * create a sequence containing a vector of objects. + /* + * Create a sequence containing a vector of objects. */ protected ASN1Sequence( ASN1Encodable[] array) @@ -209,7 +264,7 @@ public abstract class ASN1Sequence } /** - * return the object at the sequence position indicated by index. + * Return the object at the sequence position indicated by index. * * @param index the sequence number (starting at zero) of the object * @return the object at the sequence position indicated by index. @@ -221,7 +276,7 @@ public abstract class ASN1Sequence } /** - * return the number of objects in this sequence. + * Return the number of objects in this sequence. * * @return the number of objects in this sequence. */ @@ -290,6 +345,10 @@ public abstract class ASN1Sequence return encObj; } + /** + * Change current SEQUENCE object to be encoded as {@link DERSequence}. + * This is part of Distinguished Encoding Rules form serialization. + */ ASN1Primitive toDERObject() { ASN1Sequence derSeq = new DERSequence(); @@ -299,6 +358,10 @@ public abstract class ASN1Sequence return derSeq; } + /** + * Change current SEQUENCE object to be encoded as {@link DLSequence}. + * This is part of Direct Length form serialization. + */ ASN1Primitive toDLObject() { ASN1Sequence dlSeq = new DLSequence(); @@ -320,4 +383,9 @@ public abstract class ASN1Sequence { return seq.toString(); } + + public Iterator iterator() + { + return new Arrays.Iterator(toArray()); + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java index 441f150..22f83c2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java @@ -2,9 +2,18 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * A basic parser for a SEQUENCE object + */ public interface ASN1SequenceParser extends ASN1Encodable, InMemoryRepresentable { + /** + * Read the next object from the underlying object representing a SEQUENCE. + * + * @throws IOException for bad input stream. + * @return the next object, null if we are at the end. + */ ASN1Encodable readObject() throws IOException; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java index f1ac6c7..1f6234f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java @@ -1,12 +1,102 @@ package org.bouncycastle.asn1; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Enumeration; +import java.util.Iterator; import java.util.Vector; -abstract public class ASN1Set +import org.bouncycastle.util.Arrays; + +/** + * ASN.1 SET and SET OF constructs. + *

+ * Note: This does not know which syntax the set is! + * (The difference: ordering of SET elements or not ordering.) + *

+ * DER form is always definite form length fields, while + * BER support uses indefinite form. + *

+ * The CER form support does not exist. + *

+ *


+ *

X.690

+ *

8: Basic encoding rules

+ *

8.11 Encoding of a set value

+ * 8.11.1 The encoding of a set value shall be constructed + *

+ * 8.11.2 The contents octets shall consist of the complete + * encoding of a data value from each of the types listed in the + * ASN.1 definition of the set type, in an order chosen by the sender, + * unless the type was referenced with the keyword + * OPTIONAL or the keyword DEFAULT. + *

+ * 8.11.3 The encoding of a data value may, but need not, + * be present for a type which was referenced with the keyword + * OPTIONAL or the keyword DEFAULT. + *

+ * NOTE — The order of data values in a set value is not significant, + * and places no constraints on the order during transfer + *
+ *

8.12 Encoding of a set-of value

+ * 8.12.1 The encoding of a set-of value shall be constructed. + *

+ * 8.12.2 The text of 8.10.2 applies: + * The contents octets shall consist of zero, + * one or more complete encodings of data values from the type listed in + * the ASN.1 definition. + *

+ * 8.12.3 The order of data values need not be preserved by + * the encoding and subsequent decoding. + * + *

9: Canonical encoding rules

+ *

9.1 Length forms

+ * If the encoding is constructed, it shall employ the indefinite-length form. + * If the encoding is primitive, it shall include the fewest length octets necessary. + * [Contrast with 8.1.3.2 b).] + *

9.3 Set components

+ * The encodings of the component values of a set value shall + * appear in an order determined by their tags as specified + * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. + * Additionally, for the purposes of determining the order in which + * components are encoded when one or more component is an untagged + * choice type, each untagged choice type is ordered as though it + * has a tag equal to that of the smallest tag in that choice type + * or any untagged choice types nested within. + * + *

10: Distinguished encoding rules

+ *

10.1 Length forms

+ * The definite form of length encoding shall be used, + * encoded in the minimum number of octets. + * [Contrast with 8.1.3.2 b).] + *

10.3 Set components

+ * The encodings of the component values of a set value shall appear + * in an order determined by their tags as specified + * in 8.6 of ITU-T Rec. X.680 | ISO/IEC 8824-1. + *
+ * NOTE — Where a component of the set is an untagged choice type, + * the location of that component in the ordering will depend on + * the tag of the choice component being encoded. + *
+ * + *

11: Restrictions on BER employed by both CER and DER

+ *

11.5 Set and sequence components with default value

+ * The encoding of a set value or sequence value shall not include + * an encoding for any component value which is equal to + * its default value. + *

11.6 Set-of components

+ *

+ * The encodings of the component values of a set-of value + * shall appear in ascending order, the encodings being compared + * as octet strings with the shorter components being padded at + * their trailing end with 0-octets. + *

+ * NOTE — The padding octets are for comparison purposes only + * and do not appear in the encodings. + *
+ */ +public abstract class ASN1Set extends ASN1Primitive + implements org.bouncycastle.util.Iterable { private Vector set = new Vector(); private boolean isSorted = false; @@ -16,6 +106,7 @@ abstract public class ASN1Set * * @param obj the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. + * @return an ASN1Set instance, or null. */ public static ASN1Set getInstance( Object obj) @@ -67,6 +158,7 @@ abstract public class ASN1Set * false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return an ASN1Set instance. */ public static ASN1Set getInstance( ASN1TaggedObject obj, @@ -135,6 +227,7 @@ abstract public class ASN1Set /** * create a sequence containing one object + * @param obj object to be added to the SET. */ protected ASN1Set( ASN1Encodable obj) @@ -144,6 +237,8 @@ abstract public class ASN1Set /** * create a sequence containing a vector of objects. + * @param v a vector of objects to make up the SET. + * @param doSort true if should be sorted DER style, false otherwise. */ protected ASN1Set( ASN1EncodableVector v, @@ -160,7 +255,7 @@ abstract public class ASN1Set } } - /** + /* * create a sequence containing a vector of objects. */ protected ASN1Set( @@ -275,6 +370,10 @@ abstract public class ASN1Set return hashCode; } + /** + * Change current SET object to be encoded as {@link DERSet}. + * This is part of Distinguished Encoding Rules form serialization. + */ ASN1Primitive toDERObject() { if (isSorted) @@ -304,6 +403,10 @@ abstract public class ASN1Set } } + /** + * Change current SET object to be encoded as {@link DLSet}. + * This is part of Direct Length form serialization. + */ ASN1Primitive toDLObject() { ASN1Set derSet = new DLSet(); @@ -381,22 +484,17 @@ abstract public class ASN1Set return len == a.length; } - private byte[] getEncoded( + private byte[] getDEREncoded( ASN1Encodable obj) { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - try { - aOut.writeObject(obj); + return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER); } catch (IOException e) { throw new IllegalArgumentException("cannot encode object added to SET"); } - - return bOut.toByteArray(); } protected void sort() @@ -413,13 +511,13 @@ abstract public class ASN1Set { int index = 0; int swapIndex = 0; - byte[] a = getEncoded((ASN1Encodable)set.elementAt(0)); + byte[] a = getDEREncoded((ASN1Encodable)set.elementAt(0)); swapped = false; while (index != lastSwap) { - byte[] b = getEncoded((ASN1Encodable)set.elementAt(index + 1)); + byte[] b = getDEREncoded((ASN1Encodable)set.elementAt(index + 1)); if (lessThanOrEqual(a, b)) { @@ -457,4 +555,9 @@ abstract public class ASN1Set { return set.toString(); } + + public Iterator iterator() + { + return new Arrays.Iterator(toArray()); + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java index e025535..5f36dbb 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java @@ -2,9 +2,18 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * A basic parser for a SET object + */ public interface ASN1SetParser extends ASN1Encodable, InMemoryRepresentable { + /** + * Read the next object from the underlying object representing a SET. + * + * @throws IOException for bad input stream. + * @return the next object, null if we are at the end. + */ public ASN1Encodable readObject() throws IOException; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java index 420fa34..a4bb370 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java @@ -4,6 +4,9 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; +/** + * A parser for ASN.1 streams which also returns, where possible, parsers for the objects it encounters. + */ public class ASN1StreamParser { private final InputStream _in; @@ -58,7 +61,7 @@ public class ASN1StreamParser { if (!constructed) { - throw new IOException("indefinite length primitive encoding encountered"); + throw new IOException("indefinite-length primitive encoding encountered"); } return readIndef(tag); @@ -89,8 +92,7 @@ public class ASN1StreamParser } } - // TODO ASN1Exception - throw new RuntimeException("implicit tagging not implemented"); + throw new ASN1Exception("implicit tagging not implemented"); } ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException @@ -142,11 +144,11 @@ public class ASN1StreamParser // int length = ASN1InputStream.readLength(_in, _limit); - if (length < 0) // indefinite length method + if (length < 0) // indefinite-length method { if (!isConstructed) { - throw new IOException("indefinite length primitive encoding encountered"); + throw new IOException("indefinite-length primitive encoding encountered"); } IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java index fde4e23..3754440 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java @@ -1,6 +1,13 @@ package org.bouncycastle.asn1; +/** + * General interface implemented by ASN.1 STRING objects. + */ public interface ASN1String { + /** + * Return a Java String representation of this STRING type's content. + * @return a Java String representation of this STRING. + */ public String getString(); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java index fb1e244..778bea7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java @@ -192,6 +192,7 @@ public abstract class ASN1TaggedObject public ASN1Encodable getObjectParser( int tag, boolean isExplicit) + throws IOException { switch (tag) { @@ -208,7 +209,7 @@ public abstract class ASN1TaggedObject return getObject(); } - throw new RuntimeException("implicit tagging not implemented for tag: " + tag); + throw new ASN1Exception("implicit tagging not implemented for tag: " + tag); } public ASN1Primitive getLoadedObject() diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java index d3816f2..41ce817 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java @@ -1,22 +1,328 @@ package org.bouncycastle.asn1; +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; +import java.util.Locale; +import java.util.SimpleTimeZone; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +/** +- * UTC time object. + * Internal facade of {@link ASN1UTCTime}. + *

+ * This datatype is valid only from 1950-01-01 00:00:00 UTC until 2049-12-31 23:59:59 UTC. + *

+ *


+ *

X.690

+ *

11: Restrictions on BER employed by both CER and DER

+ *

11.8 UTCTime

+ * 11.8.1 The encoding shall terminate with "Z", + * as described in the ITU-T X.680 | ISO/IEC 8824-1 clause on UTCTime. + *

+ * 11.8.2 The seconds element shall always be present. + *

+ * 11.8.3 Midnight (GMT) shall be represented in the form: + *

+ * "YYMMDD000000Z" + *
+ * where "YYMMDD" represents the day following the midnight in question. + */ public class ASN1UTCTime - extends DERUTCTime + extends ASN1Primitive { - ASN1UTCTime(byte[] bytes) + private byte[] time; + + /** + * return an UTC Time from the passed in object. + * + * @param obj an ASN1UTCTime or an object that can be converted into one. + * @exception IllegalArgumentException if the object cannot be converted. + * @return an ASN1UTCTime instance, or null. + */ + public static ASN1UTCTime getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1UTCTime) + { + return (ASN1UTCTime)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (ASN1UTCTime)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an UTC Time from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + * @return an ASN1UTCTime instance, or null. + */ + public static ASN1UTCTime getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Object o = obj.getObject(); + + if (explicit || o instanceof ASN1UTCTime) + { + return getInstance(o); + } + else + { + return new ASN1UTCTime(((ASN1OctetString)o).getOctets()); + } + } + + /** + * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were + * never encoded. When you're creating one of these objects from scratch, that's + * what you want to use, otherwise we'll try to deal with whatever gets read from + * the input stream... (this is why the input format is different from the getTime() + * method output). + *

+ * + * @param time the time string. + */ + public ASN1UTCTime( + String time) + { + this.time = Strings.toByteArray(time); + try + { + this.getDate(); + } + catch (ParseException e) + { + throw new IllegalArgumentException("invalid date string: " + e.getMessage()); + } + } + + /** + * base constructor from a java.util.date object + * @param time the Date to build the time from. + */ + public ASN1UTCTime( + Date time) + { + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); + SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", Locale.US); + // END android-changed + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + this.time = Strings.toByteArray(dateF.format(time)); + } + + /** + * Base constructor from a java.util.date and Locale - you may need to use this if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param time a date object representing the time of interest. + * @param locale an appropriate Locale for producing an ASN.1 UTCTime value. + */ + public ASN1UTCTime( + Date time, + Locale locale) + { + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", locale); + SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", Locale.US); + dateF.setCalendar(Calendar.getInstance(locale)); + // END android-changed + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + this.time = Strings.toByteArray(dateF.format(time)); + } + + ASN1UTCTime( + byte[] time) + { + this.time = time; + } + + /** + * return the time as a date based on whatever a 2 digit year will return. For + * standardised processing use getAdjustedDate(). + * + * @return the resulting date + * @exception ParseException if the date string cannot be parsed. + */ + public Date getDate() + throws ParseException + { + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz"); + SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz", Locale.US); + // END android-changed + + return dateF.parse(getTime()); + } + + /** + * return the time as an adjusted date + * in the range of 1950 - 2049. + * + * @return a date in the range of 1950 to 2049. + * @exception ParseException if the date string cannot be parsed. + */ + public Date getAdjustedDate() + throws ParseException + { + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz", Locale.US); + // END android-changed + + dateF.setTimeZone(new SimpleTimeZone(0, "Z")); + + return dateF.parse(getAdjustedTime()); + } + + /** + * return the time - always in the form of + * YYMMDDhhmmssGMT(+hh:mm|-hh:mm). + *

+ * Normally in a certificate we would expect "Z" rather than "GMT", + * however adding the "GMT" means we can just use: + *

+     *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
+     * 
+ * To read in the time and get a date which is compatible with our local + * time zone. + *

+ * Note: In some cases, due to the local date processing, this + * may lead to unexpected results. If you want to stick the normal + * convention of 1950 to 2049 use the getAdjustedTime() method. + */ + public String getTime() + { + String stime = Strings.fromByteArray(time); + + // + // standardise the format. + // + if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0) + { + if (stime.length() == 11) + { + return stime.substring(0, 10) + "00GMT+00:00"; + } + else + { + return stime.substring(0, 12) + "GMT+00:00"; + } + } + else + { + int index = stime.indexOf('-'); + if (index < 0) + { + index = stime.indexOf('+'); + } + String d = stime; + + if (index == stime.length() - 3) + { + d += "00"; + } + + if (index == 10) + { + return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15); + } + else + { + return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17); + } + } + } + + /** + * return a time string as an adjusted date with a 4 digit year. This goes + * in the range of 1950 - 2049. + */ + public String getAdjustedTime() + { + String d = this.getTime(); + + if (d.charAt(0) < '5') + { + return "20" + d; + } + else + { + return "19" + d; + } + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + int length = time.length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException { - super(bytes); + out.write(BERTags.UTC_TIME); + + int length = time.length; + + out.writeLength(length); + + for (int i = 0; i != length; i++) + { + out.write((byte)time[i]); + } + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1UTCTime)) + { + return false; + } + + return Arrays.areEqual(time, ((ASN1UTCTime)o).time); } - public ASN1UTCTime(Date time) + public int hashCode() { - super(time); + return Arrays.hashCode(time); } - public ASN1UTCTime(String time) + public String toString() { - super(time); + return Strings.fromByteArray(time); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java index 8bc8a4e..f8d6aa2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java @@ -1,10 +1,114 @@ package org.bouncycastle.asn1; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * An indefinite-length encoding version of an application specific object. + */ public class BERApplicationSpecific - extends DERApplicationSpecific + extends ASN1ApplicationSpecific { + BERApplicationSpecific( + boolean isConstructed, + int tag, + byte[] octets) + { + super(isConstructed, tag, octets); + } + + /** + * Create an application specific object with a tagging of explicit/constructed. + * + * @param tag the tag number for this object. + * @param object the object to be contained. + */ + public BERApplicationSpecific( + int tag, + ASN1Encodable object) + throws IOException + { + this(true, tag, object); + } + + /** + * Create an application specific object with the tagging style given by the value of constructed. + * + * @param constructed true if the object is constructed. + * @param tag the tag number for this object. + * @param object the object to be contained. + */ + public BERApplicationSpecific( + boolean constructed, + int tag, + ASN1Encodable object) + throws IOException + { + super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object)); + } + + private static byte[] getEncoding(boolean explicit, ASN1Encodable object) + throws IOException + { + byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.BER); + + if (explicit) + { + return data; + } + else + { + int lenBytes = getLengthOfHeader(data); + byte[] tmp = new byte[data.length - lenBytes]; + System.arraycopy(data, lenBytes, tmp, 0, tmp.length); + return tmp; + } + } + + /** + * Create an application specific object which is marked as constructed + * + * @param tagNo the tag number for this object. + * @param vec the objects making up the application specific object. + */ public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec) { - super(tagNo, vec); + super(true, tagNo, getEncodedVector(vec)); + } + + private static byte[] getEncodedVector(ASN1EncodableVector vec) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + for (int i = 0; i != vec.size(); i++) + { + try + { + bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.BER)); + } + catch (IOException e) + { + throw new ASN1ParsingException("malformed object: " + e, e); + } + } + return bOut.toByteArray(); + } + + /* (non-Javadoc) + * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream) + */ + void encode(ASN1OutputStream out) throws IOException + { + int classBits = BERTags.APPLICATION; + if (isConstructed) + { + classBits |= BERTags.CONSTRUCTED; + } + + out.writeTag(classBits, tag); + out.write(0x80); + out.write(octets); + out.write(0x00); + out.write(0x00); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java index 63bd9f3..e4904e0 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java @@ -2,6 +2,9 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * A parser for indefinite-length application specific objects. + */ public class BERApplicationSpecificParser implements ASN1ApplicationSpecificParser { @@ -14,18 +17,34 @@ public class BERApplicationSpecificParser this.parser = parser; } + /** + * Return the object contained in this application specific object, + * @return the contained object. + * @throws IOException if the underlying stream cannot be read, or does not contain an ASN.1 encoding. + */ public ASN1Encodable readObject() throws IOException { return parser.readObject(); } + /** + * Return an in-memory, encodable, representation of the application specific object. + * + * @return a BERApplicationSpecific. + * @throws IOException if there is an issue loading the data. + */ public ASN1Primitive getLoadedObject() throws IOException { return new BERApplicationSpecific(tag, parser.readVector()); } + /** + * Return a BERApplicationSpecific representing this parser and its contents. + * + * @return a BERApplicationSpecific + */ public ASN1Primitive toASN1Primitive() { try @@ -37,5 +56,4 @@ public class BERApplicationSpecificParser throw new ASN1ParsingException(e.getMessage(), e); } } - } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERGenerator.java index ef7f9a3..c855110 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERGenerator.java @@ -1,23 +1,25 @@ package org.bouncycastle.asn1; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; +/** + * Base class for generators for indefinite-length structures. + */ public class BERGenerator extends ASN1Generator { private boolean _tagged = false; private boolean _isExplicit; private int _tagNo; - + protected BERGenerator( OutputStream out) { super(out); } - public BERGenerator( + protected BERGenerator( OutputStream out, int tagNo, boolean isExplicit) @@ -72,18 +74,6 @@ public class BERGenerator writeHdr(tag); } } - - protected void writeBERBody( - InputStream contentStream) - throws IOException - { - int ch; - - while ((ch = contentStream.read()) >= 0) - { - _out.write(ch); - } - } protected void writeBEREnd() throws IOException diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java index aa44950..d4bfa06 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java @@ -3,18 +3,21 @@ package org.bouncycastle.asn1; import java.io.IOException; import java.util.Enumeration; +/** + * Carrier class for an indefinite-length SEQUENCE. + */ public class BERSequence extends ASN1Sequence { /** - * create an empty sequence + * Create an empty sequence */ public BERSequence() { } /** - * create a sequence containing one object + * Create a sequence containing one object */ public BERSequence( ASN1Encodable obj) @@ -23,7 +26,7 @@ public class BERSequence } /** - * create a sequence containing a vector of objects. + * Create a sequence containing a vector of objects. */ public BERSequence( ASN1EncodableVector v) @@ -32,7 +35,7 @@ public class BERSequence } /** - * create a sequence containing an array of objects. + * Create a sequence containing an array of objects. */ public BERSequence( ASN1Encodable[] array) @@ -52,8 +55,6 @@ public class BERSequence return 2 + length + 2; } - /* - */ void encode( ASN1OutputStream out) throws IOException diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java index d5d4395..543a182 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java @@ -2,6 +2,9 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * Parser for indefinite-length SEQUENCEs. + */ public class BERSequenceParser implements ASN1SequenceParser { @@ -12,18 +15,35 @@ public class BERSequenceParser this._parser = parser; } + /** + * Read the next object in the SEQUENCE. + * + * @return the next object in the SEQUENCE, null if there are no more. + * @throws IOException if there is an issue reading the underlying stream. + */ public ASN1Encodable readObject() throws IOException { return _parser.readObject(); } + /** + * Return an in-memory, encodable, representation of the SEQUENCE. + * + * @return a BERSequence. + * @throws IOException if there is an issue loading the data. + */ public ASN1Primitive getLoadedObject() throws IOException { return new BERSequence(_parser.readVector()); } - + + /** + * Return an BERSequence representing this parser and its contents. + * + * @return an BERSequence + */ public ASN1Primitive toASN1Primitive() { try diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java index 064d778..63a276b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java @@ -3,17 +3,22 @@ package org.bouncycastle.asn1; import java.io.IOException; import java.util.Enumeration; +/** + * Carrier class for an indefinite-length SET. + */ public class BERSet extends ASN1Set { /** - * create an empty sequence + * Create an empty SET. */ public BERSet() { } /** + * Create a SET containing one object. + * * @param obj - a single object that makes up the set. */ public BERSet( @@ -23,7 +28,8 @@ public class BERSet } /** - * @param v - a vector of objects making up the set. + * Create a SET containing multiple objects. + * @param v a vector of objects making up the set. */ public BERSet( ASN1EncodableVector v) @@ -32,7 +38,8 @@ public class BERSet } /** - * create a set from an array of objects. + * Create a SET from an array of objects. + * @param a an array of ASN.1 objects. */ public BERSet( ASN1Encodable[] a) @@ -52,8 +59,6 @@ public class BERSet return 2 + length + 2; } - /* - */ void encode( ASN1OutputStream out) throws IOException @@ -70,4 +75,4 @@ public class BERSet out.write(0x00); out.write(0x00); } -} +} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSetParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSetParser.java index 5a30f3c..c6e1809 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSetParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERSetParser.java @@ -2,6 +2,9 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * Parser for indefinite-length SETs. + */ public class BERSetParser implements ASN1SetParser { @@ -12,18 +15,35 @@ public class BERSetParser this._parser = parser; } + /** + * Read the next object in the SET. + * + * @return the next object in the SET, null if there are no more. + * @throws IOException if there is an issue reading the underlying stream. + */ public ASN1Encodable readObject() throws IOException { return _parser.readObject(); } + /** + * Return an in-memory, encodable, representation of the SET. + * + * @return a BERSet. + * @throws IOException if there is an issue loading the data. + */ public ASN1Primitive getLoadedObject() throws IOException { return new BERSet(_parser.readVector()); } + /** + * Return an BERSet representing this parser and its contents. + * + * @return an BERSet + */ public ASN1Primitive toASN1Primitive() { try @@ -35,4 +55,4 @@ public class BERSetParser throw new ASN1ParsingException(e.getMessage(), e); } } -} +} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java index 7cd334a..02f3f26 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java @@ -2,6 +2,9 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * Parser for indefinite-length tagged objects. + */ public class BERTaggedObjectParser implements ASN1TaggedObjectParser { @@ -19,16 +22,34 @@ public class BERTaggedObjectParser _parser = parser; } + /** + * Return true if this tagged object is marked as constructed. + * + * @return true if constructed, false otherwise. + */ public boolean isConstructed() { return _constructed; } + /** + * Return the tag number associated with this object. + * + * @return the tag number. + */ public int getTagNo() { return _tagNumber; } + /** + * Return an object parser for the contents of this tagged object. + * + * @param tag the actual tag number of the object (needed if implicit). + * @param isExplicit true if the contained object was explicitly tagged, false if implicit. + * @return an ASN.1 encodable object parser. + * @throws IOException if there is an issue building the object parser from the stream. + */ public ASN1Encodable getObjectParser( int tag, boolean isExplicit) @@ -46,12 +67,23 @@ public class BERTaggedObjectParser return _parser.readImplicit(_constructed, tag); } + /** + * Return an in-memory, encodable, representation of the tagged object. + * + * @return an ASN1TaggedObject. + * @throws IOException if there is an issue loading the data. + */ public ASN1Primitive getLoadedObject() throws IOException { return _parser.readTaggedObject(_constructed, _tagNumber); } + /** + * Return an ASN1TaggedObject representing this parser and its contents. + * + * @return an ASN1TaggedObject + */ public ASN1Primitive toASN1Primitive() { try @@ -63,4 +95,4 @@ public class BERTaggedObjectParser throw new ASN1ParsingException(e.getMessage()); } } -} +} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java index 5b59288..a5999c0 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java @@ -3,28 +3,27 @@ package org.bouncycastle.asn1; import java.io.ByteArrayOutputStream; import java.io.IOException; -import org.bouncycastle.util.Arrays; - /** - * Base class for an application specific object + * A DER encoding version of an application specific object. */ public class DERApplicationSpecific - extends ASN1Primitive + extends ASN1ApplicationSpecific { - private final boolean isConstructed; - private final int tag; - private final byte[] octets; - DERApplicationSpecific( boolean isConstructed, int tag, byte[] octets) { - this.isConstructed = isConstructed; - this.tag = tag; - this.octets = octets; + super(isConstructed, tag, octets); } + /** + * Create an application specific object from the passed in data. This will assume + * the data does not represent a constructed object. + * + * @param tag the tag number for this object. + * @param octets the encoding of the object's body. + */ public DERApplicationSpecific( int tag, byte[] octets) @@ -32,44 +31,67 @@ public class DERApplicationSpecific this(false, tag, octets); } + /** + * Create an application specific object with a tagging of explicit/constructed. + * + * @param tag the tag number for this object. + * @param object the object to be contained. + */ public DERApplicationSpecific( - int tag, + int tag, ASN1Encodable object) throws IOException { this(true, tag, object); } + /** + * Create an application specific object with the tagging style given by the value of constructed. + * + * @param constructed true if the object is constructed. + * @param tag the tag number for this object. + * @param object the object to be contained. + */ public DERApplicationSpecific( - boolean explicit, + boolean constructed, int tag, ASN1Encodable object) throws IOException { - ASN1Primitive primitive = object.toASN1Primitive(); - - byte[] data = primitive.getEncoded(ASN1Encoding.DER); + super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object)); + } - this.isConstructed = explicit || (primitive instanceof ASN1Set || primitive instanceof ASN1Sequence); - this.tag = tag; + private static byte[] getEncoding(boolean explicit, ASN1Encodable object) + throws IOException + { + byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.DER); if (explicit) { - this.octets = data; + return data; } else { int lenBytes = getLengthOfHeader(data); byte[] tmp = new byte[data.length - lenBytes]; System.arraycopy(data, lenBytes, tmp, 0, tmp.length); - this.octets = tmp; + return tmp; } } + /** + * Create an application specific object which is marked as constructed + * + * @param tagNo the tag number for this object. + * @param vec the objects making up the application specific object. + */ public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec) { - this.tag = tagNo; - this.isConstructed = true; + super(true, tagNo, getEncodedVector(vec)); + } + + private static byte[] getEncodedVector(ASN1EncodableVector vec) + { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); for (int i = 0; i != vec.size(); i++) @@ -83,121 +105,7 @@ public class DERApplicationSpecific throw new ASN1ParsingException("malformed object: " + e, e); } } - this.octets = bOut.toByteArray(); - } - - public static DERApplicationSpecific getInstance(Object obj) - { - if (obj == null || obj instanceof DERApplicationSpecific) - { - return (DERApplicationSpecific)obj; - } - else if (obj instanceof byte[]) - { - try - { - return DERApplicationSpecific.getInstance(ASN1Primitive.fromByteArray((byte[])obj)); - } - catch (IOException e) - { - throw new IllegalArgumentException("failed to construct object from byte[]: " + e.getMessage()); - } - } - else if (obj instanceof ASN1Encodable) - { - ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); - - if (primitive instanceof ASN1Sequence) - { - return (DERApplicationSpecific)primitive; - } - } - - throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); - } - - private int getLengthOfHeader(byte[] data) - { - int length = data[1] & 0xff; // TODO: assumes 1 byte tag - - if (length == 0x80) - { - return 2; // indefinite-length encoding - } - - if (length > 127) - { - int size = length & 0x7f; - - // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here - if (size > 4) - { - throw new IllegalStateException("DER length more than 4 bytes: " + size); - } - - return size + 2; - } - - return 2; - } - - public boolean isConstructed() - { - return isConstructed; - } - - public byte[] getContents() - { - return octets; - } - - public int getApplicationTag() - { - return tag; - } - - /** - * Return the enclosed object assuming explicit tagging. - * - * @return the resulting object - * @throws IOException if reconstruction fails. - */ - public ASN1Primitive getObject() - throws IOException - { - return new ASN1InputStream(getContents()).readObject(); - } - - /** - * Return the enclosed object assuming implicit tagging. - * - * @param derTagNo the type tag that should be applied to the object's contents. - * @return the resulting object - * @throws IOException if reconstruction fails. - */ - public ASN1Primitive getObject(int derTagNo) - throws IOException - { - if (derTagNo >= 0x1f) - { - throw new IOException("unsupported tag number"); - } - - byte[] orig = this.getEncoded(); - byte[] tmp = replaceTagNumber(derTagNo, orig); - - if ((orig[0] & BERTags.CONSTRUCTED) != 0) - { - tmp[0] |= BERTags.CONSTRUCTED; - } - - return new ASN1InputStream(tmp).readObject(); - } - - int encodedLength() - throws IOException - { - return StreamUtil.calculateTagLength(tag) + StreamUtil.calculateBodyLength(octets.length) + octets.length; + return bOut.toByteArray(); } /* (non-Javadoc) @@ -213,64 +121,4 @@ public class DERApplicationSpecific out.writeEncoded(classBits, tag, octets); } - - boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DERApplicationSpecific)) - { - return false; - } - - DERApplicationSpecific other = (DERApplicationSpecific)o; - - return isConstructed == other.isConstructed - && tag == other.tag - && Arrays.areEqual(octets, other.octets); - } - - public int hashCode() - { - return (isConstructed ? 1 : 0) ^ tag ^ Arrays.hashCode(octets); - } - - private byte[] replaceTagNumber(int newTag, byte[] input) - throws IOException - { - int tagNo = input[0] & 0x1f; - int index = 1; - // - // with tagged object tag number is bottom 5 bits, or stored at the start of the content - // - if (tagNo == 0x1f) - { - tagNo = 0; - - int b = input[index++] & 0xff; - - // X.690-0207 8.1.2.4.2 - // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." - if ((b & 0x7f) == 0) // Note: -1 will pass - { - throw new ASN1ParsingException("corrupted stream - invalid high tag number found"); - } - - while ((b >= 0) && ((b & 0x80) != 0)) - { - tagNo |= (b & 0x7f); - tagNo <<= 7; - b = input[index++] & 0xff; - } - - tagNo |= (b & 0x7f); - } - - byte[] tmp = new byte[input.length - index + 1]; - - System.arraycopy(input, index, tmp, 1, tmp.length - 1); - - tmp[0] = (byte)newTag; - - return tmp; - } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java index 341e46a..e689985 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java @@ -5,19 +5,20 @@ import java.io.IOException; import org.bouncycastle.util.Arrays; /** - * DER BMPString object. + * Carrier class for DER encoding BMPString object. */ public class DERBMPString extends ASN1Primitive implements ASN1String { - private char[] string; + private final char[] string; /** * return a BMP String from the given object. * * @param obj the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERBMPString instance, or null. */ public static DERBMPString getInstance( Object obj) @@ -50,6 +51,7 @@ public class DERBMPString * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return a DERBMPString instance. */ public static DERBMPString getInstance( ASN1TaggedObject obj, @@ -69,6 +71,7 @@ public class DERBMPString /** * basic constructor - byte encoded string. + * @param string the encoded BMP STRING to wrap. */ DERBMPString( byte[] string) @@ -90,6 +93,7 @@ public class DERBMPString /** * basic constructor + * @param string a String to wrap as a BMP STRING. */ public DERBMPString( String string) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java index a7b02ec..d74bc00 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java @@ -1,99 +1,19 @@ package org.bouncycastle.asn1; -import java.io.ByteArrayOutputStream; -import java.io.EOFException; import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.io.Streams; +/** + * A BIT STRING with DER encoding. + */ public class DERBitString - extends ASN1Primitive - implements ASN1String + extends ASN1BitString { - private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - - protected byte[] data; - protected int padBits; - - /** - * return the correct number of pad bits for a bit string defined in - * a 32 bit constant - */ - static protected int getPadBits( - int bitString) - { - int val = 0; - for (int i = 3; i >= 0; i--) - { - // - // this may look a little odd, but if it isn't done like this pre jdk1.2 - // JVM's break! - // - if (i != 0) - { - if ((bitString >> (i * 8)) != 0) - { - val = (bitString >> (i * 8)) & 0xFF; - break; - } - } - else - { - if (bitString != 0) - { - val = bitString & 0xFF; - break; - } - } - } - - if (val == 0) - { - return 7; - } - - - int bits = 1; - - while (((val <<= 1) & 0xFF) != 0) - { - bits++; - } - - return 8 - bits; - } - - /** - * return the correct number of bytes for a bit string defined in - * a 32 bit constant - */ - static protected byte[] getBytes(int bitString) - { - int bytes = 4; - for (int i = 3; i >= 1; i--) - { - if ((bitString & (0xFF << (i * 8))) != 0) - { - break; - } - bytes--; - } - - byte[] result = new byte[bytes]; - for (int i = 0; i < bytes; i++) - { - result[i] = (byte) ((bitString >> (i * 8)) & 0xFF); - } - - return result; - } - /** * return a Bit String from the passed in object * + * @param obj a DERBitString or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERBitString instance, or null. */ public static DERBitString getInstance( Object obj) @@ -102,6 +22,10 @@ public class DERBitString { return (DERBitString)obj; } + if (obj instanceof DLBitString) + { + return new DERBitString(((DLBitString)obj).data, ((DLBitString)obj).padBits); + } throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); } @@ -114,6 +38,7 @@ public class DERBitString * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return a DERBitString instance, or null. */ public static DERBitString getInstance( ASN1TaggedObject obj, @@ -135,9 +60,16 @@ public class DERBitString byte data, int padBits) { - this.data = new byte[1]; - this.data[0] = data; - this.padBits = padBits; + this(toByteArray(data), padBits); + } + + private static byte[] toByteArray(byte data) + { + byte[] rv = new byte[1]; + + rv[0] = data; + + return rv; } /** @@ -148,8 +80,7 @@ public class DERBitString byte[] data, int padBits) { - this.data = data; - this.padBits = padBits; + super(data, padBits); } public DERBitString( @@ -161,42 +92,14 @@ public class DERBitString public DERBitString( int value) { - this.data = getBytes(value); - this.padBits = getPadBits(value); + super(getBytes(value), getPadBits(value)); } public DERBitString( ASN1Encodable obj) throws IOException { - this.data = obj.toASN1Primitive().getEncoded(ASN1Encoding.DER); - this.padBits = 0; - } - - public byte[] getBytes() - { - return data; - } - - public int getPadBits() - { - return padBits; - } - - - /** - * @return the value of the bit string as an int (truncating if necessary) - */ - public int intValue() - { - int value = 0; - - for (int i = 0; i != data.length && i != 4; i++) - { - value |= (data[i] & 0xff) << (8 * i); - } - - return value; + super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER), 0); } boolean isConstructed() @@ -213,64 +116,15 @@ public class DERBitString ASN1OutputStream out) throws IOException { - byte[] bytes = new byte[getBytes().length + 1]; + byte[] string = derForm(data, padBits); + byte[] bytes = new byte[string.length + 1]; bytes[0] = (byte)getPadBits(); - System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1); + System.arraycopy(string, 0, bytes, 1, bytes.length - 1); out.writeEncoded(BERTags.BIT_STRING, bytes); } - public int hashCode() - { - return padBits ^ Arrays.hashCode(data); - } - - protected boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DERBitString)) - { - return false; - } - - DERBitString other = (DERBitString)o; - - return this.padBits == other.padBits - && Arrays.areEqual(this.data, other.data); - } - - public String getString() - { - StringBuffer buf = new StringBuffer("#"); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - - try - { - aOut.writeObject(this); - } - catch (IOException e) - { - throw new RuntimeException("internal error encoding BitString"); - } - - byte[] string = bOut.toByteArray(); - - for (int i = 0; i != string.length; i++) - { - buf.append(table[(string[i] >>> 4) & 0xf]); - buf.append(table[string[i] & 0xf]); - } - - return buf.toString(); - } - - public String toString() - { - return getString(); - } - static DERBitString fromOctetString(byte[] bytes) { if (bytes.length < 1) @@ -288,26 +142,4 @@ public class DERBitString return new DERBitString(data, padBits); } - - static DERBitString fromInputStream(int length, InputStream stream) - throws IOException - { - if (length < 1) - { - throw new IllegalArgumentException("truncated BIT STRING detected"); - } - - int padBits = stream.read(); - byte[] data = new byte[length - 1]; - - if (data.length != 0) - { - if (Streams.readFully(stream, data) != data.length) - { - throw new EOFException("EOF encountered in middle of BIT STRING"); - } - } - - return new DERBitString(data, padBits); - } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java index 634f5a8..378ea35 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java @@ -1,196 +1,22 @@ package org.bouncycastle.asn1; -import java.io.IOException; - -import org.bouncycastle.util.Arrays; - +/** + * @deprecated use ASN1Boolean + */ public class DERBoolean - extends ASN1Primitive + extends ASN1Boolean { - private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff }; - private static final byte[] FALSE_VALUE = new byte[] { 0 }; - - // BEGIN android-changed - final private byte[] value; - // END android-changed - - public static final ASN1Boolean FALSE = new ASN1Boolean(false); - public static final ASN1Boolean TRUE = new ASN1Boolean(true); - - - /** - * return a boolean from the passed in object. - * - * @exception IllegalArgumentException if the object cannot be converted. - */ - public static ASN1Boolean getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1Boolean) - { - return (ASN1Boolean)obj; - } - - if (obj instanceof DERBoolean) - { - return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE; - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - - /** - * return a ASN1Boolean from the passed in boolean. - */ - public static ASN1Boolean getInstance( - boolean value) - { - return (value ? TRUE : FALSE); - } - - /** - * return a ASN1Boolean from the passed in boolean. - */ - public static ASN1Boolean getInstance( - int value) - { - return (value != 0 ? TRUE : FALSE); - } - - // BEGIN android-added - /** - * return a DERBoolean from the passed in array. - */ - public static DERBoolean getInstance( - byte[] octets) - { - return (octets[0] != 0) ? TRUE : FALSE; - } - - // END android-added - /** - * return a Boolean from a tagged object. - * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @exception IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1Boolean getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Primitive o = obj.getObject(); - - if (explicit || o instanceof DERBoolean) - { - return getInstance(o); - } - else - { - return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets()); - } - } - - // BEGIN android-changed - protected DERBoolean( - // END android-changed - byte[] value) - { - if (value.length != 1) - { - throw new IllegalArgumentException("byte value should have 1 byte in it"); - } - - if (value[0] == 0) - { - this.value = FALSE_VALUE; - } - else if (value[0] == 0xff) - { - this.value = TRUE_VALUE; - } - else - { - this.value = Arrays.clone(value); - } - } - /** * @deprecated use getInstance(boolean) method. * @param value */ - // BEGIN android-changed - protected DERBoolean( - boolean value) - // END android-changed + public DERBoolean(boolean value) { - this.value = (value) ? TRUE_VALUE : FALSE_VALUE; + super(value); } - public boolean isTrue() + DERBoolean(byte[] value) { - return (value[0] != 0); - } - - boolean isConstructed() - { - return false; - } - - int encodedLength() - { - return 3; - } - - void encode( - ASN1OutputStream out) - throws IOException - { - out.writeEncoded(BERTags.BOOLEAN, value); - } - - protected boolean asn1Equals( - ASN1Primitive o) - { - if ((o == null) || !(o instanceof DERBoolean)) - { - return false; - } - - return (value[0] == ((DERBoolean)o).value[0]); - } - - public int hashCode() - { - return value[0]; - } - - - public String toString() - { - return (value[0] != 0) ? "TRUE" : "FALSE"; - } - - static ASN1Boolean fromOctetString(byte[] value) - { - if (value.length != 1) - { - throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it"); - } - - if (value[0] == 0) - { - return FALSE; - } - else if (value[0] == 0xff) - { - return TRUE; - } - else - { - return new ASN1Boolean(value); - } + super(value); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java index 919ff72..ff1059a 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java @@ -2,7 +2,7 @@ package org.bouncycastle.asn1; /** * a general class for building up a vector of DER encodable objects - - * this will eventually be superceded by ASN1EncodableVector so you should + * this will eventually be superseded by ASN1EncodableVector so you should * use that class in preference. */ public class DEREncodableVector diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java index 9b1ef55..daa8777 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java @@ -1,170 +1,37 @@ package org.bouncycastle.asn1; -import java.io.IOException; import java.math.BigInteger; -import org.bouncycastle.util.Arrays; - /** - * Use ASN1Enumerated instead of this. + * @deprecated Use ASN1Enumerated instead of this. */ public class DEREnumerated - extends ASN1Primitive + extends ASN1Enumerated { - byte[] bytes; - - /** - * return an integer from the passed in object - * - * @exception IllegalArgumentException if the object cannot be converted. - */ - public static ASN1Enumerated getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1Enumerated) - { - return (ASN1Enumerated)obj; - } - - if (obj instanceof DEREnumerated) - { - return new ASN1Enumerated(((DEREnumerated)obj).getValue()); - } - - if (obj instanceof byte[]) - { - try - { - return (ASN1Enumerated)fromByteArray((byte[])obj); - } - catch (Exception e) - { - throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); - } - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - - /** - * return an Enumerated from a tagged object. - * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @exception IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1Enumerated getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Primitive o = obj.getObject(); - - if (explicit || o instanceof DEREnumerated) - { - return getInstance(o); - } - else - { - return fromOctetString(((ASN1OctetString)o).getOctets()); - } - } - /** + * @param bytes the value of this enumerated as an encoded BigInteger (signed). * @deprecated use ASN1Enumerated */ - public DEREnumerated( - int value) + DEREnumerated(byte[] bytes) { - bytes = BigInteger.valueOf(value).toByteArray(); + super(bytes); } /** + * @param value the value of this enumerated. * @deprecated use ASN1Enumerated */ - public DEREnumerated( - BigInteger value) + public DEREnumerated(BigInteger value) { - bytes = value.toByteArray(); + super(value); } /** + * @param value the value of this enumerated. * @deprecated use ASN1Enumerated */ - public DEREnumerated( - byte[] bytes) - { - this.bytes = bytes; - } - - public BigInteger getValue() - { - return new BigInteger(bytes); - } - - boolean isConstructed() + public DEREnumerated(int value) { - return false; - } - - int encodedLength() - { - return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; - } - - void encode( - ASN1OutputStream out) - throws IOException - { - out.writeEncoded(BERTags.ENUMERATED, bytes); - } - - boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DEREnumerated)) - { - return false; - } - - DEREnumerated other = (DEREnumerated)o; - - return Arrays.areEqual(this.bytes, other.bytes); - } - - public int hashCode() - { - return Arrays.hashCode(bytes); - } - - private static ASN1Enumerated[] cache = new ASN1Enumerated[12]; - - static ASN1Enumerated fromOctetString(byte[] enc) - { - if (enc.length > 1) - { - return new ASN1Enumerated(Arrays.clone(enc)); - } - - if (enc.length == 0) - { - throw new IllegalArgumentException("ENUMERATED has zero length"); - } - int value = enc[0] & 0xff; - - if (value >= cache.length) - { - return new ASN1Enumerated(Arrays.clone(enc)); - } - - ASN1Enumerated possibleMatch = cache[value]; - - if (possibleMatch == null) - { - possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc)); - } - - return possibleMatch; + super(value); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java index aed1d27..f6c45d3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java @@ -32,7 +32,7 @@ public class DERExternal offset++; enc = getObjFromVector(vector, offset); } - if (!(enc instanceof DERTaggedObject)) + if (!(enc instanceof ASN1TaggedObject)) { dataValueDescriptor = (ASN1Primitive) enc; offset++; @@ -44,11 +44,11 @@ public class DERExternal throw new IllegalArgumentException("input vector too large"); } - if (!(enc instanceof DERTaggedObject)) + if (!(enc instanceof ASN1TaggedObject)) { throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External"); } - DERTaggedObject obj = (DERTaggedObject)enc; + ASN1TaggedObject obj = (ASN1TaggedObject)enc; setEncoding(obj.getTagNo()); externalContent = obj.getObject(); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java index b19c84d..98d02e7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java @@ -2,13 +2,18 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * Parser DER EXTERNAL tagged objects. + */ public class DERExternalParser implements ASN1Encodable, InMemoryRepresentable { private ASN1StreamParser _parser; /** - * + * Base constructor. + * + * @param parser the underlying parser to read the DER EXTERNAL from. */ public DERExternalParser(ASN1StreamParser parser) { @@ -21,6 +26,12 @@ public class DERExternalParser return _parser.readObject(); } + /** + * Return an in-memory, encodable, representation of the EXTERNAL object. + * + * @return a DERExternal. + * @throws IOException if there is an issue loading the data. + */ public ASN1Primitive getLoadedObject() throws IOException { @@ -33,20 +44,25 @@ public class DERExternalParser throw new ASN1Exception(e.getMessage(), e); } } - + + /** + * Return an DERExternal representing this parser and its contents. + * + * @return an DERExternal + */ public ASN1Primitive toASN1Primitive() { - try + try { return getLoadedObject(); } - catch (IOException ioe) + catch (IOException ioe) { throw new ASN1ParsingException("unable to get DER object", ioe); } - catch (IllegalArgumentException ioe) + catch (IllegalArgumentException ioe) { throw new ASN1ParsingException("unable to get DER object", ioe); } } -} +} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java index c6354f4..9addf70 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java @@ -5,12 +5,22 @@ import java.io.IOException; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; +/** + * Carrier class for a DER encoding GeneralString + */ public class DERGeneralString extends ASN1Primitive implements ASN1String { - private byte[] string; - + private final byte[] string; + + /** + * return a GeneralString from the given object. + * + * @param obj the object we want converted. + * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERBMPString instance, or null. + */ public static DERGeneralString getInstance( Object obj) { @@ -35,6 +45,16 @@ public class DERGeneralString + obj.getClass().getName()); } + /** + * return a GeneralString from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + * @return a DERGeneralString instance. + */ public static DERGeneralString getInstance( ASN1TaggedObject obj, boolean explicit) @@ -56,11 +76,21 @@ public class DERGeneralString this.string = string; } + /** + * Construct a GeneralString from the passed in String. + * + * @param string the string to be contained in this object. + */ public DERGeneralString(String string) { this.string = Strings.toByteArray(string); } - + + /** + * Return a Java String representation of our contained String. + * + * @return a Java String representing our contents. + */ public String getString() { return Strings.fromByteArray(string); @@ -71,6 +101,11 @@ public class DERGeneralString return getString(); } + /** + * Return a byte array representation of our contained String. + * + * @return a byte array representing our contents. + */ public byte[] getOctets() { return Arrays.clone(string); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java index 43e4673..adee74e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java @@ -1,350 +1,28 @@ package org.bouncycastle.asn1; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Date; -import java.util.SimpleTimeZone; -import java.util.TimeZone; - -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Strings; /** - * Generalized time object. + * DER Generalized time object. */ public class DERGeneralizedTime - extends ASN1Primitive + extends ASN1GeneralizedTime { - private byte[] time; - - /** - * return a generalized time from the passed in object - * - * @exception IllegalArgumentException if the object cannot be converted. - */ - public static ASN1GeneralizedTime getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1GeneralizedTime) - { - return (ASN1GeneralizedTime)obj; - } - - if (obj instanceof DERGeneralizedTime) - { - return new ASN1GeneralizedTime(((DERGeneralizedTime)obj).time); - } - - if (obj instanceof byte[]) - { - try - { - return (ASN1GeneralizedTime)fromByteArray((byte[])obj); - } - catch (Exception e) - { - throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); - } - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - - /** - * return a Generalized Time object from a tagged object. - * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @exception IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1GeneralizedTime getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Primitive o = obj.getObject(); - - if (explicit || o instanceof DERGeneralizedTime) - { - return getInstance(o); - } - else - { - return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets()); - } - } - - /** - * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z - * for local time, or Z+-HHMM on the end, for difference between local - * time and UTC time. The fractional second amount f must consist of at - * least one number with trailing zeroes removed. - * - * @param time the time string. - * @exception IllegalArgumentException if String is an illegal format. - */ - public DERGeneralizedTime( - String time) - { - this.time = Strings.toByteArray(time); - try - { - this.getDate(); - } - catch (ParseException e) - { - throw new IllegalArgumentException("invalid date string: " + e.getMessage()); - } - } - - /** - * base constructor from a java.util.date object - */ - public DERGeneralizedTime( - Date time) - { - SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); - - dateF.setTimeZone(new SimpleTimeZone(0,"Z")); - - this.time = Strings.toByteArray(dateF.format(time)); - } - - DERGeneralizedTime( - byte[] bytes) - { - this.time = bytes; - } - - /** - * Return the time. - * @return The time string as it appeared in the encoded object. - */ - public String getTimeString() - { - return Strings.fromByteArray(time); - } - - /** - * return the time - always in the form of - * YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm). - *

- * Normally in a certificate we would expect "Z" rather than "GMT", - * however adding the "GMT" means we can just use: - *

-     *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
-     * 
- * To read in the time and get a date which is compatible with our local - * time zone. - */ - public String getTime() - { - String stime = Strings.fromByteArray(time); - - // - // standardise the format. - // - if (stime.charAt(stime.length() - 1) == 'Z') - { - return stime.substring(0, stime.length() - 1) + "GMT+00:00"; - } - else - { - int signPos = stime.length() - 5; - char sign = stime.charAt(signPos); - if (sign == '-' || sign == '+') - { - return stime.substring(0, signPos) - + "GMT" - + stime.substring(signPos, signPos + 3) - + ":" - + stime.substring(signPos + 3); - } - else - { - signPos = stime.length() - 3; - sign = stime.charAt(signPos); - if (sign == '-' || sign == '+') - { - return stime.substring(0, signPos) - + "GMT" - + stime.substring(signPos) - + ":00"; - } - } - } - return stime + calculateGMTOffset(); - } - private String calculateGMTOffset() + DERGeneralizedTime(byte[] bytes) { - String sign = "+"; - TimeZone timeZone = TimeZone.getDefault(); - int offset = timeZone.getRawOffset(); - if (offset < 0) - { - sign = "-"; - offset = -offset; - } - int hours = offset / (60 * 60 * 1000); - int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000); - - try - { - if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate())) - { - hours += sign.equals("+") ? 1 : -1; - } - } - catch (ParseException e) - { - // we'll do our best and ignore daylight savings - } - - return "GMT" + sign + convert(hours) + ":" + convert(minutes); + super(bytes); } - private String convert(int time) + public DERGeneralizedTime(Date time) { - if (time < 10) - { - return "0" + time; - } - - return Integer.toString(time); - } - - public Date getDate() - throws ParseException - { - SimpleDateFormat dateF; - String stime = Strings.fromByteArray(time); - String d = stime; - - if (stime.endsWith("Z")) - { - if (hasFractionalSeconds()) - { - dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'"); - } - else - { - dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); - } - - dateF.setTimeZone(new SimpleTimeZone(0, "Z")); - } - else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0) - { - d = this.getTime(); - if (hasFractionalSeconds()) - { - dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz"); - } - else - { - dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); - } - - dateF.setTimeZone(new SimpleTimeZone(0, "Z")); - } - else - { - if (hasFractionalSeconds()) - { - dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); - } - else - { - dateF = new SimpleDateFormat("yyyyMMddHHmmss"); - } - - dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID())); - } - - if (hasFractionalSeconds()) - { - // java misinterprets extra digits as being milliseconds... - String frac = d.substring(14); - int index; - for (index = 1; index < frac.length(); index++) - { - char ch = frac.charAt(index); - if (!('0' <= ch && ch <= '9')) - { - break; - } - } - - if (index - 1 > 3) - { - frac = frac.substring(0, 4) + frac.substring(index); - d = d.substring(0, 14) + frac; - } - else if (index - 1 == 1) - { - frac = frac.substring(0, index) + "00" + frac.substring(index); - d = d.substring(0, 14) + frac; - } - else if (index - 1 == 2) - { - frac = frac.substring(0, index) + "0" + frac.substring(index); - d = d.substring(0, 14) + frac; - } - } - - return dateF.parse(d); + super(time); } - private boolean hasFractionalSeconds() + public DERGeneralizedTime(String time) { - for (int i = 0; i != time.length; i++) - { - if (time[i] == '.') - { - if (i == 14) - { - return true; - } - } - } - return false; + super(time); } - boolean isConstructed() - { - return false; - } - - int encodedLength() - { - int length = time.length; - - return 1 + StreamUtil.calculateBodyLength(length) + length; - } - - void encode( - ASN1OutputStream out) - throws IOException - { - out.writeEncoded(BERTags.GENERALIZED_TIME, time); - } - - boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DERGeneralizedTime)) - { - return false; - } - - return Arrays.areEqual(time, ((DERGeneralizedTime)o).time); - } - - public int hashCode() - { - return Arrays.hashCode(time); - } + // TODO: create proper DER encoding. } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGraphicString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGraphicString.java new file mode 100644 index 0000000..01baf0f --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERGraphicString.java @@ -0,0 +1,124 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class DERGraphicString + extends ASN1Primitive + implements ASN1String +{ + private final byte[] string; + + /** + * return a Graphic String from the passed in object + * + * @param obj a DERGraphicString or an object that can be converted into one. + * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERGraphicString instance, or null. + */ + public static DERGraphicString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERGraphicString) + { + return (DERGraphicString)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (DERGraphicString)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Graphic String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + * @return a DERGraphicString instance, or null. + */ + public static DERGraphicString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERGraphicString) + { + return getInstance(o); + } + else + { + return new DERGraphicString(((ASN1OctetString)o).getOctets()); + } + } + + /** + * basic constructor - with bytes. + * @param string the byte encoding of the characters making up the string. + */ + public DERGraphicString( + byte[] string) + { + this.string = Arrays.clone(string); + } + + public byte[] getOctets() + { + return Arrays.clone(string); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.GRAPHIC_STRING, string); + } + + public int hashCode() + { + return Arrays.hashCode(string); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERGraphicString)) + { + return false; + } + + DERGraphicString s = (DERGraphicString)o; + + return Arrays.areEqual(string, s.string); + } + + public String getString() + { + return Strings.fromByteArray(string); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java index 631672e..0336e6b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java @@ -12,12 +12,14 @@ public class DERIA5String extends ASN1Primitive implements ASN1String { - private byte[] string; + private final byte[] string; /** * return a IA5 string from the passed in object * + * @param obj a DERIA5String or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERIA5String instance, or null. */ public static DERIA5String getInstance( Object obj) @@ -50,6 +52,7 @@ public class DERIA5String * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return a DERIA5String instance, or null. */ public static DERIA5String getInstance( ASN1TaggedObject obj, @@ -69,6 +72,7 @@ public class DERIA5String /** * basic constructor - with bytes. + * @param string the byte encoding of the characters making up the string. */ DERIA5String( byte[] string) @@ -78,6 +82,7 @@ public class DERIA5String /** * basic constructor - without validation. + * @param string the base string to use.. */ public DERIA5String( String string) @@ -163,7 +168,8 @@ public class DERIA5String * return true if the passed in String can be represented without * loss as an IA5String, false otherwise. * - * @return true if in printable set, false otherwise. + * @param str the string to check. + * @return true if character set in IA5String set, false otherwise. */ public static boolean isIA5String( String str) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java index 57cc84a..d2e850f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java @@ -1,160 +1,30 @@ package org.bouncycastle.asn1; -import java.io.IOException; import java.math.BigInteger; -import org.bouncycastle.util.Arrays; - /** - * Use ASN1Integer instead of this, + * @deprecated Use ASN1Integer instead of this, */ public class DERInteger - extends ASN1Primitive + extends ASN1Integer { - byte[] bytes; - - /** - * return an integer from the passed in object - * - * @exception IllegalArgumentException if the object cannot be converted. - */ - public static ASN1Integer getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1Integer) - { - return (ASN1Integer)obj; - } - if (obj instanceof DERInteger) - { - return new ASN1Integer((((DERInteger)obj).getValue())); - } - - if (obj instanceof byte[]) - { - try - { - return (ASN1Integer)fromByteArray((byte[])obj); - } - catch (Exception e) - { - throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); - } - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - /** - * return an Integer from a tagged object. + * Constructor from a byte array containing a signed representation of the number. * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @exception IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1Integer getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Primitive o = obj.getObject(); - - if (explicit || o instanceof DERInteger) - { - return getInstance(o); - } - else - { - return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets()); - } - } - - /** - * @deprecated use ASN1Integer constructor - */ - public DERInteger( - long value) - { - bytes = BigInteger.valueOf(value).toByteArray(); - } - - /** - * @deprecated use ASN1Integer constructor + * @param bytes a byte array containing the signed number.A copy is made of the byte array. */ - public DERInteger( - BigInteger value) + public DERInteger(byte[] bytes) { - bytes = value.toByteArray(); + super(bytes, true); } - /** - * @deprecated use ASN1Integer constructor - */ - public DERInteger( - byte[] bytes) + public DERInteger(BigInteger value) { - this.bytes = bytes; - } - - public BigInteger getValue() - { - return new BigInteger(bytes); - } - - /** - * in some cases positive values get crammed into a space, - * that's not quite big enough... - */ - public BigInteger getPositiveValue() - { - return new BigInteger(1, bytes); - } - - boolean isConstructed() - { - return false; - } - - int encodedLength() - { - return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; - } - - void encode( - ASN1OutputStream out) - throws IOException - { - out.writeEncoded(BERTags.INTEGER, bytes); - } - - public int hashCode() - { - int value = 0; - - for (int i = 0; i != bytes.length; i++) - { - value ^= (bytes[i] & 0xff) << (i % 4); - } - - return value; - } - - boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DERInteger)) - { - return false; - } - - DERInteger other = (DERInteger)o; - - return Arrays.areEqual(bytes, other.bytes); + super(value); } - public String toString() + public DERInteger(long value) { - return getValue().toString(); + super(value); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java index eca4eea..ed287e5 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java @@ -12,12 +12,14 @@ public class DERNumericString extends ASN1Primitive implements ASN1String { - private byte[] string; + private final byte[] string; /** * return a Numeric string from the passed in object * + * @param obj a DERNumericString or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERNumericString instance, or null */ public static DERNumericString getInstance( Object obj) @@ -50,6 +52,7 @@ public class DERNumericString * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return a DERNumericString instance, or null. */ public static DERNumericString getInstance( ASN1TaggedObject obj, diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java index b82647e..acb2ada 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java @@ -1,458 +1,24 @@ package org.bouncycastle.asn1; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; - -import org.bouncycastle.util.Arrays; - /** - * Use ASN1ObjectIdentifier instead of this, + * + * @deprecated Use ASN1ObjectIdentifier instead of this, */ public class DERObjectIdentifier - extends ASN1Primitive + extends ASN1ObjectIdentifier { - String identifier; - - private byte[] body; - - /** - * return an OID from the passed in object - * - * @throws IllegalArgumentException if the object cannot be converted. - */ - public static ASN1ObjectIdentifier getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1ObjectIdentifier) - { - return (ASN1ObjectIdentifier)obj; - } - - if (obj instanceof DERObjectIdentifier) - { - return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId()); - } - - if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) - { - return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); - } - - if (obj instanceof byte[]) - { - byte[] enc = (byte[])obj; - if (enc[0] == BERTags.OBJECT_IDENTIFIER) - { - try - { - return (ASN1ObjectIdentifier)fromByteArray(enc); - } - catch (IOException e) - { - throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); - } - } - else - { // TODO: this really shouldn't be supported here... - return ASN1ObjectIdentifier.fromOctetString((byte[])obj); - } - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - - /** - * return an Object Identifier from a tagged object. - * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @throws IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1ObjectIdentifier getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Primitive o = obj.getObject(); - - if (explicit || o instanceof DERObjectIdentifier) - { - return getInstance(o); - } - else - { - return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets()); - } - } - - private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f; - - DERObjectIdentifier( - byte[] bytes) + public DERObjectIdentifier(String identifier) { - StringBuffer objId = new StringBuffer(); - long value = 0; - BigInteger bigValue = null; - boolean first = true; - - for (int i = 0; i != bytes.length; i++) - { - int b = bytes[i] & 0xff; - - if (value <= LONG_LIMIT) - { - value += (b & 0x7f); - if ((b & 0x80) == 0) // end of number reached - { - if (first) - { - if (value < 40) - { - objId.append('0'); - } - else if (value < 80) - { - objId.append('1'); - value -= 40; - } - else - { - objId.append('2'); - value -= 80; - } - first = false; - } - - objId.append('.'); - objId.append(value); - value = 0; - } - else - { - value <<= 7; - } - } - else - { - if (bigValue == null) - { - bigValue = BigInteger.valueOf(value); - } - bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); - if ((b & 0x80) == 0) - { - if (first) - { - objId.append('2'); - bigValue = bigValue.subtract(BigInteger.valueOf(80)); - first = false; - } - - objId.append('.'); - objId.append(bigValue); - bigValue = null; - value = 0; - } - else - { - bigValue = bigValue.shiftLeft(7); - } - } - } - - // BEGIN android-changed - /* - * Intern the identifier so there aren't hundreds of duplicates - * (in practice). - */ - this.identifier = objId.toString().intern(); - // END android-changed - this.body = Arrays.clone(bytes); + super(identifier); } - /** - * @deprecated use ASN1ObjectIdentifier constructor. - */ - public DERObjectIdentifier( - String identifier) + DERObjectIdentifier(byte[] bytes) { - if (identifier == null) - { - throw new IllegalArgumentException("'identifier' cannot be null"); - } - if (!isValidIdentifier(identifier)) - { - throw new IllegalArgumentException("string " + identifier + " not an OID"); - } - - // BEGIN android-changed - /* - * Intern the identifier so there aren't hundreds of duplicates - * (in practice). - */ - this.identifier = identifier.intern(); - // END android-changed + super(bytes); } - DERObjectIdentifier(DERObjectIdentifier oid, String branchID) + DERObjectIdentifier(ASN1ObjectIdentifier oid, String branch) { - if (!isValidBranchID(branchID, 0)) - { - throw new IllegalArgumentException("string " + branchID + " not a valid OID branch"); - } - - this.identifier = oid.getId() + "." + branchID; - } - - public String getId() - { - return identifier; - } - - private void writeField( - ByteArrayOutputStream out, - long fieldValue) - { - byte[] result = new byte[9]; - int pos = 8; - result[pos] = (byte)((int)fieldValue & 0x7f); - while (fieldValue >= (1L << 7)) - { - fieldValue >>= 7; - result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80); - } - out.write(result, pos, 9 - pos); - } - - private void writeField( - ByteArrayOutputStream out, - BigInteger fieldValue) - { - int byteCount = (fieldValue.bitLength() + 6) / 7; - if (byteCount == 0) - { - out.write(0); - } - else - { - BigInteger tmpValue = fieldValue; - byte[] tmp = new byte[byteCount]; - for (int i = byteCount - 1; i >= 0; i--) - { - tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80); - tmpValue = tmpValue.shiftRight(7); - } - tmp[byteCount - 1] &= 0x7f; - out.write(tmp, 0, tmp.length); - } - } - - private void doOutput(ByteArrayOutputStream aOut) - { - OIDTokenizer tok = new OIDTokenizer(identifier); - int first = Integer.parseInt(tok.nextToken()) * 40; - - String secondToken = tok.nextToken(); - if (secondToken.length() <= 18) - { - writeField(aOut, first + Long.parseLong(secondToken)); - } - else - { - writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first))); - } - - while (tok.hasMoreTokens()) - { - String token = tok.nextToken(); - if (token.length() <= 18) - { - writeField(aOut, Long.parseLong(token)); - } - else - { - writeField(aOut, new BigInteger(token)); - } - } - } - - protected synchronized byte[] getBody() - { - if (body == null) - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - doOutput(bOut); - - body = bOut.toByteArray(); - } - - return body; - } - - boolean isConstructed() - { - return false; - } - - int encodedLength() - throws IOException - { - int length = getBody().length; - - return 1 + StreamUtil.calculateBodyLength(length) + length; - } - - void encode( - ASN1OutputStream out) - throws IOException - { - byte[] enc = getBody(); - - out.write(BERTags.OBJECT_IDENTIFIER); - out.writeLength(enc.length); - out.write(enc); - } - - public int hashCode() - { - return identifier.hashCode(); - } - - boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DERObjectIdentifier)) - { - return false; - } - - return identifier.equals(((DERObjectIdentifier)o).identifier); - } - - public String toString() - { - return getId(); - } - - private static boolean isValidBranchID( - String branchID, int start) - { - boolean periodAllowed = false; - - int pos = branchID.length(); - while (--pos >= start) - { - char ch = branchID.charAt(pos); - - // TODO Leading zeroes? - if ('0' <= ch && ch <= '9') - { - periodAllowed = true; - continue; - } - - if (ch == '.') - { - if (!periodAllowed) - { - return false; - } - - periodAllowed = false; - continue; - } - - return false; - } - - return periodAllowed; - } - - private static boolean isValidIdentifier( - String identifier) - { - if (identifier.length() < 3 || identifier.charAt(1) != '.') - { - return false; - } - - char first = identifier.charAt(0); - if (first < '0' || first > '2') - { - return false; - } - - return isValidBranchID(identifier, 2); - } - - private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][]; - - static ASN1ObjectIdentifier fromOctetString(byte[] enc) - { - if (enc.length < 3) - { - return new ASN1ObjectIdentifier(enc); - } - - int idx1 = enc[enc.length - 2] & 0xff; - // in this case top bit is always zero - int idx2 = enc[enc.length - 1] & 0x7f; - - ASN1ObjectIdentifier possibleMatch; - - synchronized (cache) - { - ASN1ObjectIdentifier[] first = cache[idx1]; - if (first == null) - { - first = cache[idx1] = new ASN1ObjectIdentifier[128]; - } - - possibleMatch = first[idx2]; - if (possibleMatch == null) - { - return first[idx2] = new ASN1ObjectIdentifier(enc); - } - - if (Arrays.areEqual(enc, possibleMatch.getBody())) - { - return possibleMatch; - } - - idx1 = (idx1 + 1) & 0xff; - first = cache[idx1]; - if (first == null) - { - first = cache[idx1] = new ASN1ObjectIdentifier[128]; - } - - possibleMatch = first[idx2]; - if (possibleMatch == null) - { - return first[idx2] = new ASN1ObjectIdentifier(enc); - } - - if (Arrays.areEqual(enc, possibleMatch.getBody())) - { - return possibleMatch; - } - - idx2 = (idx2 + 1) & 0x7f; - possibleMatch = first[idx2]; - if (possibleMatch == null) - { - return first[idx2] = new ASN1ObjectIdentifier(enc); - } - } - - if (Arrays.areEqual(enc, possibleMatch.getBody())) - { - return possibleMatch; - } - - return new ASN1ObjectIdentifier(enc); + super(oid, branch); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetString.java index 988186f..1201c74 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetString.java @@ -2,10 +2,15 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * Carrier class for a DER encoding OCTET STRING + */ public class DEROctetString extends ASN1OctetString { /** + * Base constructor. + * * @param string the octets making up the octet string. */ public DEROctetString( @@ -14,6 +19,11 @@ public class DEROctetString super(string); } + /** + * Constructor from the encoding of an ASN.1 object. + * + * @param obj the object to be encoded. + */ public DEROctetString( ASN1Encodable obj) throws IOException diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java index e6e2068..58be862 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java @@ -3,6 +3,9 @@ package org.bouncycastle.asn1; import java.io.IOException; import java.io.InputStream; +/** + * Parse for DER encoded OCTET STRINGS + */ public class DEROctetStringParser implements ASN1OctetStringParser { @@ -14,17 +17,33 @@ public class DEROctetStringParser this.stream = stream; } + /** + * Return an InputStream representing the contents of the OCTET STRING. + * + * @return an InputStream with its source as the OCTET STRING content. + */ public InputStream getOctetStream() { return stream; } + /** + * Return an in-memory, encodable, representation of the OCTET STRING. + * + * @return a DEROctetString. + * @throws IOException if there is an issue loading the data. + */ public ASN1Primitive getLoadedObject() throws IOException { return new DEROctetString(stream.toByteArray()); } - + + /** + * Return an DEROctetString representing this parser and its contents. + * + * @return an DEROctetString + */ public ASN1Primitive toASN1Primitive() { try diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java index 59d0110..805ad30 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java @@ -12,14 +12,14 @@ public class DERPrintableString extends ASN1Primitive implements ASN1String { - // BEGIN android-changed private final byte[] string; - // END android-changed /** * return a printable string from the passed in object. - * + * + * @param obj a DERPrintableString or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERPrintableString instance, or null. */ public static DERPrintableString getInstance( Object obj) @@ -52,6 +52,7 @@ public class DERPrintableString * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return a DERPrintableString instance, or null. */ public static DERPrintableString getInstance( ASN1TaggedObject obj, diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java index ad48a83..b631064 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java @@ -17,6 +17,7 @@ public class DERSequence /** * create a sequence containing one object + * @param obj the object to go in the sequence. */ public DERSequence( ASN1Encodable obj) @@ -26,6 +27,7 @@ public class DERSequence /** * create a sequence containing a vector of objects. + * @param v the vector of objects to make up the sequence. */ public DERSequence( ASN1EncodableVector v) @@ -35,6 +37,7 @@ public class DERSequence /** * create a sequence containing an array of objects. + * @param array the array of objects to make up the sequence. */ public DERSequence( ASN1Encodable[] array) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java index c1faf84..ac58eac 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java @@ -19,7 +19,8 @@ public class DERSet } /** - * @param obj - a single object that makes up the set. + * create a set containing one object + * @param obj the object to go in the set */ public DERSet( ASN1Encodable obj) @@ -28,7 +29,8 @@ public class DERSet } /** - * @param v - a vector of objects making up the set. + * create a set containing a vector of objects. + * @param v the vector of objects to make up the set. */ public DERSet( ASN1EncodableVector v) @@ -37,7 +39,8 @@ public class DERSet } /** - * create a set from an array of objects. + * create a set containing an array of objects. + * @param a the array of objects to make up the set. */ public DERSet( ASN1Encodable[] a) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java index d50fb7c..30744c6 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java @@ -13,12 +13,14 @@ public class DERT61String extends ASN1Primitive implements ASN1String { - private byte[] string; + private final byte[] string; /** * return a T61 string from the passed in object. * + * @param obj a DERT61String or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERT61String instance, or null */ public static DERT61String getInstance( Object obj) @@ -51,6 +53,7 @@ public class DERT61String * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return a DERT61String instance, or null */ public static DERT61String getInstance( ASN1TaggedObject obj, @@ -70,6 +73,8 @@ public class DERT61String /** * basic constructor - string encoded as a sequence of bytes. + * + * @param string the byte encoding of the string to be wrapped. */ public DERT61String( byte[] string) @@ -79,6 +84,8 @@ public class DERT61String /** * basic constructor - with string 8 bit assumed. + * + * @param string the string to be wrapped. */ public DERT61String( String string) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUTCTime.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUTCTime.java index c5bd536..18e17b1 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUTCTime.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUTCTime.java @@ -1,278 +1,27 @@ package org.bouncycastle.asn1; -import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Date; -import java.util.SimpleTimeZone; - -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Strings; /** - * UTC time object. + * DER UTC time object. */ public class DERUTCTime - extends ASN1Primitive + extends ASN1UTCTime { - private byte[] time; - - /** - * return an UTC Time from the passed in object. - * - * @exception IllegalArgumentException if the object cannot be converted. - */ - public static ASN1UTCTime getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1UTCTime) - { - return (ASN1UTCTime)obj; - } - - if (obj instanceof DERUTCTime) - { - return new ASN1UTCTime(((DERUTCTime)obj).time); - } - - if (obj instanceof byte[]) - { - try - { - return (ASN1UTCTime)fromByteArray((byte[])obj); - } - catch (Exception e) - { - throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); - } - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - - /** - * return an UTC Time from a tagged object. - * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @exception IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1UTCTime getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Object o = obj.getObject(); - - if (explicit || o instanceof ASN1UTCTime) - { - return getInstance(o); - } - else - { - return new ASN1UTCTime(((ASN1OctetString)o).getOctets()); - } - } - - /** - * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were - * never encoded. When you're creating one of these objects from scratch, that's - * what you want to use, otherwise we'll try to deal with whatever gets read from - * the input stream... (this is why the input format is different from the getTime() - * method output). - *

- * - * @param time the time string. - */ - public DERUTCTime( - String time) - { - this.time = Strings.toByteArray(time); - try - { - this.getDate(); - } - catch (ParseException e) - { - throw new IllegalArgumentException("invalid date string: " + e.getMessage()); - } - } - - /** - * base constructer from a java.util.date object - */ - public DERUTCTime( - Date time) - { - SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); - - dateF.setTimeZone(new SimpleTimeZone(0,"Z")); - - this.time = Strings.toByteArray(dateF.format(time)); - } - - DERUTCTime( - byte[] time) - { - this.time = time; - } - - /** - * return the time as a date based on whatever a 2 digit year will return. For - * standardised processing use getAdjustedDate(). - * - * @return the resulting date - * @exception ParseException if the date string cannot be parsed. - */ - public Date getDate() - throws ParseException - { - SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz"); - - return dateF.parse(getTime()); - } - - /** - * return the time as an adjusted date - * in the range of 1950 - 2049. - * - * @return a date in the range of 1950 to 2049. - * @exception ParseException if the date string cannot be parsed. - */ - public Date getAdjustedDate() - throws ParseException + DERUTCTime(byte[] bytes) { - SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); - - dateF.setTimeZone(new SimpleTimeZone(0, "Z")); - - return dateF.parse(getAdjustedTime()); - } - - /** - * return the time - always in the form of - * YYMMDDhhmmssGMT(+hh:mm|-hh:mm). - *

- * Normally in a certificate we would expect "Z" rather than "GMT", - * however adding the "GMT" means we can just use: - *

-     *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
-     * 
- * To read in the time and get a date which is compatible with our local - * time zone. - *

- * Note: In some cases, due to the local date processing, this - * may lead to unexpected results. If you want to stick the normal - * convention of 1950 to 2049 use the getAdjustedTime() method. - */ - public String getTime() - { - String stime = Strings.fromByteArray(time); - - // - // standardise the format. - // - if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0) - { - if (stime.length() == 11) - { - return stime.substring(0, 10) + "00GMT+00:00"; - } - else - { - return stime.substring(0, 12) + "GMT+00:00"; - } - } - else - { - int index = stime.indexOf('-'); - if (index < 0) - { - index = stime.indexOf('+'); - } - String d = stime; - - if (index == stime.length() - 3) - { - d += "00"; - } - - if (index == 10) - { - return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15); - } - else - { - return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17); - } - } - } - - /** - * return a time string as an adjusted date with a 4 digit year. This goes - * in the range of 1950 - 2049. - */ - public String getAdjustedTime() - { - String d = this.getTime(); - - if (d.charAt(0) < '5') - { - return "20" + d; - } - else - { - return "19" + d; - } - } - - boolean isConstructed() - { - return false; + super(bytes); } - int encodedLength() + public DERUTCTime(Date time) { - int length = time.length; - - return 1 + StreamUtil.calculateBodyLength(length) + length; + super(time); } - void encode( - ASN1OutputStream out) - throws IOException + public DERUTCTime(String time) { - out.write(BERTags.UTC_TIME); - - int length = time.length; - - out.writeLength(length); - - for (int i = 0; i != length; i++) - { - out.write((byte)time[i]); - } + super(time); } - - boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DERUTCTime)) - { - return false; - } - return Arrays.areEqual(time, ((DERUTCTime)o).time); - } - - public int hashCode() - { - return Arrays.hashCode(time); - } - - public String toString() - { - return Strings.fromByteArray(time); - } + // TODO: create proper DER encoding. } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUTF8String.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUTF8String.java index fa34b22..d1fffa6 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUTF8String.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUTF8String.java @@ -12,13 +12,15 @@ public class DERUTF8String extends ASN1Primitive implements ASN1String { - private byte[] string; + private final byte[] string; /** - * return an UTF8 string from the passed in object. - * + * Return an UTF8 string from the passed in object. + * + * @param obj a DERUTF8String or an object that can be converted into one. * @exception IllegalArgumentException * if the object cannot be converted. + * @return a DERUTF8String instance, or null */ public static DERUTF8String getInstance(Object obj) { @@ -44,7 +46,7 @@ public class DERUTF8String } /** - * return an UTF8 String from a tagged object. + * Return an UTF8 String from a tagged object. * * @param obj * the tagged object holding the object we want @@ -53,6 +55,7 @@ public class DERUTF8String * otherwise. * @exception IllegalArgumentException * if the tagged object cannot be converted. + * @return a DERUTF8String instance, or null */ public static DERUTF8String getInstance( ASN1TaggedObject obj, @@ -70,8 +73,8 @@ public class DERUTF8String } } - /** - * basic constructor - byte encoded string. + /* + * Basic constructor - byte encoded string. */ DERUTF8String(byte[] string) { @@ -79,7 +82,9 @@ public class DERUTF8String } /** - * basic constructor + * Basic constructor + * + * @param string the string to be carried in the UTF8String object, */ public DERUTF8String(String string) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java index 51b0799..8539099 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java @@ -13,12 +13,14 @@ public class DERUniversalString implements ASN1String { private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - private byte[] string; + private final byte[] string; /** * return a Universal String from the passed in object. * + * @param obj a DERUniversalString or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERUniversalString instance, or null */ public static DERUniversalString getInstance( Object obj) @@ -51,6 +53,7 @@ public class DERUniversalString * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return a DERUniversalString instance, or null */ public static DERUniversalString getInstance( ASN1TaggedObject obj, @@ -70,6 +73,8 @@ public class DERUniversalString /** * basic constructor - byte encoded string. + * + * @param string the byte encoding of the string to be carried in the UniversalString object, */ public DERUniversalString( byte[] string) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERVideotexString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERVideotexString.java new file mode 100644 index 0000000..da231e1 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERVideotexString.java @@ -0,0 +1,124 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class DERVideotexString + extends ASN1Primitive + implements ASN1String +{ + private final byte[] string; + + /** + * return a Videotex String from the passed in object + * + * @param obj a DERVideotexString or an object that can be converted into one. + * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERVideotexString instance, or null. + */ + public static DERVideotexString getInstance( + Object obj) + { + if (obj == null || obj instanceof DERVideotexString) + { + return (DERVideotexString)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (DERVideotexString)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Videotex String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + * @return a DERVideotexString instance, or null. + */ + public static DERVideotexString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DERVideotexString) + { + return getInstance(o); + } + else + { + return new DERVideotexString(((ASN1OctetString)o).getOctets()); + } + } + + /** + * basic constructor - with bytes. + * @param string the byte encoding of the characters making up the string. + */ + public DERVideotexString( + byte[] string) + { + this.string = Arrays.clone(string); + } + + public byte[] getOctets() + { + return Arrays.clone(string); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.VIDEOTEX_STRING, string); + } + + public int hashCode() + { + return Arrays.hashCode(string); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof DERVideotexString)) + { + return false; + } + + DERVideotexString s = (DERVideotexString)o; + + return Arrays.areEqual(string, s.string); + } + + public String getString() + { + return Strings.fromByteArray(string); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERVisibleString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERVisibleString.java index 18e7d73..5932c97 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERVisibleString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DERVisibleString.java @@ -6,18 +6,23 @@ import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; /** - * DER VisibleString object. + * DER VisibleString object encoding ISO 646 (ASCII) character code points 32 to 126. + *

+ * Explicit character set escape sequences are not allowed. + *

*/ public class DERVisibleString extends ASN1Primitive implements ASN1String { - private byte[] string; + private final byte[] string; /** - * return a Visible String from the passed in object. + * Return a Visible String from the passed in object. * + * @param obj a DERVisibleString or an object that can be converted into one. * @exception IllegalArgumentException if the object cannot be converted. + * @return a DERVisibleString instance, or null */ public static DERVisibleString getInstance( Object obj) @@ -43,13 +48,14 @@ public class DERVisibleString } /** - * return a Visible String from a tagged object. + * Return a Visible String from a tagged object. * * @param obj the tagged object holding the object we want * @param explicit true if the object is meant to be explicitly * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. + * @return a DERVisibleString instance, or null */ public static DERVisibleString getInstance( ASN1TaggedObject obj, @@ -67,8 +73,8 @@ public class DERVisibleString } } - /** - * basic constructor - byte encoded string. + /* + * Basic constructor - byte encoded string. */ DERVisibleString( byte[] string) @@ -77,7 +83,9 @@ public class DERVisibleString } /** - * basic constructor + * Basic constructor + * + * @param string the string to be carried in the VisibleString object, */ public DERVisibleString( String string) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java new file mode 100644 index 0000000..c81f0ab --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLBitString.java @@ -0,0 +1,145 @@ +package org.bouncycastle.asn1; + +import java.io.IOException; + +/** + * A Definite length BIT STRING + */ +public class DLBitString + extends ASN1BitString +{ + /** + * return a Bit String that can be definite-length encoded from the passed in object. + * + * @param obj a DL or DER BitString or an object that can be converted into one. + * @exception IllegalArgumentException if the object cannot be converted. + * @return an ASN1BitString instance, or null. + */ + public static ASN1BitString getInstance( + Object obj) + { + if (obj == null || obj instanceof DLBitString) + { + return (DLBitString)obj; + } + if (obj instanceof DERBitString) + { + return (DERBitString)obj; + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return a Bit String from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + * @return an ASN1BitString instance, or null. + */ + public static ASN1BitString getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof DLBitString) + { + return getInstance(o); + } + else + { + return fromOctetString(((ASN1OctetString)o).getOctets()); + } + } + + protected DLBitString( + byte data, + int padBits) + { + this(toByteArray(data), padBits); + } + + private static byte[] toByteArray(byte data) + { + byte[] rv = new byte[1]; + + rv[0] = data; + + return rv; + } + + /** + * @param data the octets making up the bit string. + * @param padBits the number of extra bits at the end of the string. + */ + public DLBitString( + byte[] data, + int padBits) + { + super(data, padBits); + } + + public DLBitString( + byte[] data) + { + this(data, 0); + } + + public DLBitString( + int value) + { + super(getBytes(value), getPadBits(value)); + } + + public DLBitString( + ASN1Encodable obj) + throws IOException + { + super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER), 0); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + byte[] string = data; + byte[] bytes = new byte[string.length + 1]; + + bytes[0] = (byte)getPadBits(); + System.arraycopy(string, 0, bytes, 1, bytes.length - 1); + + out.writeEncoded(BERTags.BIT_STRING, bytes); + } + + static DLBitString fromOctetString(byte[] bytes) + { + if (bytes.length < 1) + { + throw new IllegalArgumentException("truncated BIT STRING detected"); + } + + int padBits = bytes[0]; + byte[] data = new byte[bytes.length - 1]; + + if (data.length != 0) + { + System.arraycopy(bytes, 1, data, 0, bytes.length - 1); + } + + return new DLBitString(data, padBits); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java index b5cc59a..65acd27 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java @@ -19,7 +19,8 @@ public class DLSequence } /** - * Create a sequence containing one object + * create a sequence containing one object + * @param obj the object to go in the sequence. */ public DLSequence( ASN1Encodable obj) @@ -28,7 +29,8 @@ public class DLSequence } /** - * Create a sequence containing a vector of objects. + * create a sequence containing a vector of objects. + * @param v the vector of objects to make up the sequence. */ public DLSequence( ASN1EncodableVector v) @@ -37,7 +39,8 @@ public class DLSequence } /** - * Create a sequence containing an array of objects. + * create a sequence containing an array of objects. + * @param array the array of objects to make up the sequence. */ public DLSequence( ASN1Encodable[] array) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java index 91e83fa..e3042c2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java @@ -11,13 +11,13 @@ import java.util.Enumeration; *

8: Basic encoding rules

*

8.11 Encoding of a set value

* 8.11.1 The encoding of a set value shall be constructed - *

+ *

* 8.11.2 The contents octets shall consist of the complete * encoding of a data value from each of the types listed in the * ASN.1 definition of the set type, in an order chosen by the sender, * unless the type was referenced with the keyword * OPTIONAL or the keyword DEFAULT. - *

+ *

* 8.11.3 The encoding of a data value may, but need not, * be present for a type which was referenced with the keyword * OPTIONAL or the keyword DEFAULT. diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java index a4b1492..734298b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java @@ -2,8 +2,16 @@ package org.bouncycastle.asn1; import java.io.IOException; +/** + * Interface implemented by objects that can be converted from streaming to in-memory objects. + */ public interface InMemoryRepresentable { + /** + * Get the in-memory representation of the ASN.1 object. + * @return an ASN1Primitive representing the loaded object. + * @throws IOException for bad input data. + */ ASN1Primitive getLoadedObject() throws IOException; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java index 5467944..4c896ad 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java @@ -1,7 +1,7 @@ package org.bouncycastle.asn1; /** - * class for breaking up an OID into it's component tokens, ala + * Class for breaking up an OID into it's component tokens, ala * java.util.StringTokenizer. We need this class as some of the * lightweight Java environment don't support classes like * StringTokenizer. @@ -11,6 +11,11 @@ public class OIDTokenizer private String oid; private int index; + /** + * Base constructor. + * + * @param oid the string representation of the OID. + */ public OIDTokenizer( String oid) { @@ -18,11 +23,21 @@ public class OIDTokenizer this.index = 0; } + /** + * Return whether or not there are more tokens in this tokenizer. + * + * @return true if there are more tokens, false otherwise. + */ public boolean hasMoreTokens() { return (index != -1); } + /** + * Return the next token in the underlying String. + * + * @return the next token. + */ public String nextToken() { if (index == -1) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java index 16a6768..5b95b79 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java @@ -3,9 +3,7 @@ package org.bouncycastle.asn1.bc; import org.bouncycastle.asn1.ASN1ObjectIdentifier; /** - * iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle - *

- * 1.3.6.1.4.1.22554 + * Object Identifiers belonging to iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle (1.3.6.1.4.1.22554) */ public interface BCObjectIdentifiers { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java index 066cf69..8c48743 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java @@ -7,7 +7,6 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; /** @@ -73,17 +72,6 @@ public class Attribute attrValues = (ASN1Set)seq.getObjectAt(1); } - /** - * @deprecated use ASN1ObjectIdentifier - */ - public Attribute( - DERObjectIdentifier attrType, - ASN1Set attrValues) - { - this.attrType = new ASN1ObjectIdentifier(attrType.getId()); - this.attrValues = attrValues; - } - public Attribute( ASN1ObjectIdentifier attrType, ASN1Set attrValues) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java index 02b6cc1..7550282 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java @@ -8,7 +8,6 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSet; /** @@ -90,14 +89,6 @@ public class AttributeTable } } - /** - * @deprecated use ASN1ObjectIdentifier - */ - public Attribute get(DERObjectIdentifier oid) - { - return get(new ASN1ObjectIdentifier(oid.getId())); - } - /** * Return the first attribute matching the OBJECT IDENTIFIER oid. * @@ -117,14 +108,6 @@ public class AttributeTable return (Attribute)value; } - /** - * @deprecated use ASN1ObjectIdentifier - */ - public ASN1EncodableVector getAll(DERObjectIdentifier oid) - { - return getAll(new ASN1ObjectIdentifier(oid.getId())); - } - /** * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be * empty if there are no attributes of the required type present. @@ -233,9 +216,9 @@ public class AttributeTable /** * Return a new table with the passed in attribute added. * - * @param attrType - * @param attrValue - * @return + * @param attrType the type of the attribute to add. + * @param attrValue the value corresponding to the attribute (will be wrapped in a SET). + * @return a new table with the extra attribute in it. */ public AttributeTable add(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java new file mode 100644 index 0000000..d18fe4b --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java @@ -0,0 +1,136 @@ +package org.bouncycastle.asn1.cms; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * From RFC 6211 + *

+ * CMSAlgorithmProtection ::= SEQUENCE {
+ *    digestAlgorithm         DigestAlgorithmIdentifier,
+ *    signatureAlgorithm  [1] SignatureAlgorithmIdentifier OPTIONAL,
+ *    macAlgorithm        [2] MessageAuthenticationCodeAlgorithm
+ *                                     OPTIONAL
+ * }
+ * (WITH COMPONENTS { signatureAlgorithm PRESENT,
+ *                    macAlgorithm ABSENT } |
+ *  WITH COMPONENTS { signatureAlgorithm ABSENT,
+ *                    macAlgorithm PRESENT })
+ * 
+ */ +public class CMSAlgorithmProtection + extends ASN1Object +{ + public static final int SIGNATURE = 1; + public static final int MAC = 2; + + private final AlgorithmIdentifier digestAlgorithm; + private final AlgorithmIdentifier signatureAlgorithm; + private final AlgorithmIdentifier macAlgorithm; + + public CMSAlgorithmProtection(AlgorithmIdentifier digestAlgorithm, int type, AlgorithmIdentifier algorithmIdentifier) + { + if (digestAlgorithm == null || algorithmIdentifier == null) + { + throw new NullPointerException("AlgorithmIdentifiers cannot be null"); + } + + this.digestAlgorithm = digestAlgorithm; + + if (type == 1) + { + this.signatureAlgorithm = algorithmIdentifier; + this.macAlgorithm = null; + } + else if (type == 2) + { + this.signatureAlgorithm = null; + this.macAlgorithm = algorithmIdentifier; + } + else + { + throw new IllegalArgumentException("Unknown type: " + type); + } + } + + private CMSAlgorithmProtection(ASN1Sequence sequence) + { + if (sequence.size() != 2) + { + throw new IllegalArgumentException("Sequence wrong size: One of signatureAlgorithm or macAlgorithm must be present"); + } + + this.digestAlgorithm = AlgorithmIdentifier.getInstance(sequence.getObjectAt(0)); + + ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(sequence.getObjectAt(1)); + if (tagged.getTagNo() == 1) + { + this.signatureAlgorithm = AlgorithmIdentifier.getInstance(tagged, false); + this.macAlgorithm = null; + } + else if (tagged.getTagNo() == 2) + { + this.signatureAlgorithm = null; + + this.macAlgorithm = AlgorithmIdentifier.getInstance(tagged, false); + } + else + { + throw new IllegalArgumentException("Unknown tag found: " + tagged.getTagNo()); + } + } + + public static CMSAlgorithmProtection getInstance( + Object obj) + { + if (obj instanceof CMSAlgorithmProtection) + { + return (CMSAlgorithmProtection)obj; + } + else if (obj != null) + { + return new CMSAlgorithmProtection(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + + public AlgorithmIdentifier getDigestAlgorithm() + { + return digestAlgorithm; + } + + public AlgorithmIdentifier getMacAlgorithm() + { + return macAlgorithm; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(digestAlgorithm); + if (signatureAlgorithm != null) + { + v.add(new DERTaggedObject(false, 1, signatureAlgorithm)); + } + if (macAlgorithm != null) + { + v.add(new DERTaggedObject(false, 2, macAlgorithm)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java index d2fc7d1..71c85fb 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java @@ -5,13 +5,15 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; /** * RFC 5652 CMS attribute OID constants. + * and RFC 6211 Algorithm Identifier Protection Attribute. *
  * contentType      ::= 1.2.840.113549.1.9.3
  * messageDigest    ::= 1.2.840.113549.1.9.4
  * signingTime      ::= 1.2.840.113549.1.9.5
  * counterSignature ::= 1.2.840.113549.1.9.6
  *
- * contentHint      ::= 1.2.840.113549.1.9.16.2.4 
+ * contentHint      ::= 1.2.840.113549.1.9.16.2.4
+ * cmsAlgorithmProtect := 1.2.840.113549.1.9.52
  * 
*/ @@ -27,4 +29,7 @@ public interface CMSAttributes public static final ASN1ObjectIdentifier counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature; /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See RFC 2634 */ public static final ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint; + + public static final ASN1ObjectIdentifier cmsAlgorithmProtect = PKCSObjectIdentifiers.id_aa_cmsAlgorithmProtect; + } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java index 8c7fcc2..7027897 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java @@ -34,7 +34,7 @@ import org.bouncycastle.asn1.DERTaggedObject; * SignerInfos ::= SET OF SignerInfo * *

- * The version calculation uses following ruleset from RFC 3852 section 5.1: + * The version calculation uses following ruleset from RFC 5652 section 5.1: *

  * IF ((certificates is present) AND
  *    (any certificates with a type of other are present)) OR
@@ -54,7 +54,6 @@ import org.bouncycastle.asn1.DERTaggedObject;
  *       ELSE version MUST be 1
  * 
*

- * @todo Check possible update for this to RFC 5652 level */ public class SignedData extends ASN1Object @@ -84,7 +83,8 @@ public class SignedData * * * @param o the object we want converted. - * @exception IllegalArgumentException if the object cannot be converted. + * @return a reference that can be assigned to SignedData (may be null) + * @throws IllegalArgumentException if the object cannot be converted. */ public static SignedData getInstance( Object o) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java index 4209045..486eae2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java @@ -39,7 +39,7 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier; * * ----------------------------------------- * - * RFC 5256: + * RFC 5652: * * SignerInfo ::= SEQUENCE { * version CMSVersion, diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java index 977fce6..ed9a6c0 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java @@ -2,13 +2,17 @@ package org.bouncycastle.asn1.cms; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; +import java.util.Locale; import java.util.SimpleTimeZone; import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1GeneralizedTime; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.ASN1UTCTime; import org.bouncycastle.asn1.DERGeneralizedTime; import org.bouncycastle.asn1.DERUTCTime; @@ -47,8 +51,8 @@ public class Time public Time( ASN1Primitive time) { - if (!(time instanceof DERUTCTime) - && !(time instanceof DERGeneralizedTime)) + if (!(time instanceof ASN1UTCTime) + && !(time instanceof ASN1GeneralizedTime)) { throw new IllegalArgumentException("unknown object passed to Time"); } @@ -57,28 +61,68 @@ public class Time } /** - * Create a time object from a given date - if the year is in between 1950 + * Creates a time object from a given date - if the date is between 1950 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime * is used. + * + * @param time a date object representing the time of interest. + */ + public Time( + Date time) + { + SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); + // END android-changed + + dateF.setTimeZone(tz); + + String d = dateF.format(time) + "Z"; + int year = Integer.parseInt(d.substring(0, 4)); + + if (year < 1950 || year > 2049) + { + this.time = new DERGeneralizedTime(d); + } + else + { + this.time = new DERUTCTime(d.substring(2)); + } + } + + /** + * Creates a time object from a given date and locale - if the date is between 1950 + * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime + * is used. You may need to use this constructor if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param time a date object representing the time of interest. + * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. */ public Time( - Date date) + Date time, + Locale locale) { SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); - SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); + dateF.setCalendar(Calendar.getInstance(locale)); + // END android-changed dateF.setTimeZone(tz); - String d = dateF.format(date) + "Z"; + String d = dateF.format(time) + "Z"; int year = Integer.parseInt(d.substring(0, 4)); if (year < 1950 || year > 2049) { - time = new DERGeneralizedTime(d); + this.time = new DERGeneralizedTime(d); } else { - time = new DERUTCTime(d.substring(2)); + this.time = new DERUTCTime(d.substring(2)); } } @@ -103,13 +147,13 @@ public class Time { return (Time)obj; } - else if (obj instanceof DERUTCTime) + else if (obj instanceof ASN1UTCTime) { - return new Time((DERUTCTime)obj); + return new Time((ASN1UTCTime)obj); } - else if (obj instanceof DERGeneralizedTime) + else if (obj instanceof ASN1GeneralizedTime) { - return new Time((DERGeneralizedTime)obj); + return new Time((ASN1GeneralizedTime)obj); } throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); @@ -120,13 +164,13 @@ public class Time */ public String getTime() { - if (time instanceof DERUTCTime) + if (time instanceof ASN1UTCTime) { - return ((DERUTCTime)time).getAdjustedTime(); + return ((ASN1UTCTime)time).getAdjustedTime(); } else { - return ((DERGeneralizedTime)time).getTime(); + return ((ASN1GeneralizedTime)time).getTime(); } } @@ -137,13 +181,13 @@ public class Time { try { - if (time instanceof DERUTCTime) + if (time instanceof ASN1UTCTime) { - return ((DERUTCTime)time).getAdjustedDate(); + return ((ASN1UTCTime)time).getAdjustedDate(); } else { - return ((DERGeneralizedTime)time).getDate(); + return ((ASN1GeneralizedTime)time).getDate(); } } catch (ParseException e) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java index 77416dc..805a506 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java @@ -4,17 +4,17 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; /** * German Federal Office for Information Security - * (Bundesamt für Sicherheit in der Informationstechnik) + * (Bundesamt für Sicherheit in der Informationstechnik) * http://www.bsi.bund.de/ *

* BSI TR-03110 * Technical Guideline Advanced Security Mechanisms for Machine Readable Travel Documents *

- * Technical Guideline TR-03110-3 + * + * Technical Guideline TR-03110-3 * Advanced Security Mechanisms for Machine Readable Travel Documents; * Part 3: Common Specifications. */ - public interface EACObjectIdentifiers { /** diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java index 6aff988..284751e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java @@ -35,9 +35,16 @@ public interface MiscObjectIdentifiers static final ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1"); /** Verisign CZAG (Country,Zip,Age,Gender) Extension OID: 2.16.840.1.113733.1.6.3 */ - static final ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3"); - /** Verisign D&B D-U-N-S number Extension OID: 2.16.840.1.113733.1.6.15 */ - static final ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15"); + static final ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3"); + + static final ASN1ObjectIdentifier verisignPrivate_6_9 = verisign.branch("6.9"); + static final ASN1ObjectIdentifier verisignOnSiteJurisdictionHash = verisign.branch("6.11"); + static final ASN1ObjectIdentifier verisignBitString_6_13 = verisign.branch("6.13"); + + /** Verisign D&B D-U-N-S number Extension OID: 2.16.840.1.113733.1.6.15 */ + static final ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15"); + + static final ASN1ObjectIdentifier verisignIssStrongCrypto = verisign.branch("8.1"); // // Novell @@ -56,4 +63,33 @@ public interface MiscObjectIdentifiers static final ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7"); /** NortelNetworks Entrust VersionExtension OID: 1.2.840.113533.7.65.0 */ static final ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0"); + + /** cast5CBC OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) nt(113533) nsn(7) algorithms(66) 10} SEE RFC 2984 */ + ASN1ObjectIdentifier cast5CBC = entrust.branch("66.10"); + + // + // Ascom + // + ASN1ObjectIdentifier as_sys_sec_alg_ideaCBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2"); + + // + // Peter Gutmann's Cryptlib + // + ASN1ObjectIdentifier cryptlib = new ASN1ObjectIdentifier("1.3.6.1.4.1.3029"); + + ASN1ObjectIdentifier cryptlib_algorithm = cryptlib.branch("1"); + ASN1ObjectIdentifier cryptlib_algorithm_blowfish_ECB = cryptlib_algorithm.branch("1.1"); + ASN1ObjectIdentifier cryptlib_algorithm_blowfish_CBC = cryptlib_algorithm.branch("1.2"); + ASN1ObjectIdentifier cryptlib_algorithm_blowfish_CFB = cryptlib_algorithm.branch("1.3"); + ASN1ObjectIdentifier cryptlib_algorithm_blowfish_OFB = cryptlib_algorithm.branch("1.4"); + + // + // Blake2b + // + ASN1ObjectIdentifier blake2 = new ASN1ObjectIdentifier("1.3.6.1.4.1.1722.12.2"); + + ASN1ObjectIdentifier id_blake2b160 = blake2.branch("1.5"); + ASN1ObjectIdentifier id_blake2b256 = blake2.branch("1.8"); + ASN1ObjectIdentifier id_blake2b384 = blake2.branch("1.12"); + ASN1ObjectIdentifier id_blake2b512 = blake2.branch("1.16"); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java index ba7e518..19077e4 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java @@ -17,42 +17,38 @@ public class NISTNamedCurves static final Hashtable objIds = new Hashtable(); static final Hashtable names = new Hashtable(); - static void defineCurve(String name, ASN1ObjectIdentifier oid) + static void defineCurveAlias(String name, ASN1ObjectIdentifier oid) { - objIds.put(name, oid); + objIds.put(name.toUpperCase(), oid); names.put(oid, name); } static { - defineCurve("B-571", SECObjectIdentifiers.sect571r1); - defineCurve("B-409", SECObjectIdentifiers.sect409r1); - defineCurve("B-283", SECObjectIdentifiers.sect283r1); - defineCurve("B-233", SECObjectIdentifiers.sect233r1); - defineCurve("B-163", SECObjectIdentifiers.sect163r2); - defineCurve("K-571", SECObjectIdentifiers.sect571k1); - defineCurve("K-409", SECObjectIdentifiers.sect409k1); - defineCurve("K-283", SECObjectIdentifiers.sect283k1); - defineCurve("K-233", SECObjectIdentifiers.sect233k1); - defineCurve("K-163", SECObjectIdentifiers.sect163k1); - defineCurve("P-521", SECObjectIdentifiers.secp521r1); - defineCurve("P-384", SECObjectIdentifiers.secp384r1); - defineCurve("P-256", SECObjectIdentifiers.secp256r1); - defineCurve("P-224", SECObjectIdentifiers.secp224r1); - defineCurve("P-192", SECObjectIdentifiers.secp192r1); + defineCurveAlias("B-163", SECObjectIdentifiers.sect163r2); + defineCurveAlias("B-233", SECObjectIdentifiers.sect233r1); + defineCurveAlias("B-283", SECObjectIdentifiers.sect283r1); + defineCurveAlias("B-409", SECObjectIdentifiers.sect409r1); + defineCurveAlias("B-571", SECObjectIdentifiers.sect571r1); + + defineCurveAlias("K-163", SECObjectIdentifiers.sect163k1); + defineCurveAlias("K-233", SECObjectIdentifiers.sect233k1); + defineCurveAlias("K-283", SECObjectIdentifiers.sect283k1); + defineCurveAlias("K-409", SECObjectIdentifiers.sect409k1); + defineCurveAlias("K-571", SECObjectIdentifiers.sect571k1); + + defineCurveAlias("P-192", SECObjectIdentifiers.secp192r1); + defineCurveAlias("P-224", SECObjectIdentifiers.secp224r1); + defineCurveAlias("P-256", SECObjectIdentifiers.secp256r1); + defineCurveAlias("P-384", SECObjectIdentifiers.secp384r1); + defineCurveAlias("P-521", SECObjectIdentifiers.secp521r1); } public static X9ECParameters getByName( String name) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name)); - - if (oid != null) - { - return getByOID(oid); - } - - return null; + ASN1ObjectIdentifier oid = getOID(name); + return oid == null ? null : getByOID(oid); } /** @@ -94,6 +90,6 @@ public class NISTNamedCurves */ public static Enumeration getNames() { - return objIds.keys(); + return names.elements(); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java index e3613c6..0de40f2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java @@ -31,6 +31,19 @@ public interface NISTObjectIdentifiers /** 2.16.840.1.101.3.4.2.6 */ static final ASN1ObjectIdentifier id_sha512_256 = hashAlgs.branch("6"); + /** 2.16.840.1.101.3.4.2.7 */ + static final ASN1ObjectIdentifier id_sha3_224 = hashAlgs.branch("7"); + /** 2.16.840.1.101.3.4.2.8 */ + static final ASN1ObjectIdentifier id_sha3_256 = hashAlgs.branch("8"); + /** 2.16.840.1.101.3.4.2.9 */ + static final ASN1ObjectIdentifier id_sha3_384 = hashAlgs.branch("9"); + /** 2.16.840.1.101.3.4.2.10 */ + static final ASN1ObjectIdentifier id_sha3_512 = hashAlgs.branch("10"); + /** 2.16.840.1.101.3.4.2.11 */ + static final ASN1ObjectIdentifier id_shake128 = hashAlgs.branch("11"); + /** 2.16.840.1.101.3.4.2.12 */ + static final ASN1ObjectIdentifier id_shake256 = hashAlgs.branch("12"); + /** 2.16.840.1.101.3.4.1 */ static final ASN1ObjectIdentifier aes = nistAlgorithm.branch("1"); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java new file mode 100644 index 0000000..1b2e7f5 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java @@ -0,0 +1,112 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class BasicOCSPResponse + extends ASN1Object +{ + private ResponseData tbsResponseData; + private AlgorithmIdentifier signatureAlgorithm; + private DERBitString signature; + private ASN1Sequence certs; + + public BasicOCSPResponse( + ResponseData tbsResponseData, + AlgorithmIdentifier signatureAlgorithm, + DERBitString signature, + ASN1Sequence certs) + { + this.tbsResponseData = tbsResponseData; + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + this.certs = certs; + } + + private BasicOCSPResponse( + ASN1Sequence seq) + { + this.tbsResponseData = ResponseData.getInstance(seq.getObjectAt(0)); + this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1)); + this.signature = (DERBitString)seq.getObjectAt(2); + + if (seq.size() > 3) + { + this.certs = ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(3), true); + } + } + + public static BasicOCSPResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static BasicOCSPResponse getInstance( + Object obj) + { + if (obj instanceof BasicOCSPResponse) + { + return (BasicOCSPResponse)obj; + } + else if (obj != null) + { + return new BasicOCSPResponse(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ResponseData getTbsResponseData() + { + return tbsResponseData; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public DERBitString getSignature() + { + return signature; + } + + public ASN1Sequence getCerts() + { + return certs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *

+     * BasicOCSPResponse       ::= SEQUENCE {
+     *      tbsResponseData      ResponseData,
+     *      signatureAlgorithm   AlgorithmIdentifier,
+     *      signature            BIT STRING,
+     *      certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsResponseData); + v.add(signatureAlgorithm); + v.add(signature); + if (certs != null) + { + v.add(new DERTaggedObject(true, 0, certs)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java new file mode 100644 index 0000000..9d3496e --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java @@ -0,0 +1,105 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class CertID + extends ASN1Object +{ + AlgorithmIdentifier hashAlgorithm; + ASN1OctetString issuerNameHash; + ASN1OctetString issuerKeyHash; + ASN1Integer serialNumber; + + public CertID( + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString issuerNameHash, + ASN1OctetString issuerKeyHash, + ASN1Integer serialNumber) + { + this.hashAlgorithm = hashAlgorithm; + this.issuerNameHash = issuerNameHash; + this.issuerKeyHash = issuerKeyHash; + this.serialNumber = serialNumber; + } + + private CertID( + ASN1Sequence seq) + { + hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + issuerNameHash = (ASN1OctetString)seq.getObjectAt(1); + issuerKeyHash = (ASN1OctetString)seq.getObjectAt(2); + serialNumber = (ASN1Integer)seq.getObjectAt(3); + } + + public static CertID getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static CertID getInstance( + Object obj) + { + if (obj instanceof CertID) + { + return (CertID)obj; + } + else if (obj != null) + { + return new CertID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AlgorithmIdentifier getHashAlgorithm() + { + return hashAlgorithm; + } + + public ASN1OctetString getIssuerNameHash() + { + return issuerNameHash; + } + + public ASN1OctetString getIssuerKeyHash() + { + return issuerKeyHash; + } + + public ASN1Integer getSerialNumber() + { + return serialNumber; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * CertID          ::=     SEQUENCE {
+     *     hashAlgorithm       AlgorithmIdentifier,
+     *     issuerNameHash      OCTET STRING, -- Hash of Issuer's DN
+     *     issuerKeyHash       OCTET STRING, -- Hash of Issuers public key
+     *     serialNumber        CertificateSerialNumber }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(hashAlgorithm); + v.add(issuerNameHash); + v.add(issuerKeyHash); + v.add(serialNumber); + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java new file mode 100644 index 0000000..af530ae --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java @@ -0,0 +1,105 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERTaggedObject; + +public class CertStatus + extends ASN1Object + implements ASN1Choice +{ + private int tagNo; + private ASN1Encodable value; + + /** + * create a CertStatus object with a tag of zero. + */ + public CertStatus() + { + tagNo = 0; + value = DERNull.INSTANCE; + } + + public CertStatus( + RevokedInfo info) + { + tagNo = 1; + value = info; + } + + public CertStatus( + int tagNo, + ASN1Encodable value) + { + this.tagNo = tagNo; + this.value = value; + } + + public CertStatus( + ASN1TaggedObject choice) + { + this.tagNo = choice.getTagNo(); + + switch (choice.getTagNo()) + { + case 0: + value = DERNull.INSTANCE; + break; + case 1: + value = RevokedInfo.getInstance(choice, false); + break; + case 2: + value = DERNull.INSTANCE; + } + } + + public static CertStatus getInstance( + Object obj) + { + if (obj == null || obj instanceof CertStatus) + { + return (CertStatus)obj; + } + else if (obj instanceof ASN1TaggedObject) + { + return new CertStatus((ASN1TaggedObject)obj); + } + + throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); + } + + public static CertStatus getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public int getTagNo() + { + return tagNo; + } + + public ASN1Encodable getStatus() + { + return value; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     *  CertStatus ::= CHOICE {
+     *                  good        [0]     IMPLICIT NULL,
+     *                  revoked     [1]     IMPLICIT RevokedInfo,
+     *                  unknown     [2]     IMPLICIT UnknownInfo }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + return new DERTaggedObject(false, tagNo, value); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CrlID.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CrlID.java new file mode 100644 index 0000000..f5a3581 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/CrlID.java @@ -0,0 +1,110 @@ +package org.bouncycastle.asn1.ocsp; + +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class CrlID + extends ASN1Object +{ + private DERIA5String crlUrl; + private ASN1Integer crlNum; + private ASN1GeneralizedTime crlTime; + + private CrlID( + ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + + while (e.hasMoreElements()) + { + ASN1TaggedObject o = (ASN1TaggedObject)e.nextElement(); + + switch (o.getTagNo()) + { + case 0: + crlUrl = DERIA5String.getInstance(o, true); + break; + case 1: + crlNum = ASN1Integer.getInstance(o, true); + break; + case 2: + crlTime = ASN1GeneralizedTime.getInstance(o, true); + break; + default: + throw new IllegalArgumentException( + "unknown tag number: " + o.getTagNo()); + } + } + } + + public static CrlID getInstance( + Object obj) + { + if (obj instanceof CrlID) + { + return (CrlID)obj; + } + else if (obj != null) + { + return new CrlID(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public DERIA5String getCrlUrl() + { + return crlUrl; + } + + public ASN1Integer getCrlNum() + { + return crlNum; + } + + public ASN1GeneralizedTime getCrlTime() + { + return crlTime; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * CrlID ::= SEQUENCE {
+     *     crlUrl               [0]     EXPLICIT IA5String OPTIONAL,
+     *     crlNum               [1]     EXPLICIT INTEGER OPTIONAL,
+     *     crlTime              [2]     EXPLICIT GeneralizedTime OPTIONAL }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (crlUrl != null) + { + v.add(new DERTaggedObject(true, 0, crlUrl)); + } + + if (crlNum != null) + { + v.add(new DERTaggedObject(true, 1, crlNum)); + } + + if (crlTime != null) + { + v.add(new DERTaggedObject(true, 2, crlTime)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java new file mode 100644 index 0000000..577e413 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPObjectIdentifiers.java @@ -0,0 +1,34 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * OIDs for RFC 2560 and RFC 6960 + * Online Certificate Status Protocol - OCSP. + */ +public interface OCSPObjectIdentifiers +{ + /** OID: 1.3.6.1.5.5.7.48.1 */ + static final ASN1ObjectIdentifier id_pkix_ocsp = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1"); + /** OID: 1.3.6.1.5.5.7.48.1.1 */ + static final ASN1ObjectIdentifier id_pkix_ocsp_basic = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.1"); + + /** OID: 1.3.6.1.5.5.7.48.1.2 */ + static final ASN1ObjectIdentifier id_pkix_ocsp_nonce = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.2"); + /** OID: 1.3.6.1.5.5.7.48.1.3 */ + static final ASN1ObjectIdentifier id_pkix_ocsp_crl = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.3"); + + /** OID: 1.3.6.1.5.5.7.48.1.4 */ + static final ASN1ObjectIdentifier id_pkix_ocsp_response = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.4"); + /** OID: 1.3.6.1.5.5.7.48.1.5 */ + static final ASN1ObjectIdentifier id_pkix_ocsp_nocheck = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.5"); + /** OID: 1.3.6.1.5.5.7.48.1.6 */ + static final ASN1ObjectIdentifier id_pkix_ocsp_archive_cutoff = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.6"); + /** OID: 1.3.6.1.5.5.7.48.1.7 */ + static final ASN1ObjectIdentifier id_pkix_ocsp_service_locator = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.7"); + + + static final ASN1ObjectIdentifier id_pkix_ocsp_pref_sig_algs = id_pkix_ocsp.branch("8"); + + static final ASN1ObjectIdentifier id_pkix_ocsp_extended_revoke = id_pkix_ocsp.branch("9"); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java new file mode 100644 index 0000000..559cf4c --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java @@ -0,0 +1,90 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class OCSPRequest + extends ASN1Object +{ + TBSRequest tbsRequest; + Signature optionalSignature; + + public OCSPRequest( + TBSRequest tbsRequest, + Signature optionalSignature) + { + this.tbsRequest = tbsRequest; + this.optionalSignature = optionalSignature; + } + + private OCSPRequest( + ASN1Sequence seq) + { + tbsRequest = TBSRequest.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + optionalSignature = Signature.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + public static OCSPRequest getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static OCSPRequest getInstance( + Object obj) + { + if (obj instanceof OCSPRequest) + { + return (OCSPRequest)obj; + } + else if (obj != null) + { + return new OCSPRequest(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public TBSRequest getTbsRequest() + { + return tbsRequest; + } + + public Signature getOptionalSignature() + { + return optionalSignature; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * OCSPRequest     ::=     SEQUENCE {
+     *     tbsRequest                  TBSRequest,
+     *     optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsRequest); + + if (optionalSignature != null) + { + v.add(new DERTaggedObject(true, 0, optionalSignature)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java new file mode 100644 index 0000000..31602da --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java @@ -0,0 +1,90 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; + +public class OCSPResponse + extends ASN1Object +{ + OCSPResponseStatus responseStatus; + ResponseBytes responseBytes; + + public OCSPResponse( + OCSPResponseStatus responseStatus, + ResponseBytes responseBytes) + { + this.responseStatus = responseStatus; + this.responseBytes = responseBytes; + } + + private OCSPResponse( + ASN1Sequence seq) + { + responseStatus = OCSPResponseStatus.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + responseBytes = ResponseBytes.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + public static OCSPResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static OCSPResponse getInstance( + Object obj) + { + if (obj instanceof OCSPResponse) + { + return (OCSPResponse)obj; + } + else if (obj != null) + { + return new OCSPResponse(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public OCSPResponseStatus getResponseStatus() + { + return responseStatus; + } + + public ResponseBytes getResponseBytes() + { + return responseBytes; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * OCSPResponse ::= SEQUENCE {
+     *     responseStatus         OCSPResponseStatus,
+     *     responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(responseStatus); + + if (responseBytes != null) + { + v.add(new DERTaggedObject(true, 0, responseBytes)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java new file mode 100644 index 0000000..aa225f9 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java @@ -0,0 +1,71 @@ +package org.bouncycastle.asn1.ocsp; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; + +public class OCSPResponseStatus + extends ASN1Object +{ + public static final int SUCCESSFUL = 0; + public static final int MALFORMED_REQUEST = 1; + public static final int INTERNAL_ERROR = 2; + public static final int TRY_LATER = 3; + public static final int SIG_REQUIRED = 5; + public static final int UNAUTHORIZED = 6; + + private ASN1Enumerated value; + + /** + * The OCSPResponseStatus enumeration. + *
+     * OCSPResponseStatus ::= ENUMERATED {
+     *     successful            (0),  --Response has valid confirmations
+     *     malformedRequest      (1),  --Illegal confirmation request
+     *     internalError         (2),  --Internal error in issuer
+     *     tryLater              (3),  --Try again later
+     *                                 --(4) is not used
+     *     sigRequired           (5),  --Must sign the request
+     *     unauthorized          (6)   --Request unauthorized
+     * }
+     * 
+ */ + public OCSPResponseStatus( + int value) + { + this(new ASN1Enumerated(value)); + } + + private OCSPResponseStatus( + ASN1Enumerated value) + { + this.value = value; + } + + public static OCSPResponseStatus getInstance( + Object obj) + { + if (obj instanceof OCSPResponseStatus) + { + return (OCSPResponseStatus)obj; + } + else if (obj != null) + { + return new OCSPResponseStatus(ASN1Enumerated.getInstance(obj)); + } + + return null; + } + + public BigInteger getValue() + { + return value.getValue(); + } + + public ASN1Primitive toASN1Primitive() + { + return value; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/Request.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/Request.java new file mode 100644 index 0000000..236bc72 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/Request.java @@ -0,0 +1,91 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; + +public class Request + extends ASN1Object +{ + CertID reqCert; + Extensions singleRequestExtensions; + + public Request( + CertID reqCert, + Extensions singleRequestExtensions) + { + this.reqCert = reqCert; + this.singleRequestExtensions = singleRequestExtensions; + } + + private Request( + ASN1Sequence seq) + { + reqCert = CertID.getInstance(seq.getObjectAt(0)); + + if (seq.size() == 2) + { + singleRequestExtensions = Extensions.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true); + } + } + + public static Request getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Request getInstance( + Object obj) + { + if (obj instanceof Request) + { + return (Request)obj; + } + else if (obj != null) + { + return new Request(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public CertID getReqCert() + { + return reqCert; + } + + public Extensions getSingleRequestExtensions() + { + return singleRequestExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * Request         ::=     SEQUENCE {
+     *     reqCert                     CertID,
+     *     singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(reqCert); + + if (singleRequestExtensions != null) + { + v.add(new DERTaggedObject(true, 0, singleRequestExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/ResponderID.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/ResponderID.java new file mode 100644 index 0000000..9719047 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/ResponderID.java @@ -0,0 +1,104 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x500.X500Name; + +public class ResponderID + extends ASN1Object + implements ASN1Choice +{ + private ASN1Encodable value; + + public ResponderID( + ASN1OctetString value) + { + this.value = value; + } + + public ResponderID( + X500Name value) + { + this.value = value; + } + + public static ResponderID getInstance( + Object obj) + { + if (obj instanceof ResponderID) + { + return (ResponderID)obj; + } + else if (obj instanceof DEROctetString) + { + return new ResponderID((DEROctetString)obj); + } + else if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)obj; + + if (o.getTagNo() == 1) + { + return new ResponderID(X500Name.getInstance(o, true)); + } + else + { + return new ResponderID(ASN1OctetString.getInstance(o, true)); + } + } + + return new ResponderID(X500Name.getInstance(obj)); + } + + public static ResponderID getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + + public byte[] getKeyHash() + { + if (this.value instanceof ASN1OctetString) + { + ASN1OctetString octetString = (ASN1OctetString)this.value; + return octetString.getOctets(); + } + + return null; + } + + public X500Name getName() + { + if (this.value instanceof ASN1OctetString) + { + return null; + } + + return X500Name.getInstance(value); + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * ResponderID ::= CHOICE {
+     *      byName          [1] Name,
+     *      byKey           [2] KeyHash }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + if (value instanceof ASN1OctetString) + { + return new DERTaggedObject(true, 2, value); + } + + return new DERTaggedObject(true, 1, value); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java new file mode 100644 index 0000000..01167b5 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java @@ -0,0 +1,85 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +public class ResponseBytes + extends ASN1Object +{ + ASN1ObjectIdentifier responseType; + ASN1OctetString response; + + public ResponseBytes( + ASN1ObjectIdentifier responseType, + ASN1OctetString response) + { + this.responseType = responseType; + this.response = response; + } + + /** + * @deprecated use getInstance() + */ + public ResponseBytes( + ASN1Sequence seq) + { + responseType = (ASN1ObjectIdentifier)seq.getObjectAt(0); + response = (ASN1OctetString)seq.getObjectAt(1); + } + + public static ResponseBytes getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ResponseBytes getInstance( + Object obj) + { + if (obj instanceof ResponseBytes) + { + return (ResponseBytes)obj; + } + else if (obj != null) + { + return new ResponseBytes(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1ObjectIdentifier getResponseType() + { + return responseType; + } + + public ASN1OctetString getResponse() + { + return response; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * ResponseBytes ::=       SEQUENCE {
+     *     responseType   OBJECT IDENTIFIER,
+     *     response       OCTET STRING }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(responseType); + v.add(response); + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java new file mode 100644 index 0000000..6874b22 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java @@ -0,0 +1,181 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.X509Extensions; + +public class ResponseData + extends ASN1Object +{ + private static final ASN1Integer V1 = new ASN1Integer(0); + + private boolean versionPresent; + + private ASN1Integer version; + private ResponderID responderID; + private ASN1GeneralizedTime producedAt; + private ASN1Sequence responses; + private Extensions responseExtensions; + + public ResponseData( + ASN1Integer version, + ResponderID responderID, + ASN1GeneralizedTime producedAt, + ASN1Sequence responses, + Extensions responseExtensions) + { + this.version = version; + this.responderID = responderID; + this.producedAt = producedAt; + this.responses = responses; + this.responseExtensions = responseExtensions; + } + + /** + * @deprecated use method taking Extensions + * @param responderID + * @param producedAt + * @param responses + * @param responseExtensions + */ + public ResponseData( + ResponderID responderID, + ASN1GeneralizedTime producedAt, + ASN1Sequence responses, + X509Extensions responseExtensions) + { + this(V1, responderID, ASN1GeneralizedTime.getInstance(producedAt), responses, Extensions.getInstance(responseExtensions)); + } + + public ResponseData( + ResponderID responderID, + ASN1GeneralizedTime producedAt, + ASN1Sequence responses, + Extensions responseExtensions) + { + this(V1, responderID, producedAt, responses, responseExtensions); + } + + private ResponseData( + ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(0) instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0); + + if (o.getTagNo() == 0) + { + this.versionPresent = true; + this.version = ASN1Integer.getInstance( + (ASN1TaggedObject)seq.getObjectAt(0), true); + index++; + } + else + { + this.version = V1; + } + } + else + { + this.version = V1; + } + + this.responderID = ResponderID.getInstance(seq.getObjectAt(index++)); + this.producedAt = ASN1GeneralizedTime.getInstance(seq.getObjectAt(index++)); + this.responses = (ASN1Sequence)seq.getObjectAt(index++); + + if (seq.size() > index) + { + this.responseExtensions = Extensions.getInstance( + (ASN1TaggedObject)seq.getObjectAt(index), true); + } + } + + public static ResponseData getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ResponseData getInstance( + Object obj) + { + if (obj instanceof ResponseData) + { + return (ResponseData)obj; + } + else if (obj != null) + { + return new ResponseData(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public ResponderID getResponderID() + { + return responderID; + } + + public ASN1GeneralizedTime getProducedAt() + { + return producedAt; + } + + public ASN1Sequence getResponses() + { + return responses; + } + + public Extensions getResponseExtensions() + { + return responseExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * ResponseData ::= SEQUENCE {
+     *     version              [0] EXPLICIT Version DEFAULT v1,
+     *     responderID              ResponderID,
+     *     producedAt               GeneralizedTime,
+     *     responses                SEQUENCE OF SingleResponse,
+     *     responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + if (versionPresent || !version.equals(V1)) + { + v.add(new DERTaggedObject(true, 0, version)); + } + + v.add(responderID); + v.add(producedAt); + v.add(responses); + if (responseExtensions != null) + { + v.add(new DERTaggedObject(true, 1, responseExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java new file mode 100644 index 0000000..6770050 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java @@ -0,0 +1,92 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.CRLReason; + +public class RevokedInfo + extends ASN1Object +{ + private ASN1GeneralizedTime revocationTime; + private CRLReason revocationReason; + + public RevokedInfo( + ASN1GeneralizedTime revocationTime, + CRLReason revocationReason) + { + this.revocationTime = revocationTime; + this.revocationReason = revocationReason; + } + + private RevokedInfo( + ASN1Sequence seq) + { + this.revocationTime = ASN1GeneralizedTime.getInstance(seq.getObjectAt(0)); + + if (seq.size() > 1) + { + this.revocationReason = CRLReason.getInstance(ASN1Enumerated.getInstance( + (ASN1TaggedObject)seq.getObjectAt(1), true)); + } + } + + public static RevokedInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static RevokedInfo getInstance( + Object obj) + { + if (obj instanceof RevokedInfo) + { + return (RevokedInfo)obj; + } + else if (obj != null) + { + return new RevokedInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1GeneralizedTime getRevocationTime() + { + return revocationTime; + } + + public CRLReason getRevocationReason() + { + return revocationReason; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * RevokedInfo ::= SEQUENCE {
+     *      revocationTime              GeneralizedTime,
+     *      revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(revocationTime); + if (revocationReason != null) + { + v.add(new DERTaggedObject(true, 0, revocationReason)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java new file mode 100644 index 0000000..80bd740 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java @@ -0,0 +1,111 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class Signature + extends ASN1Object +{ + AlgorithmIdentifier signatureAlgorithm; + DERBitString signature; + ASN1Sequence certs; + + public Signature( + AlgorithmIdentifier signatureAlgorithm, + DERBitString signature) + { + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + } + + public Signature( + AlgorithmIdentifier signatureAlgorithm, + DERBitString signature, + ASN1Sequence certs) + { + this.signatureAlgorithm = signatureAlgorithm; + this.signature = signature; + this.certs = certs; + } + + private Signature( + ASN1Sequence seq) + { + signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + signature = (DERBitString)seq.getObjectAt(1); + + if (seq.size() == 3) + { + certs = ASN1Sequence.getInstance( + (ASN1TaggedObject)seq.getObjectAt(2), true); + } + } + + public static Signature getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static Signature getInstance( + Object obj) + { + if (obj instanceof Signature) + { + return (Signature)obj; + } + else if (obj != null) + { + return new Signature(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public DERBitString getSignature() + { + return signature; + } + + public ASN1Sequence getCerts() + { + return certs; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * Signature       ::=     SEQUENCE {
+     *     signatureAlgorithm      AlgorithmIdentifier,
+     *     signature               BIT STRING,
+     *     certs               [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL}
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(signatureAlgorithm); + v.add(signature); + + if (certs != null) + { + v.add(new DERTaggedObject(true, 0, certs)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/SingleResponse.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/SingleResponse.java new file mode 100644 index 0000000..0dc2a91 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/SingleResponse.java @@ -0,0 +1,162 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.X509Extensions; + +public class SingleResponse + extends ASN1Object +{ + private CertID certID; + private CertStatus certStatus; + private ASN1GeneralizedTime thisUpdate; + private ASN1GeneralizedTime nextUpdate; + private Extensions singleExtensions; + + /** + * @deprecated use method taking ASN1GeneralizedTime and Extensions + * @param certID + * @param certStatus + * @param thisUpdate + * @param nextUpdate + * @param singleExtensions + */ + public SingleResponse( + CertID certID, + CertStatus certStatus, + ASN1GeneralizedTime thisUpdate, + ASN1GeneralizedTime nextUpdate, + X509Extensions singleExtensions) + { + this(certID, certStatus, thisUpdate, nextUpdate, Extensions.getInstance(singleExtensions)); + } + + public SingleResponse( + CertID certID, + CertStatus certStatus, + ASN1GeneralizedTime thisUpdate, + ASN1GeneralizedTime nextUpdate, + Extensions singleExtensions) + { + this.certID = certID; + this.certStatus = certStatus; + this.thisUpdate = thisUpdate; + this.nextUpdate = nextUpdate; + this.singleExtensions = singleExtensions; + } + + private SingleResponse( + ASN1Sequence seq) + { + this.certID = CertID.getInstance(seq.getObjectAt(0)); + this.certStatus = CertStatus.getInstance(seq.getObjectAt(1)); + this.thisUpdate = ASN1GeneralizedTime.getInstance(seq.getObjectAt(2)); + + if (seq.size() > 4) + { + this.nextUpdate = ASN1GeneralizedTime.getInstance( + (ASN1TaggedObject)seq.getObjectAt(3), true); + this.singleExtensions = Extensions.getInstance( + (ASN1TaggedObject)seq.getObjectAt(4), true); + } + else if (seq.size() > 3) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(3); + + if (o.getTagNo() == 0) + { + this.nextUpdate = ASN1GeneralizedTime.getInstance(o, true); + } + else + { + this.singleExtensions = Extensions.getInstance(o, true); + } + } + } + + public static SingleResponse getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static SingleResponse getInstance( + Object obj) + { + if (obj instanceof SingleResponse) + { + return (SingleResponse)obj; + } + else if (obj != null) + { + return new SingleResponse(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public CertID getCertID() + { + return certID; + } + + public CertStatus getCertStatus() + { + return certStatus; + } + + public ASN1GeneralizedTime getThisUpdate() + { + return thisUpdate; + } + + public ASN1GeneralizedTime getNextUpdate() + { + return nextUpdate; + } + + public Extensions getSingleExtensions() + { + return singleExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     *  SingleResponse ::= SEQUENCE {
+     *          certID                       CertID,
+     *          certStatus                   CertStatus,
+     *          thisUpdate                   GeneralizedTime,
+     *          nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
+     *          singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(certID); + v.add(certStatus); + v.add(thisUpdate); + + if (nextUpdate != null) + { + v.add(new DERTaggedObject(true, 0, nextUpdate)); + } + + if (singleExtensions != null) + { + v.add(new DERTaggedObject(true, 1, singleExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java new file mode 100644 index 0000000..2a05705 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java @@ -0,0 +1,172 @@ +package org.bouncycastle.asn1.ocsp; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.X509Extensions; + +public class TBSRequest + extends ASN1Object +{ + private static final ASN1Integer V1 = new ASN1Integer(0); + + ASN1Integer version; + GeneralName requestorName; + ASN1Sequence requestList; + Extensions requestExtensions; + + boolean versionSet; + + /** + * @deprecated use method taking Extensions + * @param requestorName + * @param requestList + * @param requestExtensions + */ + public TBSRequest( + GeneralName requestorName, + ASN1Sequence requestList, + X509Extensions requestExtensions) + { + this.version = V1; + this.requestorName = requestorName; + this.requestList = requestList; + this.requestExtensions = Extensions.getInstance(requestExtensions); + } + + public TBSRequest( + GeneralName requestorName, + ASN1Sequence requestList, + Extensions requestExtensions) + { + this.version = V1; + this.requestorName = requestorName; + this.requestList = requestList; + this.requestExtensions = requestExtensions; + } + + private TBSRequest( + ASN1Sequence seq) + { + int index = 0; + + if (seq.getObjectAt(0) instanceof ASN1TaggedObject) + { + ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0); + + if (o.getTagNo() == 0) + { + versionSet = true; + version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true); + index++; + } + else + { + version = V1; + } + } + else + { + version = V1; + } + + if (seq.getObjectAt(index) instanceof ASN1TaggedObject) + { + requestorName = GeneralName.getInstance((ASN1TaggedObject)seq.getObjectAt(index++), true); + } + + requestList = (ASN1Sequence)seq.getObjectAt(index++); + + if (seq.size() == (index + 1)) + { + requestExtensions = Extensions.getInstance((ASN1TaggedObject)seq.getObjectAt(index), true); + } + } + + public static TBSRequest getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static TBSRequest getInstance( + Object obj) + { + if (obj instanceof TBSRequest) + { + return (TBSRequest)obj; + } + else if (obj != null) + { + return new TBSRequest(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ASN1Integer getVersion() + { + return version; + } + + public GeneralName getRequestorName() + { + return requestorName; + } + + public ASN1Sequence getRequestList() + { + return requestList; + } + + public Extensions getRequestExtensions() + { + return requestExtensions; + } + + /** + * Produce an object suitable for an ASN1OutputStream. + *
+     * TBSRequest      ::=     SEQUENCE {
+     *     version             [0]     EXPLICIT Version DEFAULT v1,
+     *     requestorName       [1]     EXPLICIT GeneralName OPTIONAL,
+     *     requestList                 SEQUENCE OF Request,
+     *     requestExtensions   [2]     EXPLICIT Extensions OPTIONAL }
+     * 
+ */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + // + // if default don't include - unless explicitly provided. Not strictly correct + // but required for some requests + // + if (!version.equals(V1) || versionSet) + { + v.add(new DERTaggedObject(true, 0, version)); + } + + if (requestorName != null) + { + v.add(new DERTaggedObject(true, 1, requestorName)); + } + + v.add(requestList); + + if (requestExtensions != null) + { + v.add(new DERTaggedObject(true, 2, requestExtensions)); + } + + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java index b91c1a5..747277c 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java @@ -9,6 +9,9 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; +/** + * CRL Bag for PKCS#12 + */ public class CRLBag extends ASN1Object { @@ -44,31 +47,31 @@ public class CRLBag this.crlValue = crlValue; } - public ASN1ObjectIdentifier getcrlId() + public ASN1ObjectIdentifier getCrlId() { return crlId; } - public ASN1Encodable getCRLValue() + public ASN1Encodable getCrlValue() { return crlValue; } /** *
-     CRLBag ::= SEQUENCE {
-     crlId  BAG-TYPE.&id ({CRLTypes}),
-     crlValue  [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId})
-     }
-
-     x509CRL BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1}
-     -- DER-encoded X.509 CRL stored in OCTET STRING
-
-     CRLTypes BAG-TYPE ::= {
-     x509CRL,
-     ... -- For future extensions
-     }
-       
+ * CRLBag ::= SEQUENCE { + * crlId BAG-TYPE.&id ({CRLTypes}), + * crlValue [0] EXPLICIT BAG-TYPE.&Type ({CRLTypes}{@crlId}) + * } + * + * x509CRL BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {certTypes 1} + * -- DER-encoded X.509 CRL stored in OCTET STRING + * + * CRLTypes BAG-TYPE ::= { + * x509CRL, + * ... -- For future extensions + * } + * */ public ASN1Primitive toASN1Primitive() { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java index c9c14fe..fb418ae 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java @@ -25,8 +25,8 @@ import org.bouncycastle.asn1.x509.X509Name; * Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }} * * Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE { - * type ATTRIBUTE.&id({IOSet}), - * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) + * type ATTRIBUTE.&id({IOSet}), + * values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type}) * } * */ @@ -67,18 +67,18 @@ public class CertificationRequestInfo * @param attributes any attributes to be associated with the request. */ public CertificationRequestInfo( - X500Name subject, + X500Name subject, SubjectPublicKeyInfo pkInfo, ASN1Set attributes) { - this.subject = subject; - this.subjectPKInfo = pkInfo; - this.attributes = attributes; - - if ((subject == null) || (version == null) || (subjectPKInfo == null)) + if ((subject == null) || (pkInfo == null)) { throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator."); } + + this.subject = subject; + this.subjectPKInfo = pkInfo; + this.attributes = attributes; } /** @@ -89,14 +89,14 @@ public class CertificationRequestInfo SubjectPublicKeyInfo pkInfo, ASN1Set attributes) { - this.subject = X500Name.getInstance(subject.toASN1Primitive()); - this.subjectPKInfo = pkInfo; - this.attributes = attributes; - - if ((subject == null) || (version == null) || (subjectPKInfo == null)) + if ((subject == null) || (pkInfo == null)) { throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator."); } + + this.subject = X500Name.getInstance(subject.toASN1Primitive()); + this.subjectPKInfo = pkInfo; + this.attributes = attributes; } /** diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java index c885a6c..848f4fc 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java @@ -25,7 +25,7 @@ public class EncryptionScheme this.algId = AlgorithmIdentifier.getInstance(seq); } - public static final EncryptionScheme getInstance(Object obj) + public static EncryptionScheme getInstance(Object obj) { if (obj instanceof EncryptionScheme) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java index 3b40836..83804f3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java @@ -25,7 +25,7 @@ public class KeyDerivationFunc this.algId = AlgorithmIdentifier.getInstance(seq); } - public static final KeyDerivationFunc getInstance(Object obj) + public static KeyDerivationFunc getInstance(Object obj) { if (obj instanceof KeyDerivationFunc) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java deleted file mode 100644 index db44a82..0000000 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.bouncycastle.asn1.pkcs; - -import java.util.Enumeration; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; - -/** - * @deprecated - use AlgorithmIdentifier and PBES2Parameters - */ -public class PBES2Algorithms - extends AlgorithmIdentifier implements PKCSObjectIdentifiers -{ - private ASN1ObjectIdentifier objectId; - private KeyDerivationFunc func; - private EncryptionScheme scheme; - - public PBES2Algorithms( - ASN1Sequence obj) - { - super(obj); - - Enumeration e = obj.getObjects(); - - objectId = (ASN1ObjectIdentifier)e.nextElement(); - - ASN1Sequence seq = (ASN1Sequence)e.nextElement(); - - e = seq.getObjects(); - - ASN1Sequence funcSeq = (ASN1Sequence)e.nextElement(); - - if (funcSeq.getObjectAt(0).equals(id_PBKDF2)) - { - func = new KeyDerivationFunc(id_PBKDF2, PBKDF2Params.getInstance(funcSeq.getObjectAt(1))); - } - else - { - func = KeyDerivationFunc.getInstance(funcSeq); - } - - scheme = EncryptionScheme.getInstance(e.nextElement()); - } - - public ASN1ObjectIdentifier getObjectId() - { - return objectId; - } - - public KeyDerivationFunc getKeyDerivationFunc() - { - return func; - } - - public EncryptionScheme getEncryptionScheme() - { - return scheme; - } - - public ASN1Primitive getASN1Primitive() - { - ASN1EncodableVector v = new ASN1EncodableVector(); - ASN1EncodableVector subV = new ASN1EncodableVector(); - - v.add(objectId); - - subV.add(func); - subV.add(scheme); - v.add(new DERSequence(subV)); - - return new DERSequence(v); - } -} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java index 92c4e8f..6a6ad55 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java @@ -13,6 +13,7 @@ import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.util.Arrays; /** *
@@ -31,19 +32,19 @@ public class PBKDF2Params
 {
     private static final AlgorithmIdentifier algid_hmacWithSHA1 = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA1, DERNull.INSTANCE);
 
-    private ASN1OctetString octStr;
-    private ASN1Integer      iterationCount;
-    private ASN1Integer      keyLength;
-    private AlgorithmIdentifier prf;
+    private final ASN1OctetString octStr;
+    private final ASN1Integer iterationCount;
+    private final ASN1Integer keyLength;
+    private final AlgorithmIdentifier prf;
 
     /**
      * Create PBKDF2Params from the passed in object,
      *
-     * @param obj either PBKDF2Params or an ASN2Sequence.
+     * @param obj either PBKDF2Params or an ASN1Sequence.
      * @return a PBKDF2Params instance.
      */
     public static PBKDF2Params getInstance(
-        Object  obj)
+        Object obj)
     {
         if (obj instanceof PBKDF2Params)
         {
@@ -61,72 +62,77 @@ public class PBKDF2Params
     /**
      * Create a PBKDF2Params with the specified salt, iteration count, and algid-hmacWithSHA1 for the prf.
      *
-     * @param salt  input salt.
+     * @param salt           input salt.
      * @param iterationCount input iteration count.
      */
     public PBKDF2Params(
-        byte[]  salt,
-        int     iterationCount)
+        byte[] salt,
+        int iterationCount)
     {
-        this.octStr = new DEROctetString(salt);
-        this.iterationCount = new ASN1Integer(iterationCount);
+        this(salt, iterationCount, 0);
     }
 
     /**
      * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and algid-hmacWithSHA1 for the prf.
      *
-     * @param salt  input salt.
+     * @param salt           input salt.
      * @param iterationCount input iteration count.
-     * @param keyLength intended key length to be produced.
+     * @param keyLength      intended key length to be produced.
      */
     public PBKDF2Params(
-        byte[]  salt,
-        int     iterationCount,
-        int     keyLength)
+        byte[] salt,
+        int iterationCount,
+        int keyLength)
     {
-        this(salt, iterationCount);
-
-        this.keyLength = new ASN1Integer(keyLength);
+        this(salt, iterationCount, keyLength, null);
     }
 
     /**
      * Create a PBKDF2Params with the specified salt, iteration count, keyLength, and a defined prf.
      *
-     * @param salt  input salt.
+     * @param salt           input salt.
      * @param iterationCount input iteration count.
-     * @param keyLength intended key length to be produced.
-     * @param prf the pseudo-random function to use.
+     * @param keyLength      intended key length to be produced.
+     * @param prf            the pseudo-random function to use.
      */
     public PBKDF2Params(
-        byte[]  salt,
-        int     iterationCount,
-        int     keyLength,
+        byte[] salt,
+        int iterationCount,
+        int keyLength,
         AlgorithmIdentifier prf)
     {
-        this(salt, iterationCount);
+        this.octStr = new DEROctetString(Arrays.clone(salt));
+        this.iterationCount = new ASN1Integer(iterationCount);
+
+        if (keyLength > 0)
+        {
+            this.keyLength = new ASN1Integer(keyLength);
+        }
+        else
+        {
+            this.keyLength = null;
+        }
 
-        this.keyLength = new ASN1Integer(keyLength);
         this.prf = prf;
     }
 
     /**
      * Create a PBKDF2Params with the specified salt, iteration count, and a defined prf.
      *
-     * @param salt  input salt.
+     * @param salt           input salt.
      * @param iterationCount input iteration count.
-     * @param prf the pseudo-random function to use.
+     * @param prf            the pseudo-random function to use.
      */
     public PBKDF2Params(
-        byte[]  salt,
-        int     iterationCount,
+        byte[] salt,
+        int iterationCount,
         AlgorithmIdentifier prf)
     {
-        this(salt, iterationCount);
-        this.prf = prf;
+        this(salt, iterationCount, 0, prf);
     }
 
     private PBKDF2Params(
-        ASN1Sequence  seq)
+        ASN1Sequence seq)
     {
         Enumeration e = seq.getObjects();
 
@@ -158,6 +164,15 @@ public class PBKDF2Params
             {
                 prf = AlgorithmIdentifier.getInstance(o);
             }
+            else
+            {
+                prf = null;
+            }
+        }
+        else
+        {
+            keyLength = null;
+            prf = null;
         }
     }
 
@@ -228,7 +243,7 @@ public class PBKDF2Params
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector();
 
         v.add(octStr);
         v.add(iterationCount);
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
index 82f1f94..5dbddc3 100644
--- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
@@ -120,34 +120,34 @@ public interface PKCSObjectIdentifiers
     static final ASN1ObjectIdentifier    md5                    = digestAlgorithm.branch("5");
 
     /**  1.2.840.113549.2.7 */
-    static final ASN1ObjectIdentifier    id_hmacWithSHA1        = digestAlgorithm.branch("7");
+    static final ASN1ObjectIdentifier    id_hmacWithSHA1        = digestAlgorithm.branch("7").intern();
     /**  1.2.840.113549.2.8 */
-    static final ASN1ObjectIdentifier    id_hmacWithSHA224      = digestAlgorithm.branch("8");
+    static final ASN1ObjectIdentifier    id_hmacWithSHA224      = digestAlgorithm.branch("8").intern();
     /**  1.2.840.113549.2.9 */
-    static final ASN1ObjectIdentifier    id_hmacWithSHA256      = digestAlgorithm.branch("9");
+    static final ASN1ObjectIdentifier    id_hmacWithSHA256      = digestAlgorithm.branch("9").intern();
     /**  1.2.840.113549.2.10 */
-    static final ASN1ObjectIdentifier    id_hmacWithSHA384      = digestAlgorithm.branch("10");
+    static final ASN1ObjectIdentifier    id_hmacWithSHA384      = digestAlgorithm.branch("10").intern();
     /**  1.2.840.113549.2.11 */
-    static final ASN1ObjectIdentifier    id_hmacWithSHA512      = digestAlgorithm.branch("11");
+    static final ASN1ObjectIdentifier    id_hmacWithSHA512      = digestAlgorithm.branch("11").intern();
 
     //
     // pkcs-7 OBJECT IDENTIFIER ::= {
     //       iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
     //
     /** pkcs#7: 1.2.840.113549.1.7 */
-    static final ASN1ObjectIdentifier    pkcs_7                  = new ASN1ObjectIdentifier("1.2.840.113549.1.7");
+    static final ASN1ObjectIdentifier    pkcs_7                  = new ASN1ObjectIdentifier("1.2.840.113549.1.7").intern();
     /** PKCS#7: 1.2.840.113549.1.7.1 */
-    static final ASN1ObjectIdentifier    data                    = new ASN1ObjectIdentifier("1.2.840.113549.1.7.1");
+    static final ASN1ObjectIdentifier    data                    = new ASN1ObjectIdentifier("1.2.840.113549.1.7.1").intern();
     /** PKCS#7: 1.2.840.113549.1.7.2 */
-    static final ASN1ObjectIdentifier    signedData              = new ASN1ObjectIdentifier("1.2.840.113549.1.7.2");
+    static final ASN1ObjectIdentifier    signedData              = new ASN1ObjectIdentifier("1.2.840.113549.1.7.2").intern();
     /** PKCS#7: 1.2.840.113549.1.7.3 */
-    static final ASN1ObjectIdentifier    envelopedData           = new ASN1ObjectIdentifier("1.2.840.113549.1.7.3");
+    static final ASN1ObjectIdentifier    envelopedData           = new ASN1ObjectIdentifier("1.2.840.113549.1.7.3").intern();
     /** PKCS#7: 1.2.840.113549.1.7.4 */
-    static final ASN1ObjectIdentifier    signedAndEnvelopedData  = new ASN1ObjectIdentifier("1.2.840.113549.1.7.4");
+    static final ASN1ObjectIdentifier    signedAndEnvelopedData  = new ASN1ObjectIdentifier("1.2.840.113549.1.7.4").intern();
     /** PKCS#7: 1.2.840.113549.1.7.5 */
-    static final ASN1ObjectIdentifier    digestedData            = new ASN1ObjectIdentifier("1.2.840.113549.1.7.5");
+    static final ASN1ObjectIdentifier    digestedData            = new ASN1ObjectIdentifier("1.2.840.113549.1.7.5").intern();
     /** PKCS#7: 1.2.840.113549.1.7.76 */
-    static final ASN1ObjectIdentifier    encryptedData           = new ASN1ObjectIdentifier("1.2.840.113549.1.7.6");
+    static final ASN1ObjectIdentifier    encryptedData           = new ASN1ObjectIdentifier("1.2.840.113549.1.7.6").intern();
 
     //
     // pkcs-9 OBJECT IDENTIFIER ::= {
@@ -157,37 +157,37 @@ public interface PKCSObjectIdentifiers
     static final ASN1ObjectIdentifier    pkcs_9                  = new ASN1ObjectIdentifier("1.2.840.113549.1.9");
 
     /** PKCS#9: 1.2.840.113549.1.9.1 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_emailAddress        = pkcs_9.branch("1");
+    static final ASN1ObjectIdentifier    pkcs_9_at_emailAddress        = pkcs_9.branch("1").intern();
     /** PKCS#9: 1.2.840.113549.1.9.2 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredName    = pkcs_9.branch("2");
+    static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredName    = pkcs_9.branch("2").intern();
     /** PKCS#9: 1.2.840.113549.1.9.3 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_contentType         = pkcs_9.branch("3");
+    static final ASN1ObjectIdentifier    pkcs_9_at_contentType         = pkcs_9.branch("3").intern();
     /** PKCS#9: 1.2.840.113549.1.9.4 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_messageDigest       = pkcs_9.branch("4");
+    static final ASN1ObjectIdentifier    pkcs_9_at_messageDigest       = pkcs_9.branch("4").intern();
     /** PKCS#9: 1.2.840.113549.1.9.5 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_signingTime         = pkcs_9.branch("5");
+    static final ASN1ObjectIdentifier    pkcs_9_at_signingTime         = pkcs_9.branch("5").intern();
     /** PKCS#9: 1.2.840.113549.1.9.6 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_counterSignature    = pkcs_9.branch("6");
+    static final ASN1ObjectIdentifier    pkcs_9_at_counterSignature    = pkcs_9.branch("6").intern();
     /** PKCS#9: 1.2.840.113549.1.9.7 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_challengePassword   = pkcs_9.branch("7");
+    static final ASN1ObjectIdentifier    pkcs_9_at_challengePassword   = pkcs_9.branch("7").intern();
     /** PKCS#9: 1.2.840.113549.1.9.8 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredAddress = pkcs_9.branch("8");
+    static final ASN1ObjectIdentifier    pkcs_9_at_unstructuredAddress = pkcs_9.branch("8").intern();
     /** PKCS#9: 1.2.840.113549.1.9.9 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9");
+    static final ASN1ObjectIdentifier    pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9").intern();
 
     /** PKCS#9: 1.2.840.113549.1.9.13 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_signingDescription = pkcs_9.branch("13");
+    static final ASN1ObjectIdentifier    pkcs_9_at_signingDescription = pkcs_9.branch("13").intern();
     /** PKCS#9: 1.2.840.113549.1.9.14 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_extensionRequest   = pkcs_9.branch("14");
+    static final ASN1ObjectIdentifier    pkcs_9_at_extensionRequest   = pkcs_9.branch("14").intern();
     /** PKCS#9: 1.2.840.113549.1.9.15 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_smimeCapabilities  = pkcs_9.branch("15");
+    static final ASN1ObjectIdentifier    pkcs_9_at_smimeCapabilities  = pkcs_9.branch("15").intern();
     /** PKCS#9: 1.2.840.113549.1.9.16 */
-    static final ASN1ObjectIdentifier    id_smime                     = pkcs_9.branch("16");
+    static final ASN1ObjectIdentifier    id_smime                     = pkcs_9.branch("16").intern();
 
     /** PKCS#9: 1.2.840.113549.1.9.20 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_friendlyName  = pkcs_9.branch("20");
+    static final ASN1ObjectIdentifier    pkcs_9_at_friendlyName  = pkcs_9.branch("20").intern();
     /** PKCS#9: 1.2.840.113549.1.9.21 */
-    static final ASN1ObjectIdentifier    pkcs_9_at_localKeyId    = pkcs_9.branch("21");
+    static final ASN1ObjectIdentifier    pkcs_9_at_localKeyId    = pkcs_9.branch("21").intern();
 
     /** PKCS#9: 1.2.840.113549.1.9.22.1
      * @deprecated use x509Certificate instead */
@@ -196,14 +196,19 @@ public interface PKCSObjectIdentifiers
     /** PKCS#9: 1.2.840.113549.1.9.22 */
     static final ASN1ObjectIdentifier    certTypes               = pkcs_9.branch("22");
     /** PKCS#9: 1.2.840.113549.1.9.22.1 */
-    static final ASN1ObjectIdentifier    x509Certificate         = certTypes.branch("1");
+    static final ASN1ObjectIdentifier    x509Certificate         = certTypes.branch("1").intern();
     /** PKCS#9: 1.2.840.113549.1.9.22.2 */
-    static final ASN1ObjectIdentifier    sdsiCertificate         = certTypes.branch("2");
+    static final ASN1ObjectIdentifier    sdsiCertificate         = certTypes.branch("2").intern();
 
     /** PKCS#9: 1.2.840.113549.1.9.23 */
     static final ASN1ObjectIdentifier    crlTypes                = pkcs_9.branch("23");
     /** PKCS#9: 1.2.840.113549.1.9.23.1 */
-    static final ASN1ObjectIdentifier    x509Crl                 = crlTypes.branch("1");
+    static final ASN1ObjectIdentifier    x509Crl                 = crlTypes.branch("1").intern();
+
+    /** RFC 6211 -  id-aa-cmsAlgorithmProtect OBJECT IDENTIFIER ::= {
+            iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+            pkcs9(9) 52 }  */
+    ASN1ObjectIdentifier   id_aa_cmsAlgorithmProtect = pkcs_9.branch("52").intern();
 
     //
     // SMIME capability sub oids.
@@ -238,6 +243,17 @@ public interface PKCSObjectIdentifiers
     static final ASN1ObjectIdentifier id_alg                  = id_smime.branch("3");
     /** PKCS#9: 1.2.840.113549.1.9.16.3.9 */
     static final ASN1ObjectIdentifier id_alg_PWRI_KEK         = id_alg.branch("9");
+    /**
+     * 
+     * -- RSA-KEM Key Transport Algorithm
+     *
+     * id-rsa-kem OID ::= {
+     *      iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+     *      pkcs-9(9) smime(16) alg(3) 14
+     *   }
+     * 
+ */ + static final ASN1ObjectIdentifier id_rsa_KEM = id_alg.branch("14"); // // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) @@ -392,5 +408,9 @@ public interface PKCSObjectIdentifiers static final ASN1ObjectIdentifier id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"); /** PKCS#9: 1.2.840.113549.1.9.16.3.7 */ static final ASN1ObjectIdentifier id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"); + /** PKCS#9: 1.2.840.113549.1.9.16.3.5 */ + static final ASN1ObjectIdentifier id_alg_ESDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.5"); + /** PKCS#9: 1.2.840.113549.1.9.16.3.10 */ + static final ASN1ObjectIdentifier id_alg_SSDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.10"); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java index dad8650..7f02e70 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java @@ -68,7 +68,7 @@ public class PrivateKeyInfo } /** - * @deprectaed use PrivateKeyInfo.getInstance() + * @deprecated use PrivateKeyInfo.getInstance() * @param seq */ public PrivateKeyInfo( diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java index df2238a..269466d 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java @@ -47,10 +47,26 @@ public class ECPrivateKey return null; } + /** + * @deprecated use constructor which takes orderBitLength to guarantee correct encoding. + */ public ECPrivateKey( BigInteger key) { - byte[] bytes = BigIntegers.asUnsignedByteArray(key); + this(key.bitLength(), key); + } + + /** + * Base constructor. + * + * @param orderBitLength the bitLength of the order of the curve. + * @param key the private key value. + */ + public ECPrivateKey( + int orderBitLength, + BigInteger key) + { + byte[] bytes = BigIntegers.asUnsignedByteArray((orderBitLength + 7) / 8, key); ASN1EncodableVector v = new ASN1EncodableVector(); @@ -60,6 +76,9 @@ public class ECPrivateKey seq = new DERSequence(v); } + /** + * @deprecated use constructor which takes orderBitLength to guarantee correct encoding. + */ public ECPrivateKey( BigInteger key, ASN1Encodable parameters) @@ -67,12 +86,32 @@ public class ECPrivateKey this(key, null, parameters); } + /** + * @deprecated use constructor which takes orderBitLength to guarantee correct encoding. + */ + public ECPrivateKey( + BigInteger key, + DERBitString publicKey, + ASN1Encodable parameters) + { + this(key.bitLength(), key, publicKey, parameters); + } + + public ECPrivateKey( + int orderBitLength, + BigInteger key, + ASN1Encodable parameters) + { + this(orderBitLength, key, null, parameters); + } + public ECPrivateKey( + int orderBitLength, BigInteger key, DERBitString publicKey, ASN1Encodable parameters) { - byte[] bytes = BigIntegers.asUnsignedByteArray(key); + byte[] bytes = BigIntegers.asUnsignedByteArray((orderBitLength + 7) / 8, key); ASN1EncodableVector v = new ASN1EncodableVector(); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java index 50a7a63..1cdaf12 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java @@ -7,9 +7,11 @@ import java.util.Hashtable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ECParametersHolder; +import org.bouncycastle.asn1.x9.X9ECPoint; import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; -import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism; +import org.bouncycastle.math.ec.endo.GLVTypeBParameters; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; @@ -17,19 +19,14 @@ public class SECNamedCurves { private static ECCurve configureCurve(ECCurve curve) { -// int coord = ECCurve.COORD_JACOBIAN_MODIFIED; -// -// if (curve.getCoordinateSystem() != coord && curve.supportsCoordinateSystem(coord)) -// { -// return curve.configure() -// .setCoordinateSystem(coord) -//// .setMultiplier(new WNafL2RMultiplier()) -// .create(); -// } - return curve; } + private static ECCurve configureCurveGLV(ECCurve c, GLVTypeBParameters p) + { + return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create(); + } + private static BigInteger fromHex( String hex) { @@ -51,10 +48,10 @@ public class SECNamedCurves BigInteger n = fromHex("DB7C2ABF62E35E7628DFAC6561C5"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "09487239995A5EE76B55F9C2F098")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "09487239995A5EE76B55F9C2F098" + "A89CE5AF8724C0A23E0E0FF77500")); @@ -77,10 +74,10 @@ public class SECNamedCurves BigInteger n = fromHex("36DF0AAFD8B8D7597CA10520D04B"); BigInteger h = BigInteger.valueOf(4); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "4BA30AB5E892B4E1649DD0928643")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "4BA30AB5E892B4E1649DD0928643" + "ADCD46F5882E3747DEF36E956E97")); @@ -103,10 +100,10 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFE0000000075A30D1B9038A115"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "161FF7528B899B2D0C28607CA52C5B86")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "161FF7528B899B2D0C28607CA52C5B86" + "CF5AC8395BAFEB13C02DA292DDED7A83")); @@ -129,10 +126,10 @@ public class SECNamedCurves BigInteger n = fromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3"); BigInteger h = BigInteger.valueOf(4); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "7B6AA5D85E572983E6FB32A7CDEBC140")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "7B6AA5D85E572983E6FB32A7CDEBC140" + "27B6916A894D3AEE7106FE805FC34B44")); @@ -155,10 +152,23 @@ public class SECNamedCurves BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16), + new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16), + new BigInteger[]{ + new BigInteger("9162fbe73984472a0a9e", 16), + new BigInteger("-96341f1138933bc2f505", 16) }, + new BigInteger[]{ + new BigInteger("127971af8721782ecffa3", 16), + new BigInteger("9162fbe73984472a0a9e", 16) }, + new BigInteger("9162fbe73984472a0a9d0590", 16), + new BigInteger("96341f1138933bc2f503fd44", 16), + 176); + + ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); // ECPoint G = curve.decodePoint(Hex.decode("02" // + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB" + "938CF935318FDCED6BC28286531733C3F03C4FEE")); @@ -181,10 +191,10 @@ public class SECNamedCurves BigInteger n = fromHex("0100000000000000000001F4C8F927AED3CA752257"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "4A96B5688EF573284664698968C38BB913CBFC82")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "4A96B5688EF573284664698968C38BB913CBFC82" + "23A628553168947D59DCC912042351377AC5FB32")); @@ -207,10 +217,10 @@ public class SECNamedCurves BigInteger n = fromHex("0100000000000000000000351EE786A818F3A1A16B"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "52DCB034293A117E1F4FF11B30F7199D3144CE6D" + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E")); @@ -233,10 +243,23 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16), + new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16), + new BigInteger[]{ + new BigInteger("71169be7330b3038edb025f1", 16), + new BigInteger("-b3fb3400dec5c4adceb8655c", 16) }, + new BigInteger[]{ + new BigInteger("12511cfe811d0f4e6bc688b4d", 16), + new BigInteger("71169be7330b3038edb025f1", 16) }, + new BigInteger("71169be7330b3038edb025f1d0f9", 16), + new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16), + 208); + + ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); @@ -259,10 +282,10 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012" + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")); @@ -285,10 +308,23 @@ public class SECNamedCurves BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16), + new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16), + new BigInteger[]{ + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16), + new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) }, + new BigInteger[]{ + new BigInteger("1243ae1b4d71613bc9f780a03690e", 16), + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) }, + new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16), + new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16), + 240); + + ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); @@ -311,10 +347,10 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); @@ -337,10 +373,23 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16), + new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16), + new BigInteger[]{ + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16), + new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) }, + new BigInteger[]{ + new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16), + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) }, + new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16), + new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16), + 272); + + ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); @@ -363,10 +412,10 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); @@ -389,10 +438,10 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); @@ -415,11 +464,11 @@ public class SECNamedCurves BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b)); + ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); @@ -446,7 +495,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "009D73616F35F4AB1407D73562C10F")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "009D73616F35F4AB1407D73562C10F" + "00A52830277958EE84D1315ED31886")); @@ -473,7 +522,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "01A57A6A7B26CA5EF52FCDB8164797")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "01A57A6A7B26CA5EF52FCDB8164797" + "00B3ADC94ED1FE674C06E695BABA1D")); @@ -502,7 +551,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0081BAF91FDF9833C40F9C181343638399")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "0081BAF91FDF9833C40F9C181343638399" + "078C6E7EA38C001F73C8134B1B4EF9E150")); @@ -531,7 +580,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0356DCD8F2F95031AD652D23951BB366A8")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "0356DCD8F2F95031AD652D23951BB366A8" + "0648F06D867940A5366D9E265DE9EB240F")); @@ -560,7 +609,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8" + "0289070FB05D38FF58321F2E800536D538CCDAA3D9")); @@ -589,7 +638,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0369979697AB43897789566789567F787A7876A654")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "0369979697AB43897789566789567F787A7876A654" + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883")); @@ -618,7 +667,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "03F0EBA16286A2D57EA0991168D4994637E8343E36" + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1")); @@ -645,7 +694,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1" + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05")); @@ -672,7 +721,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F" + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C")); @@ -699,7 +748,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126" + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3")); @@ -726,7 +775,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B" + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052")); @@ -753,7 +802,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC" + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA")); @@ -782,7 +831,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836" + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259")); @@ -811,7 +860,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053" + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4")); @@ -838,7 +887,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746" + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B")); @@ -865,7 +914,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7" + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706")); @@ -894,7 +943,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972" + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3")); @@ -923,7 +972,7 @@ public class SECNamedCurves ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19")); - ECPoint G = curve.decodePoint(Hex.decode("04" + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19" + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B")); @@ -938,7 +987,7 @@ public class SECNamedCurves static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) { - objIds.put(name, oid); + objIds.put(name.toLowerCase(), oid); names.put(oid, name); curves.put(oid, holder); } @@ -984,14 +1033,8 @@ public class SECNamedCurves public static X9ECParameters getByName( String name) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); - - if (oid != null) - { - return getByOID(oid); - } - - return null; + ASN1ObjectIdentifier oid = getOID(name); + return oid == null ? null : getByOID(oid); } /** @@ -1004,13 +1047,7 @@ public class SECNamedCurves ASN1ObjectIdentifier oid) { X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid); - - if (holder != null) - { - return holder.getParameters(); - } - - return null; + return holder == null ? null : holder.getParameters(); } /** @@ -1040,6 +1077,6 @@ public class SECNamedCurves */ public static Enumeration getNames() { - return objIds.keys(); + return names.elements(); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java index fb60aca..1ddc17d 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java @@ -84,4 +84,25 @@ public interface SECObjectIdentifiers /** secp256r1 OID: 1.3.132.0.prime256v1 */ static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1; + static final ASN1ObjectIdentifier secg_scheme = new ASN1ObjectIdentifier("1.3.132.1"); + + static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha224kdf_scheme = secg_scheme.branch("11.0"); + static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha256kdf_scheme = secg_scheme.branch("11.1"); + static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha384kdf_scheme = secg_scheme.branch("11.2"); + static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha512kdf_scheme = secg_scheme.branch("11.3"); + + static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha224kdf_scheme = secg_scheme.branch("14.0"); + static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha256kdf_scheme = secg_scheme.branch("14.1"); + static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha384kdf_scheme = secg_scheme.branch("14.2"); + static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha512kdf_scheme = secg_scheme.branch("14.3"); + + static final ASN1ObjectIdentifier mqvSinglePass_sha224kdf_scheme = secg_scheme.branch("15.0"); + static final ASN1ObjectIdentifier mqvSinglePass_sha256kdf_scheme = secg_scheme.branch("15.1"); + static final ASN1ObjectIdentifier mqvSinglePass_sha384kdf_scheme = secg_scheme.branch("15.2"); + static final ASN1ObjectIdentifier mqvSinglePass_sha512kdf_scheme = secg_scheme.branch("15.3"); + + static final ASN1ObjectIdentifier mqvFull_sha224kdf_scheme = secg_scheme.branch("16.0"); + static final ASN1ObjectIdentifier mqvFull_sha256kdf_scheme = secg_scheme.branch("16.1"); + static final ASN1ObjectIdentifier mqvFull_sha384kdf_scheme = secg_scheme.branch("16.2"); + static final ASN1ObjectIdentifier mqvFull_sha512kdf_scheme = secg_scheme.branch("16.3"); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java index 895f5e8..2be7efe 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java @@ -41,35 +41,35 @@ public interface TeleTrusTObjectIdentifiers static final ASN1ObjectIdentifier ecc_brainpool = teleTrusTAlgorithm.branch("3.2.8"); /** 1.3.36.3.3.2.8.1 */ static final ASN1ObjectIdentifier ellipticCurve = ecc_brainpool.branch("1"); - /** 1.3.36.3.3.2.8.1 */ + /** 1.3.36.3.3.2.8.1.1 */ static final ASN1ObjectIdentifier versionOne = ellipticCurve.branch("1"); - /** 1.3.36.3.3.2.8.1.1 */ + /** 1.3.36.3.3.2.8.1.1.1 */ static final ASN1ObjectIdentifier brainpoolP160r1 = versionOne.branch("1"); - /** 1.3.36.3.3.2.8.1.2 */ + /** 1.3.36.3.3.2.8.1.1.2 */ static final ASN1ObjectIdentifier brainpoolP160t1 = versionOne.branch("2"); - /** 1.3.36.3.3.2.8.1.3 */ + /** 1.3.36.3.3.2.8.1.1.3 */ static final ASN1ObjectIdentifier brainpoolP192r1 = versionOne.branch("3"); - /** 1.3.36.3.3.2.8.1.4 */ + /** 1.3.36.3.3.2.8.1.1.4 */ static final ASN1ObjectIdentifier brainpoolP192t1 = versionOne.branch("4"); - /** 1.3.36.3.3.2.8.1.5 */ + /** 1.3.36.3.3.2.8.1.1.5 */ static final ASN1ObjectIdentifier brainpoolP224r1 = versionOne.branch("5"); - /** 1.3.36.3.3.2.8.1.6 */ + /** 1.3.36.3.3.2.8.1.1.6 */ static final ASN1ObjectIdentifier brainpoolP224t1 = versionOne.branch("6"); - /** 1.3.36.3.3.2.8.1.7 */ + /** 1.3.36.3.3.2.8.1.1.7 */ static final ASN1ObjectIdentifier brainpoolP256r1 = versionOne.branch("7"); - /** 1.3.36.3.3.2.8.1.8 */ + /** 1.3.36.3.3.2.8.1.1.8 */ static final ASN1ObjectIdentifier brainpoolP256t1 = versionOne.branch("8"); - /** 1.3.36.3.3.2.8.1.9 */ + /** 1.3.36.3.3.2.8.1.1.9 */ static final ASN1ObjectIdentifier brainpoolP320r1 = versionOne.branch("9"); - /** 1.3.36.3.3.2.8.1.10 */ + /** 1.3.36.3.3.2.8.1.1.10 */ static final ASN1ObjectIdentifier brainpoolP320t1 = versionOne.branch("10"); - /** 1.3.36.3.3.2.8.1.11 */ + /** 1.3.36.3.3.2.8.1.1.11 */ static final ASN1ObjectIdentifier brainpoolP384r1 = versionOne.branch("11"); - /** 1.3.36.3.3.2.8.1.12 */ + /** 1.3.36.3.3.2.8.1.1.12 */ static final ASN1ObjectIdentifier brainpoolP384t1 = versionOne.branch("12"); - /** 1.3.36.3.3.2.8.1.13 */ + /** 1.3.36.3.3.2.8.1.1.13 */ static final ASN1ObjectIdentifier brainpoolP512r1 = versionOne.branch("13"); - /** 1.3.36.3.3.2.8.1.14 */ + /** 1.3.36.3.3.2.8.1.1.14 */ static final ASN1ObjectIdentifier brainpoolP512t1 = versionOne.branch("14"); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java index 5302552..1330d25 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java @@ -3,7 +3,11 @@ package org.bouncycastle.asn1.util; import java.io.IOException; import java.util.Enumeration; +import org.bouncycastle.asn1.ASN1ApplicationSpecific; +import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1GeneralizedTime; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; @@ -11,8 +15,8 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.ASN1UTCTime; import org.bouncycastle.asn1.BERApplicationSpecific; -import org.bouncycastle.asn1.BERConstructedOctetString; import org.bouncycastle.asn1.BEROctetString; import org.bouncycastle.asn1.BERSequence; import org.bouncycastle.asn1.BERSet; @@ -21,18 +25,17 @@ import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERApplicationSpecific; import org.bouncycastle.asn1.DERBMPString; import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERBoolean; -import org.bouncycastle.asn1.DEREnumerated; import org.bouncycastle.asn1.DERExternal; -import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.DERGraphicString; import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DERPrintableString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERT61String; -import org.bouncycastle.asn1.DERUTCTime; import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.DERVideotexString; import org.bouncycastle.asn1.DERVisibleString; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; public class ASN1Dump @@ -51,7 +54,7 @@ public class ASN1Dump ASN1Primitive obj, StringBuffer buf) { - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); if (obj instanceof ASN1Sequence) { Enumeration e = ((ASN1Sequence)obj).getObjects(); @@ -172,7 +175,7 @@ public class ASN1Dump { ASN1OctetString oct = (ASN1OctetString)obj; - if (obj instanceof BEROctetString || obj instanceof BERConstructedOctetString) + if (obj instanceof BEROctetString) { buf.append(indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] "); } @@ -193,9 +196,9 @@ public class ASN1Dump { buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl); } - else if (obj instanceof DERBoolean) + else if (obj instanceof ASN1Boolean) { - buf.append(indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl); + buf.append(indent + "Boolean(" + ((ASN1Boolean)obj).isTrue() + ")" + nl); } else if (obj instanceof ASN1Integer) { @@ -238,13 +241,21 @@ public class ASN1Dump { buf.append(indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl); } - else if (obj instanceof DERUTCTime) + else if (obj instanceof DERGraphicString) { - buf.append(indent + "UTCTime(" + ((DERUTCTime)obj).getTime() + ") " + nl); + buf.append(indent + "GraphicString(" + ((DERGraphicString)obj).getString() + ") " + nl); } - else if (obj instanceof DERGeneralizedTime) + else if (obj instanceof DERVideotexString) { - buf.append(indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + nl); + buf.append(indent + "VideotexString(" + ((DERVideotexString)obj).getString() + ") " + nl); + } + else if (obj instanceof ASN1UTCTime) + { + buf.append(indent + "UTCTime(" + ((ASN1UTCTime)obj).getTime() + ") " + nl); + } + else if (obj instanceof ASN1GeneralizedTime) + { + buf.append(indent + "GeneralizedTime(" + ((ASN1GeneralizedTime)obj).getTime() + ") " + nl); } else if (obj instanceof BERApplicationSpecific) { @@ -254,9 +265,9 @@ public class ASN1Dump { buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl)); } - else if (obj instanceof DEREnumerated) + else if (obj instanceof ASN1Enumerated) { - DEREnumerated en = (DEREnumerated) obj; + ASN1Enumerated en = (ASN1Enumerated) obj; buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl); } else if (obj instanceof DERExternal) @@ -287,7 +298,7 @@ public class ASN1Dump private static String outputApplicationSpecific(String type, String indent, boolean verbose, ASN1Primitive obj, String nl) { - DERApplicationSpecific app = (DERApplicationSpecific)obj; + ASN1ApplicationSpecific app = ASN1ApplicationSpecific.getInstance(obj); StringBuffer buf = new StringBuffer(); if (app.isConstructed()) @@ -354,7 +365,7 @@ public class ASN1Dump private static String dumpBinaryDataAsString(String indent, byte[] bytes) { - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); StringBuffer buf = new StringBuffer(); indent += TAB; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java index 7f283f9..b4b2bd4 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java @@ -8,6 +8,9 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERSequence; +/** + * Holding class for the AttributeTypeAndValue structures that make up an RDN. + */ public class AttributeTypeAndValue extends ASN1Object { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java index cf7563e..39312de 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java @@ -12,6 +12,9 @@ import org.bouncycastle.asn1.DERT61String; import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.DERUniversalString; +/** + * The DirectoryString CHOICE object. + */ public class DirectoryString extends ASN1Object implements ASN1Choice, ASN1String diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java index f51c261..6a1b318 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java @@ -9,6 +9,9 @@ import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERSet; +/** + * Holding class for a single Relative Distinguished Name (RDN). + */ public class RDN extends ASN1Object { @@ -105,12 +108,12 @@ public class RDN *
      * RelativeDistinguishedName ::=
      *                     SET OF AttributeTypeAndValue
-
+     *
      * AttributeTypeAndValue ::= SEQUENCE {
      *        type     AttributeType,
      *        value    AttributeValue }
      * 
- * @return this object as an ASN1Primitive type + * @return this object as its ASN1Primitive type */ public ASN1Primitive toASN1Primitive() { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java index 50e57c5..67c5cd1 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java @@ -13,6 +13,7 @@ import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x500.style.BCStyle; /** + * The X.500 Name object. *
  *     Name ::= CHOICE {
  *                       RDNSequence }
@@ -38,6 +39,9 @@ public class X500Name
     private X500NameStyle style;
     private RDN[] rdns;
 
+    /**
+     * @deprecated use the getInstance() method that takes a style.
+     */
     public X500Name(X500NameStyle style, X500Name name)
     {
         this.rdns = name.rdns;
@@ -80,7 +84,7 @@ public class X500Name
     {
         if (obj instanceof X500Name)
         {
-            return getInstance(style, ((X500Name)obj).toASN1Primitive());
+            return new X500Name(style, (X500Name)obj);
         }
         else if (obj != null)
         {
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
index 7c9506a..d019aaa 100644
--- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
@@ -6,21 +6,39 @@ import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import org.bouncycastle.asn1.x500.style.BCStyle;
 
+/**
+ * A builder class for making X.500 Name objects.
+ */
 public class X500NameBuilder
 {
     private X500NameStyle template;
     private Vector rdns = new Vector();
 
+    /**
+     * Constructor using the default style (BCStyle).
+     */
     public X500NameBuilder()
     {
         this(BCStyle.INSTANCE);
     }
 
+    /**
+     * Constructor using a specified style.
+     *
+     * @param template the style template for string to DN conversion.
+     */
     public X500NameBuilder(X500NameStyle template)
     {
         this.template = template;
     }
 
+    /**
+     * Add an RDN based on a single OID and a string representation of its value.
+     *
+     * @param oid the OID for this RDN.
+     * @param value the string representation of the value the OID refers to.
+     * @return the current builder instance.
+     */
     public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, String value)
     {
         this.addRDN(oid, template.stringToValue(oid, value));
@@ -28,6 +46,13 @@ public class X500NameBuilder
         return this;
     }
 
+    /**
+     * Add an RDN based on a single OID and an ASN.1 value.
+     *
+     * @param oid the OID for this RDN.
+     * @param value the ASN.1 value the OID refers to.
+     * @return the current builder instance.
+     */
     public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, ASN1Encodable value)
     {
         rdns.addElement(new RDN(oid, value));
@@ -35,6 +60,12 @@ public class X500NameBuilder
         return this;
     }
 
+    /**
+     * Add an RDN based on the passed in AttributeTypeAndValue.
+     *
+     * @param attrTAndV the AttributeTypeAndValue to build the RDN from.
+     * @return the current builder instance.
+     */
     public X500NameBuilder addRDN(AttributeTypeAndValue attrTAndV)
     {
         rdns.addElement(new RDN(attrTAndV));
@@ -42,6 +73,13 @@ public class X500NameBuilder
         return this;
     }
 
+    /**
+     * Add a multi-valued RDN made up of the passed in OIDs and associated string values.
+     *
+     * @param oids the OIDs making up the RDN.
+     * @param values the string representation of the values the OIDs refer to.
+     * @return the current builder instance.
+     */
     public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, String[] values)
     {
         ASN1Encodable[] vals = new ASN1Encodable[values.length];
@@ -54,6 +92,13 @@ public class X500NameBuilder
         return addMultiValuedRDN(oids, vals);
     }
 
+    /**
+     * Add a multi-valued RDN made up of the passed in OIDs and associated ASN.1 values.
+     *
+     * @param oids the OIDs making up the RDN.
+     * @param values the ASN.1 values the OIDs refer to.
+     * @return the current builder instance.
+     */
     public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, ASN1Encodable[] values)
     {
         AttributeTypeAndValue[] avs = new AttributeTypeAndValue[oids.length];
@@ -66,6 +111,12 @@ public class X500NameBuilder
         return addMultiValuedRDN(avs);
     }
 
+    /**
+     * Add an RDN based on the passed in AttributeTypeAndValues.
+     *
+     * @param attrTAndVs the AttributeTypeAndValues to build the RDN from.
+     * @return the current builder instance.
+     */
     public X500NameBuilder addMultiValuedRDN(AttributeTypeAndValue[] attrTAndVs)
     {
         rdns.addElement(new RDN(attrTAndVs));
@@ -73,6 +124,11 @@ public class X500NameBuilder
         return this;
     }
 
+    /**
+     * Build an X.500 name for the current builder state.
+     *
+     * @return a new X.500 name.
+     */
     public X500Name build()
     {
         RDN[] vals = new RDN[rdns.size()];
@@ -84,4 +140,4 @@ public class X500NameBuilder
 
         return new X500Name(template, vals);
     }
-}
+}
\ No newline at end of file
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java
index 704ea72..8a87fb4 100644
--- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java
@@ -4,11 +4,11 @@ import org.bouncycastle.asn1.ASN1Encodable;
 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 /**
- * It turns out that the number of standard ways the fields in a DN should be 
- * encoded into their ASN.1 counterparts is rapidly approaching the
- * number of machines on the internet. By default the X500Name class
- * will produce UTF8Strings in line with the current recommendations (RFC 3280).
- * 

+ * This interface provides a profile to conform to when + * DNs are being converted into strings and back. The idea being that we'll be able to deal with + * the number of standard ways the fields in a DN should be + * encoded into their ASN.1 counterparts - a number that is rapidly approaching the + * number of machines on the internet. */ public interface X500NameStyle { @@ -76,4 +76,4 @@ public interface X500NameStyle * @return an array of String aliases for the OID, zero length if there are none. */ String[] oidToAttrNames(ASN1ObjectIdentifier oid); -} +} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java new file mode 100644 index 0000000..a97b17d --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java @@ -0,0 +1,193 @@ +package org.bouncycastle.asn1.x500.style; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1ParsingException; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.x500.AttributeTypeAndValue; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameStyle; + +/** + * This class provides some default behavior and common implementation for a + * X500NameStyle. It should be easily extendable to support implementing the + * desired X500NameStyle. + */ +public abstract class AbstractX500NameStyle + implements X500NameStyle +{ + + /** + * Tool function to shallow copy a Hashtable. + * + * @param paramsMap table to copy + * @return the copy of the table + */ + public static Hashtable copyHashTable(Hashtable paramsMap) + { + Hashtable newTable = new Hashtable(); + + Enumeration keys = paramsMap.keys(); + while (keys.hasMoreElements()) + { + Object key = keys.nextElement(); + newTable.put(key, paramsMap.get(key)); + } + + return newTable; + } + + private int calcHashCode(ASN1Encodable enc) + { + String value = IETFUtils.valueToString(enc); + value = IETFUtils.canonicalize(value); + return value.hashCode(); + } + + public int calculateHashCode(X500Name name) + { + int hashCodeValue = 0; + RDN[] rdns = name.getRDNs(); + + // this needs to be order independent, like equals + for (int i = 0; i != rdns.length; i++) + { + if (rdns[i].isMultiValued()) + { + AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); + + for (int j = 0; j != atv.length; j++) + { + hashCodeValue ^= atv[j].getType().hashCode(); + hashCodeValue ^= calcHashCode(atv[j].getValue()); + } + } + else + { + hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); + hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); + } + } + + return hashCodeValue; + } + + + /** + * For all string values starting with '#' is assumed, that these are + * already valid ASN.1 objects encoded in hex. + *

+ * All other string values are send to + * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}. + *

+ * Subclasses should overwrite + * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)} + * to change the encoding of specific types. + * + * @param oid the DN name of the value. + * @param value the String representation of the value. + */ + public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) + { + if (value.length() != 0 && value.charAt(0) == '#') + { + try + { + return IETFUtils.valueFromHexString(value, 1); + } + catch (IOException e) + { + throw new ASN1ParsingException("can't recode value for oid " + oid.getId()); + } + } + + if (value.length() != 0 && value.charAt(0) == '\\') + { + value = value.substring(1); + } + + return encodeStringValue(oid, value); + } + + /** + * Encoded every value into a UTF8String. + *

+ * Subclasses should overwrite + * this method to change the encoding of specific types. + *

+ * + * @param oid the DN oid of the value + * @param value the String representation of the value + * @return a the value encoded into a ASN.1 object. Never returns null. + */ + protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, String value) + { + return new DERUTF8String(value); + } + + public boolean areEqual(X500Name name1, X500Name name2) + { + RDN[] rdns1 = name1.getRDNs(); + RDN[] rdns2 = name2.getRDNs(); + + if (rdns1.length != rdns2.length) + { + return false; + } + + boolean reverse = false; + + if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) + { + reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward + } + + for (int i = 0; i != rdns1.length; i++) + { + if (!foundMatch(reverse, rdns1[i], rdns2)) + { + return false; + } + } + + return true; + } + + private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) + { + if (reverse) + { + for (int i = possRDNs.length - 1; i >= 0; i--) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + else + { + for (int i = 0; i != possRDNs.length; i++) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + + return false; + } + + protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) + { + return IETFUtils.rDNAreEqual(rdn1, rdn2); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java index 6842182..34b4385 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java @@ -1,7 +1,5 @@ package org.bouncycastle.asn1.x500.style; -import java.io.IOException; -import java.util.Enumeration; import java.util.Hashtable; import org.bouncycastle.asn1.ASN1Encodable; @@ -9,51 +7,49 @@ import org.bouncycastle.asn1.ASN1GeneralizedTime; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DERPrintableString; -import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x500.AttributeTypeAndValue; import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500NameStyle; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; public class BCStyle - implements X500NameStyle + extends AbstractX500NameStyle { /** * country code - StringType(SIZE(2)) */ - public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6"); + public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6").intern(); /** * organization - StringType(SIZE(1..64)) */ - public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10"); + public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10").intern(); /** * organizational unit name - StringType(SIZE(1..64)) */ - public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11"); + public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11").intern(); /** * Title */ - public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12"); + public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12").intern(); /** * common name - StringType(SIZE(1..64)) */ - public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3"); + public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3").intern(); /** * device serial number name - StringType(SIZE(1..64)) */ - public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5"); + public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5").intern(); /** * street - StringType(SIZE(1..64)) */ - public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9"); + public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9").intern(); /** * device serial number name - StringType(SIZE(1..64)) @@ -63,95 +59,95 @@ public class BCStyle /** * locality name - StringType(SIZE(1..64)) */ - public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7"); + public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7").intern(); /** * state, or province name - StringType(SIZE(1..64)) */ - public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8"); + public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8").intern(); /** * Naming attributes of type X520name */ - public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4"); - public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42"); - public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43"); - public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44"); - public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45"); + public static final ASN1ObjectIdentifier SURNAME = new ASN1ObjectIdentifier("2.5.4.4").intern(); + public static final ASN1ObjectIdentifier GIVENNAME = new ASN1ObjectIdentifier("2.5.4.42").intern(); + public static final ASN1ObjectIdentifier INITIALS = new ASN1ObjectIdentifier("2.5.4.43").intern(); + public static final ASN1ObjectIdentifier GENERATION = new ASN1ObjectIdentifier("2.5.4.44").intern(); + public static final ASN1ObjectIdentifier UNIQUE_IDENTIFIER = new ASN1ObjectIdentifier("2.5.4.45").intern(); /** * businessCategory - DirectoryString(SIZE(1..128) */ public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier( - "2.5.4.15"); + "2.5.4.15").intern(); /** * postalCode - DirectoryString(SIZE(1..40) */ public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier( - "2.5.4.17"); + "2.5.4.17").intern(); /** * dnQualifier - DirectoryString(SIZE(1..64) */ public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier( - "2.5.4.46"); + "2.5.4.46").intern(); /** * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64) */ public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier( - "2.5.4.65"); + "2.5.4.65").intern(); /** * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z */ public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.1"); + "1.3.6.1.5.5.7.9.1").intern(); /** * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128) */ public static final ASN1ObjectIdentifier PLACE_OF_BIRTH = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.2"); + "1.3.6.1.5.5.7.9.2").intern(); /** * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f" */ public static final ASN1ObjectIdentifier GENDER = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.3"); + "1.3.6.1.5.5.7.9.3").intern(); /** * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166 * codes only */ public static final ASN1ObjectIdentifier COUNTRY_OF_CITIZENSHIP = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.4"); + "1.3.6.1.5.5.7.9.4").intern(); /** * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166 * codes only */ public static final ASN1ObjectIdentifier COUNTRY_OF_RESIDENCE = new ASN1ObjectIdentifier( - "1.3.6.1.5.5.7.9.5"); + "1.3.6.1.5.5.7.9.5").intern(); /** * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64) */ - public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14"); + public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14").intern(); /** * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF * DirectoryString(SIZE(1..30)) */ - public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16"); + public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16").intern(); /** * RFC 2256 dmdName */ - public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54"); + public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54").intern(); /** * id-at-telephoneNumber @@ -285,42 +281,24 @@ public class BCStyle defaultSymbols = copyHashTable(DefaultSymbols); defaultLookUp = copyHashTable(DefaultLookUp); } - - public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) - { - if (value.length() != 0 && value.charAt(0) == '#') + + protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, + String value) { + if (oid.equals(EmailAddress) || oid.equals(DC)) { - try - { - return IETFUtils.valueFromHexString(value, 1); - } - catch (IOException e) - { - throw new RuntimeException("can't recode value for oid " + oid.getId()); - } + return new DERIA5String(value); } - else + else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility) { - if (value.length() != 0 && value.charAt(0) == '\\') - { - value = value.substring(1); - } - if (oid.equals(EmailAddress) || oid.equals(DC)) - { - return new DERIA5String(value); - } - else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility) - { - return new ASN1GeneralizedTime(value); - } - else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER) - || oid.equals(TELEPHONE_NUMBER)) - { - return new DERPrintableString(value); - } + return new ASN1GeneralizedTime(value); } - - return new DERUTF8String(value); + else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER) + || oid.equals(TELEPHONE_NUMBER)) + { + return new DERPrintableString(value); + } + + return super.encodeStringValue(oid, value); } public String oidToDisplayName(ASN1ObjectIdentifier oid) @@ -338,109 +316,11 @@ public class BCStyle return IETFUtils.decodeAttrName(attrName, defaultLookUp); } - public boolean areEqual(X500Name name1, X500Name name2) - { - RDN[] rdns1 = name1.getRDNs(); - RDN[] rdns2 = name2.getRDNs(); - - if (rdns1.length != rdns2.length) - { - return false; - } - - boolean reverse = false; - - if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) - { - reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward - } - - for (int i = 0; i != rdns1.length; i++) - { - if (!foundMatch(reverse, rdns1[i], rdns2)) - { - return false; - } - } - - return true; - } - - private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) - { - if (reverse) - { - for (int i = possRDNs.length - 1; i >= 0; i--) - { - if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) - { - possRDNs[i] = null; - return true; - } - } - } - else - { - for (int i = 0; i != possRDNs.length; i++) - { - if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) - { - possRDNs[i] = null; - return true; - } - } - } - - return false; - } - - protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) - { - return IETFUtils.rDNAreEqual(rdn1, rdn2); - } - public RDN[] fromString(String dirName) { return IETFUtils.rDNsFromString(dirName, this); } - public int calculateHashCode(X500Name name) - { - int hashCodeValue = 0; - RDN[] rdns = name.getRDNs(); - - // this needs to be order independent, like equals - for (int i = 0; i != rdns.length; i++) - { - if (rdns[i].isMultiValued()) - { - AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); - - for (int j = 0; j != atv.length; j++) - { - hashCodeValue ^= atv[j].getType().hashCode(); - hashCodeValue ^= calcHashCode(atv[j].getValue()); - } - } - else - { - hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); - hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); - } - } - - return hashCodeValue; - } - - private int calcHashCode(ASN1Encodable enc) - { - String value = IETFUtils.valueToString(enc); - - value = IETFUtils.canonicalize(value); - - return value.hashCode(); - } - public String toString(X500Name name) { StringBuffer buf = new StringBuffer(); @@ -465,17 +345,5 @@ public class BCStyle return buf.toString(); } - private static Hashtable copyHashTable(Hashtable paramsMap) - { - Hashtable newTable = new Hashtable(); - Enumeration keys = paramsMap.keys(); - while (keys.hasMoreElements()) - { - Object key = keys.nextElement(); - newTable.put(key, paramsMap.get(key)); - } - - return newTable; - } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java index b4f1794..9df924c 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java @@ -322,7 +322,10 @@ public class IETFUtils } else { - IETFUtils.appendTypeAndValue(buf, rdn.getFirst(), oidSymbols); + if (rdn.getFirst() != null) + { + IETFUtils.appendTypeAndValue(buf, rdn.getFirst(), oidSymbols); + } } } @@ -438,7 +441,7 @@ public class IETFUtils public static String canonicalize(String s) { - String value = Strings.toLowerCase(s.trim()); + String value = Strings.toLowerCase(s); if (value.length() > 0 && value.charAt(0) == '#') { @@ -446,7 +449,27 @@ public class IETFUtils if (obj instanceof ASN1String) { - value = Strings.toLowerCase(((ASN1String)obj).getString().trim()); + value = Strings.toLowerCase(((ASN1String)obj).getString()); + } + } + + if (value.length() > 1) + { + int start = 0; + while (start + 1 < value.length() && value.charAt(start) == '\\' && value.charAt(start + 1) == ' ') + { + start += 2; + } + + int end = value.length() - 1; + while (end - 1 > 0 && value.charAt(end - 1) == '\\' && value.charAt(end) == ' ') + { + end -= 2; + } + + if (start > 0 || end < value.length() - 1) + { + value = value.substring(start, end + 1); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java index 8c92257..2a40fb0 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java @@ -1,65 +1,61 @@ package org.bouncycastle.asn1.x500.style; -import java.io.IOException; -import java.util.Enumeration; import java.util.Hashtable; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DERPrintableString; -import org.bouncycastle.asn1.DERUTF8String; -import org.bouncycastle.asn1.x500.AttributeTypeAndValue; import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500NameStyle; public class RFC4519Style - implements X500NameStyle + extends AbstractX500NameStyle { - public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15"); - public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6"); - public static final ASN1ObjectIdentifier cn = new ASN1ObjectIdentifier("2.5.4.3"); - public static final ASN1ObjectIdentifier dc = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25"); - public static final ASN1ObjectIdentifier description = new ASN1ObjectIdentifier("2.5.4.13"); - public static final ASN1ObjectIdentifier destinationIndicator = new ASN1ObjectIdentifier("2.5.4.27"); - public static final ASN1ObjectIdentifier distinguishedName = new ASN1ObjectIdentifier("2.5.4.49"); - public static final ASN1ObjectIdentifier dnQualifier = new ASN1ObjectIdentifier("2.5.4.46"); - public static final ASN1ObjectIdentifier enhancedSearchGuide = new ASN1ObjectIdentifier("2.5.4.47"); - public static final ASN1ObjectIdentifier facsimileTelephoneNumber = new ASN1ObjectIdentifier("2.5.4.23"); - public static final ASN1ObjectIdentifier generationQualifier = new ASN1ObjectIdentifier("2.5.4.44"); - public static final ASN1ObjectIdentifier givenName = new ASN1ObjectIdentifier("2.5.4.42"); - public static final ASN1ObjectIdentifier houseIdentifier = new ASN1ObjectIdentifier("2.5.4.51"); - public static final ASN1ObjectIdentifier initials = new ASN1ObjectIdentifier("2.5.4.43"); - public static final ASN1ObjectIdentifier internationalISDNNumber = new ASN1ObjectIdentifier("2.5.4.25"); - public static final ASN1ObjectIdentifier l = new ASN1ObjectIdentifier("2.5.4.7"); - public static final ASN1ObjectIdentifier member = new ASN1ObjectIdentifier("2.5.4.31"); - public static final ASN1ObjectIdentifier name = new ASN1ObjectIdentifier("2.5.4.41"); - public static final ASN1ObjectIdentifier o = new ASN1ObjectIdentifier("2.5.4.10"); - public static final ASN1ObjectIdentifier ou = new ASN1ObjectIdentifier("2.5.4.11"); - public static final ASN1ObjectIdentifier owner = new ASN1ObjectIdentifier("2.5.4.32"); - public static final ASN1ObjectIdentifier physicalDeliveryOfficeName = new ASN1ObjectIdentifier("2.5.4.19"); - public static final ASN1ObjectIdentifier postalAddress = new ASN1ObjectIdentifier("2.5.4.16"); - public static final ASN1ObjectIdentifier postalCode = new ASN1ObjectIdentifier("2.5.4.17"); - public static final ASN1ObjectIdentifier postOfficeBox = new ASN1ObjectIdentifier("2.5.4.18"); - public static final ASN1ObjectIdentifier preferredDeliveryMethod = new ASN1ObjectIdentifier("2.5.4.28"); - public static final ASN1ObjectIdentifier registeredAddress = new ASN1ObjectIdentifier("2.5.4.26"); - public static final ASN1ObjectIdentifier roleOccupant = new ASN1ObjectIdentifier("2.5.4.33"); - public static final ASN1ObjectIdentifier searchGuide = new ASN1ObjectIdentifier("2.5.4.14"); - public static final ASN1ObjectIdentifier seeAlso = new ASN1ObjectIdentifier("2.5.4.34"); - public static final ASN1ObjectIdentifier serialNumber = new ASN1ObjectIdentifier("2.5.4.5"); - public static final ASN1ObjectIdentifier sn = new ASN1ObjectIdentifier("2.5.4.4"); - public static final ASN1ObjectIdentifier st = new ASN1ObjectIdentifier("2.5.4.8"); - public static final ASN1ObjectIdentifier street = new ASN1ObjectIdentifier("2.5.4.9"); - public static final ASN1ObjectIdentifier telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20"); - public static final ASN1ObjectIdentifier teletexTerminalIdentifier = new ASN1ObjectIdentifier("2.5.4.22"); - public static final ASN1ObjectIdentifier telexNumber = new ASN1ObjectIdentifier("2.5.4.21"); - public static final ASN1ObjectIdentifier title = new ASN1ObjectIdentifier("2.5.4.12"); - public static final ASN1ObjectIdentifier uid = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1"); - public static final ASN1ObjectIdentifier uniqueMember = new ASN1ObjectIdentifier("2.5.4.50"); - public static final ASN1ObjectIdentifier userPassword = new ASN1ObjectIdentifier("2.5.4.35"); - public static final ASN1ObjectIdentifier x121Address = new ASN1ObjectIdentifier("2.5.4.24"); - public static final ASN1ObjectIdentifier x500UniqueIdentifier = new ASN1ObjectIdentifier("2.5.4.45"); + public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15").intern(); + public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6").intern(); + public static final ASN1ObjectIdentifier cn = new ASN1ObjectIdentifier("2.5.4.3").intern(); + public static final ASN1ObjectIdentifier dc = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25").intern(); + public static final ASN1ObjectIdentifier description = new ASN1ObjectIdentifier("2.5.4.13").intern(); + public static final ASN1ObjectIdentifier destinationIndicator = new ASN1ObjectIdentifier("2.5.4.27").intern(); + public static final ASN1ObjectIdentifier distinguishedName = new ASN1ObjectIdentifier("2.5.4.49").intern(); + public static final ASN1ObjectIdentifier dnQualifier = new ASN1ObjectIdentifier("2.5.4.46").intern(); + public static final ASN1ObjectIdentifier enhancedSearchGuide = new ASN1ObjectIdentifier("2.5.4.47").intern(); + public static final ASN1ObjectIdentifier facsimileTelephoneNumber = new ASN1ObjectIdentifier("2.5.4.23").intern(); + public static final ASN1ObjectIdentifier generationQualifier = new ASN1ObjectIdentifier("2.5.4.44").intern(); + public static final ASN1ObjectIdentifier givenName = new ASN1ObjectIdentifier("2.5.4.42").intern(); + public static final ASN1ObjectIdentifier houseIdentifier = new ASN1ObjectIdentifier("2.5.4.51").intern(); + public static final ASN1ObjectIdentifier initials = new ASN1ObjectIdentifier("2.5.4.43").intern(); + public static final ASN1ObjectIdentifier internationalISDNNumber = new ASN1ObjectIdentifier("2.5.4.25").intern(); + public static final ASN1ObjectIdentifier l = new ASN1ObjectIdentifier("2.5.4.7").intern(); + public static final ASN1ObjectIdentifier member = new ASN1ObjectIdentifier("2.5.4.31").intern(); + public static final ASN1ObjectIdentifier name = new ASN1ObjectIdentifier("2.5.4.41").intern(); + public static final ASN1ObjectIdentifier o = new ASN1ObjectIdentifier("2.5.4.10").intern(); + public static final ASN1ObjectIdentifier ou = new ASN1ObjectIdentifier("2.5.4.11").intern(); + public static final ASN1ObjectIdentifier owner = new ASN1ObjectIdentifier("2.5.4.32").intern(); + public static final ASN1ObjectIdentifier physicalDeliveryOfficeName = new ASN1ObjectIdentifier("2.5.4.19").intern(); + public static final ASN1ObjectIdentifier postalAddress = new ASN1ObjectIdentifier("2.5.4.16").intern(); + public static final ASN1ObjectIdentifier postalCode = new ASN1ObjectIdentifier("2.5.4.17").intern(); + public static final ASN1ObjectIdentifier postOfficeBox = new ASN1ObjectIdentifier("2.5.4.18").intern(); + public static final ASN1ObjectIdentifier preferredDeliveryMethod = new ASN1ObjectIdentifier("2.5.4.28").intern(); + public static final ASN1ObjectIdentifier registeredAddress = new ASN1ObjectIdentifier("2.5.4.26").intern(); + public static final ASN1ObjectIdentifier roleOccupant = new ASN1ObjectIdentifier("2.5.4.33").intern(); + public static final ASN1ObjectIdentifier searchGuide = new ASN1ObjectIdentifier("2.5.4.14").intern(); + public static final ASN1ObjectIdentifier seeAlso = new ASN1ObjectIdentifier("2.5.4.34").intern(); + public static final ASN1ObjectIdentifier serialNumber = new ASN1ObjectIdentifier("2.5.4.5").intern(); + public static final ASN1ObjectIdentifier sn = new ASN1ObjectIdentifier("2.5.4.4").intern(); + public static final ASN1ObjectIdentifier st = new ASN1ObjectIdentifier("2.5.4.8").intern(); + public static final ASN1ObjectIdentifier street = new ASN1ObjectIdentifier("2.5.4.9").intern(); + public static final ASN1ObjectIdentifier telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20").intern(); + public static final ASN1ObjectIdentifier teletexTerminalIdentifier = new ASN1ObjectIdentifier("2.5.4.22").intern(); + public static final ASN1ObjectIdentifier telexNumber = new ASN1ObjectIdentifier("2.5.4.21").intern(); + public static final ASN1ObjectIdentifier title = new ASN1ObjectIdentifier("2.5.4.12").intern(); + public static final ASN1ObjectIdentifier uid = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1").intern(); + public static final ASN1ObjectIdentifier uniqueMember = new ASN1ObjectIdentifier("2.5.4.50").intern(); + public static final ASN1ObjectIdentifier userPassword = new ASN1ObjectIdentifier("2.5.4.35").intern(); + public static final ASN1ObjectIdentifier x121Address = new ASN1ObjectIdentifier("2.5.4.24").intern(); + public static final ASN1ObjectIdentifier x500UniqueIdentifier = new ASN1ObjectIdentifier("2.5.4.45").intern(); /** * default look up table translating OID values into their common symbols following @@ -179,37 +175,19 @@ public class RFC4519Style defaultLookUp = copyHashTable(DefaultLookUp); } - public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) - { - if (value.length() != 0 && value.charAt(0) == '#') + protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, + String value) { + if (oid.equals(dc)) { - try - { - return IETFUtils.valueFromHexString(value, 1); - } - catch (IOException e) - { - throw new RuntimeException("can't recode value for oid " + oid.getId()); - } + return new DERIA5String(value); } - else + else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier) + || oid.equals(telephoneNumber)) { - if (value.length() != 0 && value.charAt(0) == '\\') - { - value = value.substring(1); - } - if (oid.equals(dc)) - { - return new DERIA5String(value); - } - else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier) - || oid.equals(telephoneNumber)) - { - return new DERPrintableString(value); - } + return new DERPrintableString(value); } - return new DERUTF8String(value); + return super.encodeStringValue(oid, value); } public String oidToDisplayName(ASN1ObjectIdentifier oid) @@ -227,67 +205,6 @@ public class RFC4519Style return IETFUtils.decodeAttrName(attrName, defaultLookUp); } - public boolean areEqual(X500Name name1, X500Name name2) - { - RDN[] rdns1 = name1.getRDNs(); - RDN[] rdns2 = name2.getRDNs(); - - if (rdns1.length != rdns2.length) - { - return false; - } - - boolean reverse = false; - - if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) - { - reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward - } - - for (int i = 0; i != rdns1.length; i++) - { - if (!foundMatch(reverse, rdns1[i], rdns2)) - { - return false; - } - } - - return true; - } - - private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) - { - if (reverse) - { - for (int i = possRDNs.length - 1; i >= 0; i--) - { - if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) - { - possRDNs[i] = null; - return true; - } - } - } - else - { - for (int i = 0; i != possRDNs.length; i++) - { - if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) - { - possRDNs[i] = null; - return true; - } - } - } - - return false; - } - - protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) - { - return IETFUtils.rDNAreEqual(rdn1, rdn2); - } - // parse backwards public RDN[] fromString(String dirName) { @@ -302,43 +219,6 @@ public class RFC4519Style return res; } - public int calculateHashCode(X500Name name) - { - int hashCodeValue = 0; - RDN[] rdns = name.getRDNs(); - - // this needs to be order independent, like equals - for (int i = 0; i != rdns.length; i++) - { - if (rdns[i].isMultiValued()) - { - AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); - - for (int j = 0; j != atv.length; j++) - { - hashCodeValue ^= atv[j].getType().hashCode(); - hashCodeValue ^= calcHashCode(atv[j].getValue()); - } - } - else - { - hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); - hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); - } - } - - return hashCodeValue; - } - - private int calcHashCode(ASN1Encodable enc) - { - String value = IETFUtils.valueToString(enc); - - value = IETFUtils.canonicalize(value); - - return value.hashCode(); - } - // convert in reverse public String toString(X500Name name) { @@ -364,17 +244,5 @@ public class RFC4519Style return buf.toString(); } - private static Hashtable copyHashTable(Hashtable paramsMap) - { - Hashtable newTable = new Hashtable(); - - Enumeration keys = paramsMap.keys(); - while (keys.hasMoreElements()) - { - Object key = keys.nextElement(); - newTable.put(key, paramsMap.get(key)); - } - - return newTable; - } + } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java index 2c8e3fc..b7e52f2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java @@ -6,7 +6,7 @@ package org.bouncycastle.asn1.x500.style; * lightweight Java environment don't support classes like * StringTokenizer. */ -class X500NameTokenizer +public class X500NameTokenizer { private String value; private int index; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java index d250bf1..54eaa32 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java @@ -7,16 +7,13 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; public class AlgorithmIdentifier extends ASN1Object { - private ASN1ObjectIdentifier objectId; + private ASN1ObjectIdentifier algorithm; private ASN1Encodable parameters; - private boolean parametersDefined = false; public static AlgorithmIdentifier getInstance( ASN1TaggedObject obj, @@ -24,84 +21,37 @@ public class AlgorithmIdentifier { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + public static AlgorithmIdentifier getInstance( Object obj) { - if (obj== null || obj instanceof AlgorithmIdentifier) + if (obj instanceof AlgorithmIdentifier) { return (AlgorithmIdentifier)obj; } - - // TODO: delete - if (obj instanceof ASN1ObjectIdentifier) - { - return new AlgorithmIdentifier((ASN1ObjectIdentifier)obj); - } - - // TODO: delete - if (obj instanceof String) + else if (obj != null) { - return new AlgorithmIdentifier((String)obj); + return new AlgorithmIdentifier(ASN1Sequence.getInstance(obj)); } - return new AlgorithmIdentifier(ASN1Sequence.getInstance(obj)); - } - - public AlgorithmIdentifier( - ASN1ObjectIdentifier objectId) - { - this.objectId = objectId; - } - - /** - * @deprecated use ASN1ObjectIdentifier - * @param objectId - */ - public AlgorithmIdentifier( - String objectId) - { - this.objectId = new ASN1ObjectIdentifier(objectId); - } - - /** - * @deprecated use ASN1ObjectIdentifier - * @param objectId - */ - public AlgorithmIdentifier( - DERObjectIdentifier objectId) - { - this.objectId = new ASN1ObjectIdentifier(objectId.getId()); + return null; } - /** - * @deprecated use ASN1ObjectIdentifier - * @param objectId - * @param parameters - */ public AlgorithmIdentifier( - DERObjectIdentifier objectId, - ASN1Encodable parameters) + ASN1ObjectIdentifier algorithm) { - parametersDefined = true; - this.objectId = new ASN1ObjectIdentifier(objectId.getId()); - this.parameters = parameters; + this.algorithm = algorithm; } public AlgorithmIdentifier( - ASN1ObjectIdentifier objectId, + ASN1ObjectIdentifier algorithm, ASN1Encodable parameters) { - parametersDefined = true; - this.objectId = objectId; + this.algorithm = algorithm; this.parameters = parameters; } - /** - * @deprecated use AlgorithmIdentifier.getInstance() - * @param seq - */ - public AlgorithmIdentifier( + private AlgorithmIdentifier( ASN1Sequence seq) { if (seq.size() < 1 || seq.size() > 2) @@ -109,12 +59,11 @@ public class AlgorithmIdentifier throw new IllegalArgumentException("Bad sequence size: " + seq.size()); } - - objectId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + + algorithm = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); if (seq.size() == 2) { - parametersDefined = true; parameters = seq.getObjectAt(1); } else @@ -125,16 +74,7 @@ public class AlgorithmIdentifier public ASN1ObjectIdentifier getAlgorithm() { - return new ASN1ObjectIdentifier(objectId.getId()); - } - - /** - * @deprecated use getAlgorithm - * @return - */ - public ASN1ObjectIdentifier getObjectId() - { - return objectId; + return algorithm; } public ASN1Encodable getParameters() @@ -154,18 +94,11 @@ public class AlgorithmIdentifier { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(objectId); + v.add(algorithm); - if (parametersDefined) + if (parameters != null) { - if (parameters != null) - { - v.add(parameters); - } - else - { - v.add(DERNull.INSTANCE); - } + v.add(parameters); } return new DERSequence(v); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java index 9c5ed46..20f6ea3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java @@ -103,7 +103,7 @@ public class AuthorityKeyIdentifier * publicKey.getEncoded()).readObject()); * AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki); *
- * + * @deprecated create the extension using org.bouncycastle.cert.X509ExtensionUtils **/ public AuthorityKeyIdentifier( SubjectPublicKeyInfo spki) @@ -122,6 +122,7 @@ public class AuthorityKeyIdentifier /** * create an AuthorityKeyIdentifier with the GeneralNames tag and * the serial number provided as well. + * @deprecated create the extension using org.bouncycastle.cert.X509ExtensionUtils */ public AuthorityKeyIdentifier( SubjectPublicKeyInfo spki, @@ -150,9 +151,7 @@ public class AuthorityKeyIdentifier GeneralNames name, BigInteger serialNumber) { - this.keyidentifier = null; - this.certissuer = GeneralNames.getInstance(name.toASN1Primitive()); - this.certserno = new ASN1Integer(serialNumber); + this((byte[])null, name, serialNumber); } /** @@ -161,9 +160,7 @@ public class AuthorityKeyIdentifier public AuthorityKeyIdentifier( byte[] keyIdentifier) { - this.keyidentifier = new DEROctetString(keyIdentifier); - this.certissuer = null; - this.certserno = null; + this(keyIdentifier, null, null); } /** @@ -175,9 +172,9 @@ public class AuthorityKeyIdentifier GeneralNames name, BigInteger serialNumber) { - this.keyidentifier = new DEROctetString(keyIdentifier); - this.certissuer = GeneralNames.getInstance(name.toASN1Primitive()); - this.certserno = new ASN1Integer(serialNumber); + this.keyidentifier = (keyIdentifier != null) ? new DEROctetString(keyIdentifier) : null; + this.certissuer = name; + this.certserno = (serialNumber != null) ? new ASN1Integer(serialNumber) : null; } public byte[] getKeyIdentifier() diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java index 4a16bd4..ba5ecf1 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java @@ -9,7 +9,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DERBoolean; import org.bouncycastle.asn1.DERSequence; public class BasicConstraints @@ -59,9 +58,9 @@ public class BasicConstraints } else { - if (seq.getObjectAt(0) instanceof DERBoolean) + if (seq.getObjectAt(0) instanceof ASN1Boolean) { - this.cA = DERBoolean.getInstance(seq.getObjectAt(0)); + this.cA = ASN1Boolean.getInstance(seq.getObjectAt(0)); } else { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java index 1ee6aa5..dd3422f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java @@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.util.Strings; public class CRLDistPoint extends ASN1Object @@ -84,7 +85,7 @@ public class CRLDistPoint public String toString() { StringBuffer buf = new StringBuffer(); - String sep = System.getProperty("line.separator"); + String sep = Strings.lineSeparator(); buf.append("CRLDistPoint:"); buf.append(sep); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java index ab73dfb..48e5640 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java @@ -8,6 +8,7 @@ import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.util.Strings; /** * The DistributionPoint object. @@ -121,7 +122,7 @@ public class DistributionPoint public String toString() { - String sep = System.getProperty("line.separator"); + String sep = Strings.lineSeparator(); StringBuffer buf = new StringBuffer(); buf.append("DistributionPoint: ["); buf.append(sep); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java index ee06efd..f69ccb3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java @@ -7,6 +7,7 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.util.Strings; /** * The DistributionPointName object. @@ -105,7 +106,7 @@ public class DistributionPointName public String toString() { - String sep = System.getProperty("line.separator"); + String sep = Strings.lineSeparator(); StringBuffer buf = new StringBuffer(); buf.append("DistributionPointName: ["); buf.append(sep); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java index 4d566b1..456e3d3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java @@ -22,157 +22,157 @@ public class Extension /** * Subject Directory Attributes */ - public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9"); + public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9").intern(); /** * Subject Key Identifier */ - public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14"); + public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14").intern(); /** * Key Usage */ - public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15"); + public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15").intern(); /** * Private Key Usage Period */ - public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16"); + public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16").intern(); /** * Subject Alternative Name */ - public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17"); + public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17").intern(); /** * Issuer Alternative Name */ - public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18"); + public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18").intern(); /** * Basic Constraints */ - public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19"); + public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19").intern(); /** * CRL Number */ - public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20"); + public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20").intern(); /** * Reason code */ - public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21"); + public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21").intern(); /** * Hold Instruction Code */ - public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23"); + public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23").intern(); /** * Invalidity Date */ - public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24"); + public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24").intern(); /** * Delta CRL indicator */ - public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27"); + public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27").intern(); /** * Issuing Distribution Point */ - public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28"); + public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28").intern(); /** * Certificate Issuer */ - public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29"); + public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29").intern(); /** * Name Constraints */ - public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30"); + public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30").intern(); /** * CRL Distribution Points */ - public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31"); + public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31").intern(); /** * Certificate Policies */ - public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32"); + public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32").intern(); /** * Policy Mappings */ - public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33"); + public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33").intern(); /** * Authority Key Identifier */ - public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35"); + public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35").intern(); /** * Policy Constraints */ - public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36"); + public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36").intern(); /** * Extended Key Usage */ - public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37"); + public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37").intern(); /** * Freshest CRL */ - public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46"); + public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46").intern(); /** * Inhibit Any Policy */ - public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54"); + public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54").intern(); /** * Authority Info Access */ - public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1"); + public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1").intern(); /** * Subject Info Access */ - public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11"); + public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11").intern(); /** * Logo Type */ - public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12"); + public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12").intern(); /** * BiometricInfo */ - public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2"); + public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2").intern(); /** * QCStatements */ - public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3"); + public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3").intern(); /** * Audit identity extension in attribute certificates. */ - public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4"); + public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4").intern(); /** * NoRevAvail extension in attribute certificates. */ - public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56"); + public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56").intern(); /** * TargetInformation extension in attribute certificates. */ - public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55"); + public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55").intern(); private ASN1ObjectIdentifier extnId; private boolean critical; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java index 1aeed15..6508f93 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java @@ -43,8 +43,9 @@ public class Extensions /** * Constructor from ASN1Sequence. - *

- * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString) + *

+ * The extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString) + *

*/ private Extensions( ASN1Sequence seq) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java index 270ef1c..d20e62f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java @@ -65,6 +65,23 @@ public class ExtensionsGenerator extensions.put(oid, new Extension(oid, critical, new DEROctetString(value))); } + /** + * Add a given extension. + * + * @param extension the full extension value. + */ + public void addExtension( + Extension extension) + { + if (extensions.containsKey(extension.getExtnId())) + { + throw new IllegalArgumentException("extension " + extension.getExtnId() + " already added"); + } + + extOrdering.addElement(extension.getExtnId()); + extensions.put(extension.getExtnId(), extension); + } + /** * Return true if there are no extension present in this generator. * diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java index 7118d10..405f6e4 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java @@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.util.Strings; public class GeneralNames extends ASN1Object @@ -92,7 +93,7 @@ public class GeneralNames public String toString() { StringBuffer buf = new StringBuffer(); - String sep = System.getProperty("line.separator"); + String sep = Strings.lineSeparator(); buf.append("GeneralNames:"); buf.append(sep); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java index 1f29162..c24b788 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java @@ -8,6 +8,7 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.util.Strings; /** *
@@ -219,7 +220,7 @@ public class IssuingDistributionPoint
 
     public String toString()
     {
-        String       sep = System.getProperty("line.separator");
+        String       sep = Strings.lineSeparator();
         StringBuffer buf = new StringBuffer();
 
         buf.append("IssuingDistributionPoint: [");
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
index 01980be..01c9aa2 100644
--- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
@@ -145,6 +145,11 @@ public class KeyPurposeId
         return null;
     }
 
+    public ASN1ObjectIdentifier toOID()
+    {
+        return id;
+    }
+
     public ASN1Primitive toASN1Primitive()
     {
         return id;
@@ -154,4 +159,9 @@ public class KeyPurposeId
     {
         return id.getId();
     }
+
+    public String toString()
+    {
+        return id.toString();
+    }
 }
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraintValidator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraintValidator.java
new file mode 100644
index 0000000..4596fe0
--- /dev/null
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraintValidator.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.asn1.x509;
+
+public interface NameConstraintValidator
+{
+    void checkPermitted(GeneralName name)
+        throws NameConstraintValidatorException;
+
+    void checkExcluded(GeneralName name)
+            throws NameConstraintValidatorException;
+
+    void intersectPermittedSubtree(GeneralSubtree permitted);
+
+    void intersectPermittedSubtree(GeneralSubtree[] permitted);
+
+    void intersectEmptyPermittedSubtree(int nameType);
+
+    void addExcludedSubtree(GeneralSubtree subtree);
+}
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraintValidatorException.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraintValidatorException.java
new file mode 100644
index 0000000..517fddb
--- /dev/null
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraintValidatorException.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.asn1.x509;
+
+public class NameConstraintValidatorException
+    extends Exception
+{
+    public NameConstraintValidatorException(String msg)
+    {
+        super(msg);
+    }
+}
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java
new file mode 100644
index 0000000..0f15dae
--- /dev/null
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java
@@ -0,0 +1,1920 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Integers;
+import org.bouncycastle.util.Strings;
+
+public class PKIXNameConstraintValidator
+    implements NameConstraintValidator
+{
+    private Set excludedSubtreesDN = new HashSet();
+
+    private Set excludedSubtreesDNS = new HashSet();
+
+    private Set excludedSubtreesEmail = new HashSet();
+
+    private Set excludedSubtreesURI = new HashSet();
+
+    private Set excludedSubtreesIP = new HashSet();
+
+    private Set permittedSubtreesDN;
+
+    private Set permittedSubtreesDNS;
+
+    private Set permittedSubtreesEmail;
+
+    private Set permittedSubtreesURI;
+
+    private Set permittedSubtreesIP;
+
+    public PKIXNameConstraintValidator()
+    {
+    }
+
+    /**
+     * Checks if the given GeneralName is in the permitted set.
+     *
+     * @param name The GeneralName
+     * @throws NameConstraintValidatorException If the name
+     */
+    public void checkPermitted(GeneralName name)
+        throws NameConstraintValidatorException
+    {
+        switch (name.getTagNo())
+        {
+        case GeneralName.rfc822Name:
+            checkPermittedEmail(permittedSubtreesEmail,
+                extractNameAsString(name));
+            break;
+        case GeneralName.dNSName:
+            checkPermittedDNS(permittedSubtreesDNS, DERIA5String.getInstance(
+                name.getName()).getString());
+            break;
+        case GeneralName.directoryName:
+            checkPermittedDN(X500Name.getInstance(name.getName()));
+            break;
+        case GeneralName.uniformResourceIdentifier:
+            checkPermittedURI(permittedSubtreesURI, DERIA5String.getInstance(
+                name.getName()).getString());
+            break;
+        case GeneralName.iPAddress:
+            byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
+
+            checkPermittedIP(permittedSubtreesIP, ip);
+        }
+    }
+
+    /**
+     * Check if the given GeneralName is contained in the excluded set.
+     *
+     * @param name The GeneralName.
+     * @throws NameConstraintValidatorException If the name is
+     * excluded.
+     */
+    public void checkExcluded(GeneralName name)
+        throws NameConstraintValidatorException
+    {
+        switch (name.getTagNo())
+        {
+        case GeneralName.rfc822Name:
+            checkExcludedEmail(excludedSubtreesEmail, extractNameAsString(name));
+            break;
+        case GeneralName.dNSName:
+            checkExcludedDNS(excludedSubtreesDNS, DERIA5String.getInstance(
+                name.getName()).getString());
+            break;
+        case GeneralName.directoryName:
+            checkExcludedDN(X500Name.getInstance(name.getName()));
+            break;
+        case GeneralName.uniformResourceIdentifier:
+            checkExcludedURI(excludedSubtreesURI, DERIA5String.getInstance(
+                name.getName()).getString());
+            break;
+        case GeneralName.iPAddress:
+            byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
+
+            checkExcludedIP(excludedSubtreesIP, ip);
+        }
+    }
+
+    public void intersectPermittedSubtree(GeneralSubtree permitted)
+    {
+        intersectPermittedSubtree(new GeneralSubtree[]{permitted});
+    }
+
+    /**
+     * Updates the permitted set of these name constraints with the intersection
+     * with the given subtree.
+     *
+     * @param permitted The permitted subtrees
+     */
+    public void intersectPermittedSubtree(GeneralSubtree[] permitted)
+    {
+        Map subtreesMap = new HashMap();
+
+        // group in sets in a map ordered by tag no.
+        for (int i = 0; i != permitted.length; i++)
+        {
+            GeneralSubtree subtree = permitted[i];
+            Integer tagNo = Integers.valueOf(subtree.getBase().getTagNo());
+            if (subtreesMap.get(tagNo) == null)
+            {
+                subtreesMap.put(tagNo, new HashSet());
+            }
+            ((Set)subtreesMap.get(tagNo)).add(subtree);
+        }
+
+        for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext(); )
+        {
+            Map.Entry entry = (Map.Entry)it.next();
+
+            // go through all subtree groups
+            switch (((Integer)entry.getKey()).intValue())
+            {
+            case GeneralName.rfc822Name:
+                permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail,
+                    (Set)entry.getValue());
+                break;
+            case GeneralName.dNSName:
+                permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS,
+                    (Set)entry.getValue());
+                break;
+            case GeneralName.directoryName:
+                permittedSubtreesDN = intersectDN(permittedSubtreesDN,
+                    (Set)entry.getValue());
+                break;
+            case GeneralName.uniformResourceIdentifier:
+                permittedSubtreesURI = intersectURI(permittedSubtreesURI,
+                    (Set)entry.getValue());
+                break;
+            case GeneralName.iPAddress:
+                permittedSubtreesIP = intersectIP(permittedSubtreesIP,
+                    (Set)entry.getValue());
+            }
+        }
+    }
+
+    public void intersectEmptyPermittedSubtree(int nameType)
+    {
+        switch (nameType)
+        {
+        case GeneralName.rfc822Name:
+            permittedSubtreesEmail = new HashSet();
+            break;
+        case GeneralName.dNSName:
+            permittedSubtreesDNS = new HashSet();
+            break;
+        case GeneralName.directoryName:
+            permittedSubtreesDN = new HashSet();
+            break;
+        case GeneralName.uniformResourceIdentifier:
+            permittedSubtreesURI = new HashSet();
+            break;
+        case GeneralName.iPAddress:
+            permittedSubtreesIP = new HashSet();
+        }
+    }
+
+    /**
+     * Adds a subtree to the excluded set of these name constraints.
+     *
+     * @param subtree A subtree with an excluded GeneralName.
+     */
+    public void addExcludedSubtree(GeneralSubtree subtree)
+    {
+        GeneralName base = subtree.getBase();
+
+        switch (base.getTagNo())
+        {
+        case GeneralName.rfc822Name:
+            excludedSubtreesEmail = unionEmail(excludedSubtreesEmail,
+                extractNameAsString(base));
+            break;
+        case GeneralName.dNSName:
+            excludedSubtreesDNS = unionDNS(excludedSubtreesDNS,
+                extractNameAsString(base));
+            break;
+        case GeneralName.directoryName:
+            excludedSubtreesDN = unionDN(excludedSubtreesDN,
+                (ASN1Sequence)base.getName().toASN1Primitive());
+            break;
+        case GeneralName.uniformResourceIdentifier:
+            excludedSubtreesURI = unionURI(excludedSubtreesURI,
+                extractNameAsString(base));
+            break;
+        case GeneralName.iPAddress:
+            excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString
+                .getInstance(base.getName()).getOctets());
+            break;
+        }
+    }
+
+    public int hashCode()
+    {
+        return hashCollection(excludedSubtreesDN)
+            + hashCollection(excludedSubtreesDNS)
+            + hashCollection(excludedSubtreesEmail)
+            + hashCollection(excludedSubtreesIP)
+            + hashCollection(excludedSubtreesURI)
+            + hashCollection(permittedSubtreesDN)
+            + hashCollection(permittedSubtreesDNS)
+            + hashCollection(permittedSubtreesEmail)
+            + hashCollection(permittedSubtreesIP)
+            + hashCollection(permittedSubtreesURI);
+    }
+
+    public boolean equals(Object o)
+    {
+        if (!(o instanceof PKIXNameConstraintValidator))
+        {
+            return false;
+        }
+        PKIXNameConstraintValidator constraintValidator = (PKIXNameConstraintValidator)o;
+        return collectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP)
+            && collectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP)
+            && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI);
+    }
+
+    public String toString()
+    {
+        String temp = "";
+        temp += "permitted:\n";
+        if (permittedSubtreesDN != null)
+        {
+            temp += "DN:\n";
+            temp += permittedSubtreesDN.toString() + "\n";
+        }
+        if (permittedSubtreesDNS != null)
+        {
+            temp += "DNS:\n";
+            temp += permittedSubtreesDNS.toString() + "\n";
+        }
+        if (permittedSubtreesEmail != null)
+        {
+            temp += "Email:\n";
+            temp += permittedSubtreesEmail.toString() + "\n";
+        }
+        if (permittedSubtreesURI != null)
+        {
+            temp += "URI:\n";
+            temp += permittedSubtreesURI.toString() + "\n";
+        }
+        if (permittedSubtreesIP != null)
+        {
+            temp += "IP:\n";
+            temp += stringifyIPCollection(permittedSubtreesIP) + "\n";
+        }
+        temp += "excluded:\n";
+        if (!excludedSubtreesDN.isEmpty())
+        {
+            temp += "DN:\n";
+            temp += excludedSubtreesDN.toString() + "\n";
+        }
+        if (!excludedSubtreesDNS.isEmpty())
+        {
+            temp += "DNS:\n";
+            temp += excludedSubtreesDNS.toString() + "\n";
+        }
+        if (!excludedSubtreesEmail.isEmpty())
+        {
+            temp += "Email:\n";
+            temp += excludedSubtreesEmail.toString() + "\n";
+        }
+        if (!excludedSubtreesURI.isEmpty())
+        {
+            temp += "URI:\n";
+            temp += excludedSubtreesURI.toString() + "\n";
+        }
+        if (!excludedSubtreesIP.isEmpty())
+        {
+            temp += "IP:\n";
+            temp += stringifyIPCollection(excludedSubtreesIP) + "\n";
+        }
+        return temp;
+    }
+
+    private void checkPermittedDN(X500Name dns)
+        throws NameConstraintValidatorException
+    {
+        checkPermittedDN(permittedSubtreesDN, ASN1Sequence.getInstance(dns.toASN1Primitive()));
+    }
+
+    private void checkExcludedDN(X500Name dns)
+        throws NameConstraintValidatorException
+    {
+        checkExcludedDN(excludedSubtreesDN, ASN1Sequence.getInstance(dns));
+    }
+
+    private static boolean withinDNSubtree(
+        ASN1Sequence dns,
+        ASN1Sequence subtree)
+    {
+        if (subtree.size() < 1)
+        {
+            return false;
+        }
+
+        if (subtree.size() > dns.size())
+        {
+            return false;
+        }
+
+        for (int j = subtree.size() - 1; j >= 0; j--)
+        {
+            if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j)))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private void checkPermittedDN(Set permitted, ASN1Sequence dns)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        if (permitted.isEmpty() && dns.size() == 0)
+        {
+            return;
+        }
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+            if (withinDNSubtree(dns, subtree))
+            {
+                return;
+            }
+        }
+
+        throw new NameConstraintValidatorException(
+            "Subject distinguished name is not from a permitted subtree");
+    }
+
+    private void checkExcludedDN(Set excluded, ASN1Sequence dns)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+            if (withinDNSubtree(dns, subtree))
+            {
+                throw new NameConstraintValidatorException(
+                    "Subject distinguished name is from an excluded subtree");
+            }
+        }
+    }
+
+    private Set intersectDN(Set permitted, Set dns)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = dns.iterator(); it.hasNext(); )
+        {
+            ASN1Sequence dn = ASN1Sequence.getInstance(((GeneralSubtree)it
+                .next()).getBase().getName().toASN1Primitive());
+            if (permitted == null)
+            {
+                if (dn != null)
+                {
+                    intersect.add(dn);
+                }
+            }
+            else
+            {
+                Iterator _iter = permitted.iterator();
+                while (_iter.hasNext())
+                {
+                    ASN1Sequence subtree = (ASN1Sequence)_iter.next();
+
+                    if (withinDNSubtree(dn, subtree))
+                    {
+                        intersect.add(dn);
+                    }
+                    else if (withinDNSubtree(subtree, dn))
+                    {
+                        intersect.add(subtree);
+                    }
+                }
+            }
+        }
+        return intersect;
+    }
+
+    private Set unionDN(Set excluded, ASN1Sequence dn)
+    {
+        if (excluded.isEmpty())
+        {
+            if (dn == null)
+            {
+                return excluded;
+            }
+            excluded.add(dn);
+
+            return excluded;
+        }
+        else
+        {
+            Set intersect = new HashSet();
+
+            Iterator it = excluded.iterator();
+            while (it.hasNext())
+            {
+                ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+                if (withinDNSubtree(dn, subtree))
+                {
+                    intersect.add(subtree);
+                }
+                else if (withinDNSubtree(subtree, dn))
+                {
+                    intersect.add(dn);
+                }
+                else
+                {
+                    intersect.add(subtree);
+                    intersect.add(dn);
+                }
+            }
+
+            return intersect;
+        }
+    }
+
+    private Set intersectEmail(Set permitted, Set emails)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = emails.iterator(); it.hasNext(); )
+        {
+            String email = extractNameAsString(((GeneralSubtree)it.next())
+                .getBase());
+
+            if (permitted == null)
+            {
+                if (email != null)
+                {
+                    intersect.add(email);
+                }
+            }
+            else
+            {
+                Iterator it2 = permitted.iterator();
+                while (it2.hasNext())
+                {
+                    String _permitted = (String)it2.next();
+
+                    intersectEmail(email, _permitted, intersect);
+                }
+            }
+        }
+        return intersect;
+    }
+
+    private Set unionEmail(Set excluded, String email)
+    {
+        if (excluded.isEmpty())
+        {
+            if (email == null)
+            {
+                return excluded;
+            }
+            excluded.add(email);
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator it = excluded.iterator();
+            while (it.hasNext())
+            {
+                String _excluded = (String)it.next();
+
+                unionEmail(_excluded, email, union);
+            }
+
+            return union;
+        }
+    }
+
+    /**
+     * Returns the intersection of the permitted IP ranges in
+     * permitted with ip.
+     *
+     * @param permitted A Set of permitted IP addresses with
+     *                  their subnet mask as byte arrays.
+     * @param ips       The IP address with its subnet mask.
+     * @return The Set of permitted IP ranges intersected with
+     * ip.
+     */
+    private Set intersectIP(Set permitted, Set ips)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = ips.iterator(); it.hasNext(); )
+        {
+            byte[] ip = ASN1OctetString.getInstance(
+                ((GeneralSubtree)it.next()).getBase().getName()).getOctets();
+            if (permitted == null)
+            {
+                if (ip != null)
+                {
+                    intersect.add(ip);
+                }
+            }
+            else
+            {
+                Iterator it2 = permitted.iterator();
+                while (it2.hasNext())
+                {
+                    byte[] _permitted = (byte[])it2.next();
+                    intersect.addAll(intersectIPRange(_permitted, ip));
+                }
+            }
+        }
+        return intersect;
+    }
+
+    /**
+     * Returns the union of the excluded IP ranges in excluded
+     * with ip.
+     *
+     * @param excluded A Set of excluded IP addresses with their
+     *                 subnet mask as byte arrays.
+     * @param ip       The IP address with its subnet mask.
+     * @return The Set of excluded IP ranges unified with
+     * ip as byte arrays.
+     */
+    private Set unionIP(Set excluded, byte[] ip)
+    {
+        if (excluded.isEmpty())
+        {
+            if (ip == null)
+            {
+                return excluded;
+            }
+            excluded.add(ip);
+
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator it = excluded.iterator();
+            while (it.hasNext())
+            {
+                byte[] _excluded = (byte[])it.next();
+                union.addAll(unionIPRange(_excluded, ip));
+            }
+
+            return union;
+        }
+    }
+
+    /**
+     * Calculates the union if two IP ranges.
+     *
+     * @param ipWithSubmask1 The first IP address with its subnet mask.
+     * @param ipWithSubmask2 The second IP address with its subnet mask.
+     * @return A Set with the union of both addresses.
+     */
+    private Set unionIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+    {
+        Set set = new HashSet();
+
+        // difficult, adding always all IPs is not wrong
+        if (Arrays.areEqual(ipWithSubmask1, ipWithSubmask2))
+        {
+            set.add(ipWithSubmask1);
+        }
+        else
+        {
+            set.add(ipWithSubmask1);
+            set.add(ipWithSubmask2);
+        }
+        return set;
+    }
+
+    /**
+     * Calculates the interesction if two IP ranges.
+     *
+     * @param ipWithSubmask1 The first IP address with its subnet mask.
+     * @param ipWithSubmask2 The second IP address with its subnet mask.
+     * @return A Set with the single IP address with its subnet
+     * mask as a byte array or an empty Set.
+     */
+    private Set intersectIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
+    {
+        if (ipWithSubmask1.length != ipWithSubmask2.length)
+        {
+            return Collections.EMPTY_SET;
+        }
+        byte[][] temp = extractIPsAndSubnetMasks(ipWithSubmask1, ipWithSubmask2);
+        byte ip1[] = temp[0];
+        byte subnetmask1[] = temp[1];
+        byte ip2[] = temp[2];
+        byte subnetmask2[] = temp[3];
+
+        byte minMax[][] = minMaxIPs(ip1, subnetmask1, ip2, subnetmask2);
+        byte[] min;
+        byte[] max;
+        max = min(minMax[1], minMax[3]);
+        min = max(minMax[0], minMax[2]);
+
+        // minimum IP address must be bigger than max
+        if (compareTo(min, max) == 1)
+        {
+            return Collections.EMPTY_SET;
+        }
+        // OR keeps all significant bits
+        byte[] ip = or(minMax[0], minMax[2]);
+        byte[] subnetmask = or(subnetmask1, subnetmask2);
+        return Collections.singleton(ipWithSubnetMask(ip, subnetmask));
+    }
+
+    /**
+     * Concatenates the IP address with its subnet mask.
+     *
+     * @param ip         The IP address.
+     * @param subnetMask Its subnet mask.
+     * @return The concatenated IP address with its subnet mask.
+     */
+    private byte[] ipWithSubnetMask(byte[] ip, byte[] subnetMask)
+    {
+        int ipLength = ip.length;
+        byte[] temp = new byte[ipLength * 2];
+        System.arraycopy(ip, 0, temp, 0, ipLength);
+        System.arraycopy(subnetMask, 0, temp, ipLength, ipLength);
+        return temp;
+    }
+
+    /**
+     * Splits the IP addresses and their subnet mask.
+     *
+     * @param ipWithSubmask1 The first IP address with the subnet mask.
+     * @param ipWithSubmask2 The second IP address with the subnet mask.
+     * @return An array with two elements. Each element contains the IP address
+     * and the subnet mask in this order.
+     */
+    private byte[][] extractIPsAndSubnetMasks(
+        byte[] ipWithSubmask1,
+        byte[] ipWithSubmask2)
+    {
+        int ipLength = ipWithSubmask1.length / 2;
+        byte ip1[] = new byte[ipLength];
+        byte subnetmask1[] = new byte[ipLength];
+        System.arraycopy(ipWithSubmask1, 0, ip1, 0, ipLength);
+        System.arraycopy(ipWithSubmask1, ipLength, subnetmask1, 0, ipLength);
+
+        byte ip2[] = new byte[ipLength];
+        byte subnetmask2[] = new byte[ipLength];
+        System.arraycopy(ipWithSubmask2, 0, ip2, 0, ipLength);
+        System.arraycopy(ipWithSubmask2, ipLength, subnetmask2, 0, ipLength);
+        return new byte[][]
+            {ip1, subnetmask1, ip2, subnetmask2};
+    }
+
+    /**
+     * Based on the two IP addresses and their subnet masks the IP range is
+     * computed for each IP address - subnet mask pair and returned as the
+     * minimum IP address and the maximum address of the range.
+     *
+     * @param ip1         The first IP address.
+     * @param subnetmask1 The subnet mask of the first IP address.
+     * @param ip2         The second IP address.
+     * @param subnetmask2 The subnet mask of the second IP address.
+     * @return A array with two elements. The first/second element contains the
+     * min and max IP address of the first/second IP address and its
+     * subnet mask.
+     */
+    private byte[][] minMaxIPs(
+        byte[] ip1,
+        byte[] subnetmask1,
+        byte[] ip2,
+        byte[] subnetmask2)
+    {
+        int ipLength = ip1.length;
+        byte[] min1 = new byte[ipLength];
+        byte[] max1 = new byte[ipLength];
+
+        byte[] min2 = new byte[ipLength];
+        byte[] max2 = new byte[ipLength];
+
+        for (int i = 0; i < ipLength; i++)
+        {
+            min1[i] = (byte)(ip1[i] & subnetmask1[i]);
+            max1[i] = (byte)(ip1[i] & subnetmask1[i] | ~subnetmask1[i]);
+
+            min2[i] = (byte)(ip2[i] & subnetmask2[i]);
+            max2[i] = (byte)(ip2[i] & subnetmask2[i] | ~subnetmask2[i]);
+        }
+
+        return new byte[][]{min1, max1, min2, max2};
+    }
+
+    private void checkPermittedEmail(Set permitted, String email)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            if (emailIsConstrained(email, str))
+            {
+                return;
+            }
+        }
+
+        if (email.length() == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+
+        throw new NameConstraintValidatorException(
+            "Subject email address is not from a permitted subtree.");
+    }
+
+    private void checkExcludedEmail(Set excluded, String email)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = (String)it.next();
+
+            if (emailIsConstrained(email, str))
+            {
+                throw new NameConstraintValidatorException(
+                    "Email address is from an excluded subtree.");
+            }
+        }
+    }
+
+    /**
+     * Checks if the IP ip is included in the permitted set
+     * permitted.
+     *
+     * @param permitted A Set of permitted IP addresses with
+     *                  their subnet mask as byte arrays.
+     * @param ip        The IP address.
+     * @throws NameConstraintValidatorException if the IP is not permitted.
+     */
+    private void checkPermittedIP(Set permitted, byte[] ip)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            byte[] ipWithSubnet = (byte[])it.next();
+
+            if (isIPConstrained(ip, ipWithSubnet))
+            {
+                return;
+            }
+        }
+        if (ip.length == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+        throw new NameConstraintValidatorException(
+            "IP is not from a permitted subtree.");
+    }
+
+    /**
+     * Checks if the IP ip is included in the excluded set
+     * excluded.
+     *
+     * @param excluded A Set of excluded IP addresses with their
+     *                 subnet mask as byte arrays.
+     * @param ip       The IP address.
+     * @throws NameConstraintValidatorException if the IP is excluded.
+     */
+    private void checkExcludedIP(Set excluded, byte[] ip)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            byte[] ipWithSubnet = (byte[])it.next();
+
+            if (isIPConstrained(ip, ipWithSubnet))
+            {
+                throw new NameConstraintValidatorException(
+                    "IP is from an excluded subtree.");
+            }
+        }
+    }
+
+    /**
+     * Checks if the IP address ip is constrained by
+     * constraint.
+     *
+     * @param ip         The IP address.
+     * @param constraint The constraint. This is an IP address concatenated with
+     *                   its subnetmask.
+     * @return true if constrained, false
+     * otherwise.
+     */
+    private boolean isIPConstrained(byte ip[], byte[] constraint)
+    {
+        int ipLength = ip.length;
+
+        if (ipLength != (constraint.length / 2))
+        {
+            return false;
+        }
+
+        byte[] subnetMask = new byte[ipLength];
+        System.arraycopy(constraint, ipLength, subnetMask, 0, ipLength);
+
+        byte[] permittedSubnetAddress = new byte[ipLength];
+
+        byte[] ipSubnetAddress = new byte[ipLength];
+
+        // the resulting IP address by applying the subnet mask
+        for (int i = 0; i < ipLength; i++)
+        {
+            permittedSubnetAddress[i] = (byte)(constraint[i] & subnetMask[i]);
+            ipSubnetAddress[i] = (byte)(ip[i] & subnetMask[i]);
+        }
+
+        return Arrays.areEqual(permittedSubnetAddress, ipSubnetAddress);
+    }
+
+    private boolean emailIsConstrained(String email, String constraint)
+    {
+        String sub = email.substring(email.indexOf('@') + 1);
+        // a particular mailbox
+        if (constraint.indexOf('@') != -1)
+        {
+            if (email.equalsIgnoreCase(constraint))
+            {
+                return true;
+            }
+        }
+        // on particular host
+        else if (!(constraint.charAt(0) == '.'))
+        {
+            if (sub.equalsIgnoreCase(constraint))
+            {
+                return true;
+            }
+        }
+        // address in sub domain
+        else if (withinDomain(sub, constraint))
+        {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean withinDomain(String testDomain, String domain)
+    {
+        String tempDomain = domain;
+        if (tempDomain.startsWith("."))
+        {
+            tempDomain = tempDomain.substring(1);
+        }
+        String[] domainParts = Strings.split(tempDomain, '.');
+        String[] testDomainParts = Strings.split(testDomain, '.');
+        // must have at least one subdomain
+        if (testDomainParts.length <= domainParts.length)
+        {
+            return false;
+        }
+        int d = testDomainParts.length - domainParts.length;
+        for (int i = -1; i < domainParts.length; i++)
+        {
+            if (i == -1)
+            {
+                if (testDomainParts[i + d].equals(""))
+                {
+                    return false;
+                }
+            }
+            else if (!domainParts[i].equalsIgnoreCase(testDomainParts[i + d]))
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void checkPermittedDNS(Set permitted, String dns)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            // is sub domain
+            if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
+            {
+                return;
+            }
+        }
+        if (dns.length() == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+        throw new NameConstraintValidatorException(
+            "DNS is not from a permitted subtree.");
+    }
+
+    private void checkExcludedDNS(Set excluded, String dns)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            // is sub domain or the same
+            if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
+            {
+                throw new NameConstraintValidatorException(
+                    "DNS is from an excluded subtree.");
+            }
+        }
+    }
+
+    /**
+     * The common part of email1 and email2 is
+     * added to the union union. If email1 and
+     * email2 have nothing in common they are added both.
+     *
+     * @param email1 Email address constraint 1.
+     * @param email2 Email address constraint 2.
+     * @param union  The union.
+     */
+    private void unionEmail(String email1, String email2, Set union)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email1 specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+    }
+
+    private void unionURI(String email1, String email2, Set union)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email1 specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email2);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+        // email specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    union.add(email2);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    union.add(email1);
+                }
+                else
+                {
+                    union.add(email1);
+                    union.add(email2);
+                }
+            }
+        }
+    }
+
+    private Set intersectDNS(Set permitted, Set dnss)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = dnss.iterator(); it.hasNext(); )
+        {
+            String dns = extractNameAsString(((GeneralSubtree)it.next())
+                .getBase());
+            if (permitted == null)
+            {
+                if (dns != null)
+                {
+                    intersect.add(dns);
+                }
+            }
+            else
+            {
+                Iterator _iter = permitted.iterator();
+                while (_iter.hasNext())
+                {
+                    String _permitted = (String)_iter.next();
+
+                    if (withinDomain(_permitted, dns))
+                    {
+                        intersect.add(_permitted);
+                    }
+                    else if (withinDomain(dns, _permitted))
+                    {
+                        intersect.add(dns);
+                    }
+                }
+            }
+        }
+
+        return intersect;
+    }
+
+    private Set unionDNS(Set excluded, String dns)
+    {
+        if (excluded.isEmpty())
+        {
+            if (dns == null)
+            {
+                return excluded;
+            }
+            excluded.add(dns);
+
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator _iter = excluded.iterator();
+            while (_iter.hasNext())
+            {
+                String _permitted = (String)_iter.next();
+
+                if (withinDomain(_permitted, dns))
+                {
+                    union.add(dns);
+                }
+                else if (withinDomain(dns, _permitted))
+                {
+                    union.add(_permitted);
+                }
+                else
+                {
+                    union.add(_permitted);
+                    union.add(dns);
+                }
+            }
+
+            return union;
+        }
+    }
+
+    /**
+     * The most restricting part from email1 and
+     * email2 is added to the intersection intersect.
+     *
+     * @param email1    Email address constraint 1.
+     * @param email2    Email address constraint 2.
+     * @param intersect The intersection.
+     */
+    private void intersectEmail(String email1, String email2, Set intersect)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+        // email specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+        }
+        // email1 specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email2.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+    }
+
+    private void checkExcludedURI(Set excluded, String uri)
+        throws NameConstraintValidatorException
+    {
+        if (excluded.isEmpty())
+        {
+            return;
+        }
+
+        Iterator it = excluded.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            if (isUriConstrained(uri, str))
+            {
+                throw new NameConstraintValidatorException(
+                    "URI is from an excluded subtree.");
+            }
+        }
+    }
+
+    private Set intersectURI(Set permitted, Set uris)
+    {
+        Set intersect = new HashSet();
+        for (Iterator it = uris.iterator(); it.hasNext(); )
+        {
+            String uri = extractNameAsString(((GeneralSubtree)it.next())
+                .getBase());
+            if (permitted == null)
+            {
+                if (uri != null)
+                {
+                    intersect.add(uri);
+                }
+            }
+            else
+            {
+                Iterator _iter = permitted.iterator();
+                while (_iter.hasNext())
+                {
+                    String _permitted = (String)_iter.next();
+                    intersectURI(_permitted, uri, intersect);
+                }
+            }
+        }
+        return intersect;
+    }
+
+    private Set unionURI(Set excluded, String uri)
+    {
+        if (excluded.isEmpty())
+        {
+            if (uri == null)
+            {
+                return excluded;
+            }
+            excluded.add(uri);
+
+            return excluded;
+        }
+        else
+        {
+            Set union = new HashSet();
+
+            Iterator _iter = excluded.iterator();
+            while (_iter.hasNext())
+            {
+                String _excluded = (String)_iter.next();
+
+                unionURI(_excluded, uri, union);
+            }
+
+            return union;
+        }
+    }
+
+    private void intersectURI(String email1, String email2, Set intersect)
+    {
+        // email1 is a particular address
+        if (email1.indexOf('@') != -1)
+        {
+            String _sub = email1.substring(email1.indexOf('@') + 1);
+            // both are a particular mailbox
+            if (email2.indexOf('@') != -1)
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(_sub, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (_sub.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+        // email specifies a domain
+        else if (email1.startsWith("."))
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email1.indexOf('@') + 1);
+                if (withinDomain(_sub, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2)
+                    || email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+                else if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            else
+            {
+                if (withinDomain(email2, email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+        }
+        // email1 specifies a host
+        else
+        {
+            if (email2.indexOf('@') != -1)
+            {
+                String _sub = email2.substring(email2.indexOf('@') + 1);
+                if (_sub.equalsIgnoreCase(email1))
+                {
+                    intersect.add(email2);
+                }
+            }
+            // email2 specifies a domain
+            else if (email2.startsWith("."))
+            {
+                if (withinDomain(email1, email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+            // email2 specifies a particular host
+            else
+            {
+                if (email1.equalsIgnoreCase(email2))
+                {
+                    intersect.add(email1);
+                }
+            }
+        }
+    }
+
+    private void checkPermittedURI(Set permitted, String uri)
+        throws NameConstraintValidatorException
+    {
+        if (permitted == null)
+        {
+            return;
+        }
+
+        Iterator it = permitted.iterator();
+
+        while (it.hasNext())
+        {
+            String str = ((String)it.next());
+
+            if (isUriConstrained(uri, str))
+            {
+                return;
+            }
+        }
+        if (uri.length() == 0 && permitted.size() == 0)
+        {
+            return;
+        }
+        throw new NameConstraintValidatorException(
+            "URI is not from a permitted subtree.");
+    }
+
+    private boolean isUriConstrained(String uri, String constraint)
+    {
+        String host = extractHostFromURL(uri);
+        // a host
+        if (!constraint.startsWith("."))
+        {
+            if (host.equalsIgnoreCase(constraint))
+            {
+                return true;
+            }
+        }
+
+        // in sub domain or domain
+        else if (withinDomain(host, constraint))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    private static String extractHostFromURL(String url)
+    {
+        // see RFC 1738
+        // remove ':' after protocol, e.g. http:
+        String sub = url.substring(url.indexOf(':') + 1);
+        // extract host from Common Internet Scheme Syntax, e.g. http://
+        if (sub.indexOf("//") != -1)
+        {
+            sub = sub.substring(sub.indexOf("//") + 2);
+        }
+        // first remove port, e.g. http://test.com:21
+        if (sub.lastIndexOf(':') != -1)
+        {
+            sub = sub.substring(0, sub.lastIndexOf(':'));
+        }
+        // remove user and password, e.g. http://john:password@test.com
+        sub = sub.substring(sub.indexOf(':') + 1);
+        sub = sub.substring(sub.indexOf('@') + 1);
+        // remove local parts, e.g. http://test.com/bla
+        if (sub.indexOf('/') != -1)
+        {
+            sub = sub.substring(0, sub.indexOf('/'));
+        }
+        return sub;
+    }
+
+    private String extractNameAsString(GeneralName name)
+    {
+        return DERIA5String.getInstance(name.getName()).getString();
+    }
+
+    /**
+     * Returns the maximum IP address.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return The maximum IP address.
+     */
+    private static byte[] max(byte[] ip1, byte[] ip2)
+    {
+        for (int i = 0; i < ip1.length; i++)
+        {
+            if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF))
+            {
+                return ip1;
+            }
+        }
+        return ip2;
+    }
+
+    /**
+     * Returns the minimum IP address.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return The minimum IP address.
+     */
+    private static byte[] min(byte[] ip1, byte[] ip2)
+    {
+        for (int i = 0; i < ip1.length; i++)
+        {
+            if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF))
+            {
+                return ip1;
+            }
+        }
+        return ip2;
+    }
+
+    /**
+     * Compares IP address ip1 with ip2. If ip1
+     * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1
+     * otherwise.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise.
+     */
+    private static int compareTo(byte[] ip1, byte[] ip2)
+    {
+        if (Arrays.areEqual(ip1, ip2))
+        {
+            return 0;
+        }
+        if (Arrays.areEqual(max(ip1, ip2), ip1))
+        {
+            return 1;
+        }
+        return -1;
+    }
+
+    /**
+     * Returns the logical OR of the IP addresses ip1 and
+     * ip2.
+     *
+     * @param ip1 The first IP address.
+     * @param ip2 The second IP address.
+     * @return The OR of ip1 and ip2.
+     */
+    private static byte[] or(byte[] ip1, byte[] ip2)
+    {
+        byte[] temp = new byte[ip1.length];
+        for (int i = 0; i < ip1.length; i++)
+        {
+            temp[i] = (byte)(ip1[i] | ip2[i]);
+        }
+        return temp;
+    }
+
+    private int hashCollection(Collection coll)
+    {
+        if (coll == null)
+        {
+            return 0;
+        }
+        int hash = 0;
+        Iterator it1 = coll.iterator();
+        while (it1.hasNext())
+        {
+            Object o = it1.next();
+            if (o instanceof byte[])
+            {
+                hash += Arrays.hashCode((byte[])o);
+            }
+            else
+            {
+                hash += o.hashCode();
+            }
+        }
+        return hash;
+    }
+
+    private boolean collectionsAreEqual(Collection coll1, Collection coll2)
+    {
+        if (coll1 == coll2)
+        {
+            return true;
+        }
+        if (coll1 == null || coll2 == null)
+        {
+            return false;
+        }
+        if (coll1.size() != coll2.size())
+        {
+            return false;
+        }
+        Iterator it1 = coll1.iterator();
+
+        while (it1.hasNext())
+        {
+            Object a = it1.next();
+            Iterator it2 = coll2.iterator();
+            boolean found = false;
+            while (it2.hasNext())
+            {
+                Object b = it2.next();
+                if (equals(a, b))
+                {
+                    found = true;
+                    break;
+                }
+            }
+            if (!found)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean equals(Object o1, Object o2)
+    {
+        if (o1 == o2)
+        {
+            return true;
+        }
+        if (o1 == null || o2 == null)
+        {
+            return false;
+        }
+        if (o1 instanceof byte[] && o2 instanceof byte[])
+        {
+            return Arrays.areEqual((byte[])o1, (byte[])o2);
+        }
+        else
+        {
+            return o1.equals(o2);
+        }
+    }
+
+    /**
+     * Stringifies an IPv4 or v6 address with subnet mask.
+     *
+     * @param ip The IP with subnet mask.
+     * @return The stringified IP address.
+     */
+    private String stringifyIP(byte[] ip)
+    {
+        String temp = "";
+        for (int i = 0; i < ip.length / 2; i++)
+        {
+            temp += Integer.toString(ip[i] & 0x00FF) + ".";
+        }
+        temp = temp.substring(0, temp.length() - 1);
+        temp += "/";
+        for (int i = ip.length / 2; i < ip.length; i++)
+        {
+            temp += Integer.toString(ip[i] & 0x00FF) + ".";
+        }
+        temp = temp.substring(0, temp.length() - 1);
+        return temp;
+    }
+
+    private String stringifyIPCollection(Set ips)
+    {
+        String temp = "";
+        temp += "[";
+        for (Iterator it = ips.iterator(); it.hasNext(); )
+        {
+            temp += stringifyIP((byte[])it.next()) + ",";
+        }
+        if (temp.length() > 1)
+        {
+            temp = temp.substring(0, temp.length() - 1);
+        }
+        temp += "]";
+        return temp;
+    }
+}
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
index d1de26f..97f752a 100644
--- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
@@ -65,11 +65,13 @@ public class PolicyInformation
         return policyQualifiers;
     }
     
-    /* 
+    /*
+     * 
      * PolicyInformation ::= SEQUENCE {
      *      policyIdentifier   CertPolicyId,
      *      policyQualifiers   SEQUENCE SIZE (1..MAX) OF
      *              PolicyQualifierInfo OPTIONAL }
+     * 
*/ public ASN1Primitive toASN1Primitive() { @@ -84,4 +86,31 @@ public class PolicyInformation return new DERSequence(v); } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + + sb.append("Policy information: "); + sb.append(policyIdentifier); + + if (policyQualifiers != null) + { + StringBuffer p = new StringBuffer(); + for (int i = 0; i < policyQualifiers.size(); i++) + { + if (p.length() != 0) + { + p.append(", "); + } + p.append(PolicyQualifierInfo.getInstance(policyQualifiers.getObjectAt(i))); + } + + sb.append("["); + sb.append(p); + sb.append("]"); + } + + return sb.toString(); + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierId.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierId.java new file mode 100644 index 0000000..82835f6 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierId.java @@ -0,0 +1,31 @@ + +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * PolicyQualifierId, used in the CertificatePolicies + * X509V3 extension. + * + *
+ *    id-qt          OBJECT IDENTIFIER ::=  { id-pkix 2 }
+ *    id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
+ *    id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
+ *  PolicyQualifierId ::=
+ *       OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice)
+ * 
+ */ +public class PolicyQualifierId extends ASN1ObjectIdentifier +{ + private static final String id_qt = "1.3.6.1.5.5.7.2"; + + private PolicyQualifierId(String id) + { + super(id); + } + + public static final PolicyQualifierId id_qt_cps = + new PolicyQualifierId(id_qt + ".1"); + public static final PolicyQualifierId id_qt_unotice = + new PolicyQualifierId(id_qt + ".2"); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java new file mode 100644 index 0000000..2f79a96 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java @@ -0,0 +1,117 @@ +package org.bouncycastle.asn1.x509; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DERSequence; + +/** + * Policy qualifiers, used in the X509V3 CertificatePolicies + * extension. + * + *
+ *   PolicyQualifierInfo ::= SEQUENCE {
+ *       policyQualifierId  PolicyQualifierId,
+ *       qualifier          ANY DEFINED BY policyQualifierId }
+ *
+ *  PolicyQualifierId ::= OBJECT IDENTIFIER ( id-qt-cps | id-qt-unotice )
+ * 
+ */ +public class PolicyQualifierInfo + extends ASN1Object +{ + private ASN1ObjectIdentifier policyQualifierId; + private ASN1Encodable qualifier; + + /** + * Creates a new PolicyQualifierInfo instance. + * + * @param policyQualifierId a PolicyQualifierId value + * @param qualifier the qualifier, defined by the above field. + */ + public PolicyQualifierInfo( + ASN1ObjectIdentifier policyQualifierId, + ASN1Encodable qualifier) + { + this.policyQualifierId = policyQualifierId; + this.qualifier = qualifier; + } + + /** + * Creates a new PolicyQualifierInfo containing a + * cPSuri qualifier. + * + * @param cps the CPS (certification practice statement) uri as a + * String. + */ + public PolicyQualifierInfo( + String cps) + { + policyQualifierId = PolicyQualifierId.id_qt_cps; + qualifier = new DERIA5String (cps); + } + + /** + * Creates a new PolicyQualifierInfo instance. + * + * @param as PolicyQualifierInfo X509 structure + * encoded as an ASN1Sequence. + * @deprecated use PolicyQualifierInfo.getInstance() + */ + public PolicyQualifierInfo( + ASN1Sequence as) + { + if (as.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + + as.size()); + } + + policyQualifierId = ASN1ObjectIdentifier.getInstance(as.getObjectAt(0)); + qualifier = as.getObjectAt(1); + } + + public static PolicyQualifierInfo getInstance( + Object obj) + { + if (obj instanceof PolicyQualifierInfo) + { + return (PolicyQualifierInfo)obj; + } + else if (obj != null) + { + return new PolicyQualifierInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + + public ASN1ObjectIdentifier getPolicyQualifierId() + { + return policyQualifierId; + } + + public ASN1Encodable getQualifier() + { + return qualifier; + } + + /** + * Returns a DER-encodable representation of this instance. + * + * @return a ASN1Primitive value + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector dev = new ASN1EncodableVector(); + dev.add(policyQualifierId); + dev.add(qualifier); + + return new DERSequence(dev); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java index 1a9400d..5f0cd07 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java @@ -5,10 +5,6 @@ import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.crypto.Digest; -// BEGIN android-changed -import org.bouncycastle.crypto.digests.AndroidDigestFactory; -// END android-changed /** * The SubjectKeyIdentifier object. @@ -69,71 +65,4 @@ public class SubjectKeyIdentifier { return new DEROctetString(keyidentifier); } - - - /** - * Calculates the keyidentifier using a SHA1 hash over the BIT STRING - * from SubjectPublicKeyInfo as defined in RFC3280. - * - * @param spki the subject public key info. - * @deprecated - */ - public SubjectKeyIdentifier( - SubjectPublicKeyInfo spki) - { - this.keyidentifier = getDigest(spki); - } - - /** - * Return a RFC 3280 type 1 key identifier. As in: - *
-     * (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
-     * value of the BIT STRING subjectPublicKey (excluding the tag,
-     * length, and number of unused bits).
-     * 
- * @param keyInfo the key info object containing the subjectPublicKey field. - * @return the key identifier. - * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createSubjectKeyIdentifier - */ - public static SubjectKeyIdentifier createSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo) - { - return new SubjectKeyIdentifier(keyInfo); - } - - /** - * Return a RFC 3280 type 2 key identifier. As in: - *
-     * (2) The keyIdentifier is composed of a four bit type field with
-     * the value 0100 followed by the least significant 60 bits of the
-     * SHA-1 hash of the value of the BIT STRING subjectPublicKey.
-     * 
- * @param keyInfo the key info object containing the subjectPublicKey field. - * @return the key identifier. - * @deprecated use org.bouncycastle.cert.X509ExtensionUtils.createTruncatedSubjectKeyIdentifier - */ - public static SubjectKeyIdentifier createTruncatedSHA1KeyIdentifier(SubjectPublicKeyInfo keyInfo) - { - byte[] dig = getDigest(keyInfo); - byte[] id = new byte[8]; - - System.arraycopy(dig, dig.length - 8, id, 0, id.length); - - id[0] &= 0x0f; - id[0] |= 0x40; - - return new SubjectKeyIdentifier(id); - } - - private static byte[] getDigest(SubjectPublicKeyInfo spki) - { - // BEGIN android-changed - Digest digest = AndroidDigestFactory.getSHA1(); - // END android-changed - byte[] resBuf = new byte[digest.getDigestSize()]; - - byte[] bytes = spki.getPublicKeyData().getBytes(); - digest.update(bytes, 0, bytes.length); - digest.doFinal(resBuf, 0); - return resBuf; - } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java index 9e09cd7..0938a94 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java @@ -64,6 +64,9 @@ public class SubjectPublicKeyInfo this.algId = algId; } + /** + @deprecated use SubjectPublicKeyInfo.getInstance() + */ public SubjectPublicKeyInfo( ASN1Sequence seq) { @@ -104,7 +107,7 @@ public class SubjectPublicKeyInfo public ASN1Primitive parsePublicKey() throws IOException { - ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes()); + ASN1InputStream aIn = new ASN1InputStream(keyData.getOctets()); return aIn.readObject(); } @@ -121,7 +124,7 @@ public class SubjectPublicKeyInfo public ASN1Primitive getPublicKey() throws IOException { - ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes()); + ASN1InputStream aIn = new ASN1InputStream(keyData.getOctets()); return aIn.readObject(); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java index ce657a7..23f99d0 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java @@ -1,17 +1,18 @@ package org.bouncycastle.asn1.x509; import java.util.Enumeration; +import java.util.NoSuchElementException; import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1GeneralizedTime; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DERGeneralizedTime; +import org.bouncycastle.asn1.ASN1UTCTime; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.DERUTCTime; import org.bouncycastle.asn1.x500.X500Name; /** @@ -132,7 +133,7 @@ public class TBSCertList public Object nextElement() { - return null; // TODO: check exception handling + throw new NoSuchElementException("Empty Enumeration"); } } @@ -190,8 +191,8 @@ public class TBSCertList thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++)); if (seqPos < seq.size() - && (seq.getObjectAt(seqPos) instanceof DERUTCTime - || seq.getObjectAt(seqPos) instanceof DERGeneralizedTime + && (seq.getObjectAt(seqPos) instanceof ASN1UTCTime + || seq.getObjectAt(seqPos) instanceof ASN1GeneralizedTime || seq.getObjectAt(seqPos) instanceof Time)) { nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++)); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Time.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Time.java index 5bffedc..989de4c 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Time.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/Time.java @@ -2,13 +2,17 @@ package org.bouncycastle.asn1.x509; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; +import java.util.Locale; import java.util.SimpleTimeZone; import org.bouncycastle.asn1.ASN1Choice; +import org.bouncycastle.asn1.ASN1GeneralizedTime; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.ASN1UTCTime; import org.bouncycastle.asn1.DERGeneralizedTime; import org.bouncycastle.asn1.DERUTCTime; @@ -28,8 +32,8 @@ public class Time public Time( ASN1Primitive time) { - if (!(time instanceof DERUTCTime) - && !(time instanceof DERGeneralizedTime)) + if (!(time instanceof ASN1UTCTime) + && !(time instanceof ASN1GeneralizedTime)) { throw new IllegalArgumentException("unknown object passed to Time"); } @@ -38,28 +42,68 @@ public class Time } /** - * creates a time object from a given date - if the date is between 1950 + * Creates a time object from a given date - if the date is between 1950 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime * is used. + * + * @param time a date object representing the time of interest. */ public Time( - Date date) + Date time) { SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); - SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); + // END android-changed dateF.setTimeZone(tz); - String d = dateF.format(date) + "Z"; + String d = dateF.format(time) + "Z"; int year = Integer.parseInt(d.substring(0, 4)); if (year < 1950 || year > 2049) { - time = new DERGeneralizedTime(d); + this.time = new DERGeneralizedTime(d); } else { - time = new DERUTCTime(d.substring(2)); + this.time = new DERUTCTime(d.substring(2)); + } + } + + /** + * Creates a time object from a given date and locale - if the date is between 1950 + * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime + * is used. You may need to use this constructor if the default locale + * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. + * + * @param time a date object representing the time of interest. + * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. + */ + public Time( + Date time, + Locale locale) + { + SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); + // BEGIN android-changed + // Was: SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale); + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", Locale.US); + dateF.setCalendar(Calendar.getInstance(locale)); + // END android-changed + + dateF.setTimeZone(tz); + + String d = dateF.format(time) + "Z"; + int year = Integer.parseInt(d.substring(0, 4)); + + if (year < 1950 || year > 2049) + { + this.time = new DERGeneralizedTime(d); + } + else + { + this.time = new DERUTCTime(d.substring(2)); } } @@ -70,13 +114,13 @@ public class Time { return (Time)obj; } - else if (obj instanceof DERUTCTime) + else if (obj instanceof ASN1UTCTime) { - return new Time((DERUTCTime)obj); + return new Time((ASN1UTCTime)obj); } - else if (obj instanceof DERGeneralizedTime) + else if (obj instanceof ASN1GeneralizedTime) { - return new Time((DERGeneralizedTime)obj); + return new Time((ASN1GeneralizedTime)obj); } throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); @@ -84,13 +128,13 @@ public class Time public String getTime() { - if (time instanceof DERUTCTime) + if (time instanceof ASN1UTCTime) { - return ((DERUTCTime)time).getAdjustedTime(); + return ((ASN1UTCTime)time).getAdjustedTime(); } else { - return ((DERGeneralizedTime)time).getTime(); + return ((ASN1GeneralizedTime)time).getTime(); } } @@ -98,13 +142,13 @@ public class Time { try { - if (time instanceof DERUTCTime) + if (time instanceof ASN1UTCTime) { - return ((DERUTCTime)time).getAdjustedDate(); + return ((ASN1UTCTime)time).getAdjustedDate(); } else { - return ((DERGeneralizedTime)time).getDate(); + return ((ASN1GeneralizedTime)time).getDate(); } } catch (ParseException e) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java index 3d923b6..d778d7f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java @@ -2,10 +2,10 @@ package org.bouncycastle.asn1.x509; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1UTCTime; import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.DERUTCTime; import org.bouncycastle.asn1.x500.X500Name; /** @@ -74,7 +74,7 @@ public class V3TBSCertificateGenerator } public void setStartDate( - DERUTCTime startDate) + ASN1UTCTime startDate) { this.startDate = new Time(startDate); } @@ -86,7 +86,7 @@ public class V3TBSCertificateGenerator } public void setEndDate( - DERUTCTime endDate) + ASN1UTCTime endDate) { this.endDate = new Time(endDate); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java index f29284d..9353057 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java @@ -2,11 +2,11 @@ package org.bouncycastle.asn1.x509; import java.io.IOException; +import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DERBoolean; /** * an object for the elements in the X.509 V3 extension block. @@ -173,7 +173,7 @@ public class X509Extension ASN1OctetString value; public X509Extension( - DERBoolean critical, + ASN1Boolean critical, ASN1OctetString value) { this.critical = critical.isTrue(); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java index c72e3cc..5b9ea9e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java @@ -4,6 +4,7 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; +import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1ObjectIdentifier; @@ -11,8 +12,6 @@ import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DERBoolean; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; /** @@ -259,7 +258,7 @@ public class X509Extensions if (s.size() == 3) { - extensions.put(s.getObjectAt(0), new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)))); + extensions.put(s.getObjectAt(0), new X509Extension(ASN1Boolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)))); } else if (s.size() == 2) { @@ -368,17 +367,6 @@ public class X509Extensions * * @return the extension if it's present, null otherwise. */ - public X509Extension getExtension( - DERObjectIdentifier oid) - { - return (X509Extension)extensions.get(oid); - } - - /** - * @deprecated - * @param oid - * @return - */ public X509Extension getExtension( ASN1ObjectIdentifier oid) { @@ -410,7 +398,7 @@ public class X509Extensions if (ext.isCritical()) { - v.add(DERBoolean.TRUE); + v.add(ASN1Boolean.TRUE); } v.add(ext.getValue()); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java index 468d1b9..589d512 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java @@ -7,7 +7,6 @@ import java.util.Vector; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DEROctetString; /** @@ -28,28 +27,6 @@ public class X509ExtensionsGenerator extOrdering = new Vector(); } - /** - * @deprecated use ASN1ObjectIdentifier - */ - public void addExtension( - DERObjectIdentifier oid, - boolean critical, - ASN1Encodable value) - { - addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); - } - - /** - * @deprecated use ASN1ObjectIdentifier - */ - public void addExtension( - DERObjectIdentifier oid, - boolean critical, - byte[] value) - { - addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); - } - /** * Add an extension with the given oid and the passed in value to be included * in the OCTET STRING associated with the extension. diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java index 5d919e1..188af43 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java @@ -23,7 +23,7 @@ import org.bouncycastle.util.Strings; * ASN1ObjectIdentifier oid, * String value) * { - * if (str.length() != 0 && str.charAt(0) == '#') + * if (str.length() != 0 && str.charAt(0) == '#') * { * return convertHexEncoded(str, 1); * } @@ -45,6 +45,7 @@ import org.bouncycastle.util.Strings; * } * } * } + *
*/ public abstract class X509NameEntryConverter { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java index e1c7a54..e58220e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java @@ -6,22 +6,22 @@ public interface X509ObjectIdentifiers { /** Subject RDN components: commonName = 2.5.4.3 */ - static final ASN1ObjectIdentifier commonName = new ASN1ObjectIdentifier("2.5.4.3"); + static final ASN1ObjectIdentifier commonName = new ASN1ObjectIdentifier("2.5.4.3").intern(); /** Subject RDN components: countryName = 2.5.4.6 */ - static final ASN1ObjectIdentifier countryName = new ASN1ObjectIdentifier("2.5.4.6"); + static final ASN1ObjectIdentifier countryName = new ASN1ObjectIdentifier("2.5.4.6").intern(); /** Subject RDN components: localityName = 2.5.4.7 */ - static final ASN1ObjectIdentifier localityName = new ASN1ObjectIdentifier("2.5.4.7"); + static final ASN1ObjectIdentifier localityName = new ASN1ObjectIdentifier("2.5.4.7").intern(); /** Subject RDN components: stateOrProvinceName = 2.5.4.8 */ - static final ASN1ObjectIdentifier stateOrProvinceName = new ASN1ObjectIdentifier("2.5.4.8"); + static final ASN1ObjectIdentifier stateOrProvinceName = new ASN1ObjectIdentifier("2.5.4.8").intern(); /** Subject RDN components: organization = 2.5.4.10 */ - static final ASN1ObjectIdentifier organization = new ASN1ObjectIdentifier("2.5.4.10"); + static final ASN1ObjectIdentifier organization = new ASN1ObjectIdentifier("2.5.4.10").intern(); /** Subject RDN components: organizationalUnitName = 2.5.4.11 */ - static final ASN1ObjectIdentifier organizationalUnitName = new ASN1ObjectIdentifier("2.5.4.11"); + static final ASN1ObjectIdentifier organizationalUnitName = new ASN1ObjectIdentifier("2.5.4.11").intern(); /** Subject RDN components: telephone_number = 2.5.4.20 */ - static final ASN1ObjectIdentifier id_at_telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20"); + static final ASN1ObjectIdentifier id_at_telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20").intern(); /** Subject RDN components: name = 2.5.4.41 */ - static final ASN1ObjectIdentifier id_at_name = new ASN1ObjectIdentifier("2.5.4.41"); + static final ASN1ObjectIdentifier id_at_name = new ASN1ObjectIdentifier("2.5.4.41").intern(); /** * id-SHA1 OBJECT IDENTIFIER ::= @@ -29,7 +29,7 @@ public interface X509ObjectIdentifiers *

* OID: 1.3.14.3.2.27 */ - static final ASN1ObjectIdentifier id_SHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26"); + static final ASN1ObjectIdentifier id_SHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26").intern(); /** * ripemd160 OBJECT IDENTIFIER ::= @@ -37,7 +37,7 @@ public interface X509ObjectIdentifiers *

* OID: 1.3.36.3.2.1 */ - static final ASN1ObjectIdentifier ripemd160 = new ASN1ObjectIdentifier("1.3.36.3.2.1"); + static final ASN1ObjectIdentifier ripemd160 = new ASN1ObjectIdentifier("1.3.36.3.2.1").intern(); /** * ripemd160WithRSAEncryption OBJECT IDENTIFIER ::= @@ -45,11 +45,11 @@ public interface X509ObjectIdentifiers *

* OID: 1.3.36.3.3.1.2 */ - static final ASN1ObjectIdentifier ripemd160WithRSAEncryption = new ASN1ObjectIdentifier("1.3.36.3.3.1.2"); + static final ASN1ObjectIdentifier ripemd160WithRSAEncryption = new ASN1ObjectIdentifier("1.3.36.3.3.1.2").intern(); /** OID: 2.5.8.1.1 */ - static final ASN1ObjectIdentifier id_ea_rsa = new ASN1ObjectIdentifier("2.5.8.1.1"); + static final ASN1ObjectIdentifier id_ea_rsa = new ASN1ObjectIdentifier("2.5.8.1.1").intern(); /** id-pkix OID: 1.3.6.1.5.5.7 */ @@ -70,9 +70,9 @@ public interface X509ObjectIdentifiers /** id-pkix OID: 1.3.6.1.5.5.7.48 */ static final ASN1ObjectIdentifier id_ad = id_pkix.branch("48"); /** id-ad-caIssuers OID: 1.3.6.1.5.5.7.48.2 */ - static final ASN1ObjectIdentifier id_ad_caIssuers = id_ad.branch("2"); + static final ASN1ObjectIdentifier id_ad_caIssuers = id_ad.branch("2").intern(); /** id-ad-ocsp OID: 1.3.6.1.5.5.7.48.1 */ - static final ASN1ObjectIdentifier id_ad_ocsp = id_ad.branch("1"); + static final ASN1ObjectIdentifier id_ad_ocsp = id_ad.branch("1").intern(); /** OID for ocsp uri in AuthorityInformationAccess extension */ static final ASN1ObjectIdentifier ocspAccessMethod = id_ad_ocsp; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java index 6a97a48..abff363 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java @@ -1,5 +1,6 @@ package org.bouncycastle.asn1.x9; +import java.math.BigInteger; import java.util.Enumeration; import org.bouncycastle.asn1.ASN1Encodable; @@ -11,6 +12,9 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERSequence; +/** + * @deprecated use DomainParameters + */ public class DHDomainParameters extends ASN1Object { @@ -38,6 +42,29 @@ public class DHDomainParameters + obj.getClass().getName()); } + public DHDomainParameters(BigInteger p, BigInteger g, BigInteger q, BigInteger j, + DHValidationParms validationParms) + { + if (p == null) + { + throw new IllegalArgumentException("'p' cannot be null"); + } + if (g == null) + { + throw new IllegalArgumentException("'g' cannot be null"); + } + if (q == null) + { + throw new IllegalArgumentException("'q' cannot be null"); + } + + this.p = new ASN1Integer(p); + this.g = new ASN1Integer(g); + this.q = new ASN1Integer(q); + this.j = new ASN1Integer(j); + this.validationParms = validationParms; + } + public DHDomainParameters(ASN1Integer p, ASN1Integer g, ASN1Integer q, ASN1Integer j, DHValidationParms validationParms) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java index 7c6d217..a74188a 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java @@ -1,20 +1,41 @@ package org.bouncycastle.asn1.x9; +import java.math.BigInteger; + import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; +/** + * X9.42 definition of a DHPublicKey + *

+ *     DHPublicKey ::= INTEGER
+ * 
+ */ public class DHPublicKey extends ASN1Object { private ASN1Integer y; + /** + * Return a DHPublicKey from the passed in tagged object. + * + * @param obj a tagged object. + * @param explicit true if the contents of the object is explictly tagged, false otherwise. + * @return a DHPublicKey + */ public static DHPublicKey getInstance(ASN1TaggedObject obj, boolean explicit) { return getInstance(ASN1Integer.getInstance(obj, explicit)); } + /** + * Return a DHPublicKey from the passed in object. + * + * @param obj an object for conversion or a byte[]. + * @return a DHPublicKey + */ public static DHPublicKey getInstance(Object obj) { if (obj == null || obj instanceof DHPublicKey) @@ -30,7 +51,7 @@ public class DHPublicKey throw new IllegalArgumentException("Invalid DHPublicKey: " + obj.getClass().getName()); } - public DHPublicKey(ASN1Integer y) + private DHPublicKey(ASN1Integer y) { if (y == null) { @@ -40,13 +61,38 @@ public class DHPublicKey this.y = y; } - public ASN1Integer getY() + /** + * Base constructor. + * + * @param y the public value Y. + */ + public DHPublicKey(BigInteger y) { - return this.y; + if (y == null) + { + throw new IllegalArgumentException("'y' cannot be null"); + } + + this.y = new ASN1Integer(y); + } + + /** + * Return the public value Y for the key. + * + * @return the Y value. + */ + public BigInteger getY() + { + return this.y.getPositiveValue(); } + /** + * Return an ASN.1 primitive representation of this object. + * + * @return an ASN1Integer. + */ public ASN1Primitive toASN1Primitive() { return this.y; } -} +} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java index 78b0979..db38459 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java @@ -9,6 +9,9 @@ import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERSequence; +/** + * @deprecated use ValidationParams + */ public class DHValidationParms extends ASN1Object { private DERBitString seed; @@ -21,17 +24,16 @@ public class DHValidationParms extends ASN1Object public static DHValidationParms getInstance(Object obj) { - if (obj == null || obj instanceof DHDomainParameters) + if (obj instanceof DHValidationParms) { return (DHValidationParms)obj; } - - if (obj instanceof ASN1Sequence) + else if (obj != null) { - return new DHValidationParms((ASN1Sequence)obj); + return new DHValidationParms(ASN1Sequence.getInstance(obj)); } - throw new IllegalArgumentException("Invalid DHValidationParms: " + obj.getClass().getName()); + return null; } public DHValidationParms(DERBitString seed, ASN1Integer pgenCounter) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DomainParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DomainParameters.java new file mode 100644 index 0000000..e23f1b8 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/DomainParameters.java @@ -0,0 +1,223 @@ +package org.bouncycastle.asn1.x9; + +import java.math.BigInteger; +import java.util.Enumeration; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERSequence; + +/** + * X9.44 Diffie-Hellman domain parameters. + *
+ *    DomainParameters ::= SEQUENCE {
+ *       p                INTEGER,           -- odd prime, p=jq +1
+ *       g                INTEGER,           -- generator, g
+ *       q                INTEGER,           -- factor of p-1
+ *       j                INTEGER OPTIONAL,  -- subgroup factor, j>= 2
+ *       validationParams  ValidationParams OPTIONAL
+ *    }
+ * 
+ */ +public class DomainParameters + extends ASN1Object +{ + private final ASN1Integer p, g, q, j; + private final ValidationParams validationParams; + + /** + * Return a DomainParameters object from the passed in tagged object. + * + * @param obj a tagged object. + * @param explicit true if the contents of the object is explictly tagged, false otherwise. + * @return a DomainParameters + */ + public static DomainParameters getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + /** + * Return a DomainParameters object from the passed in object. + * + * @param obj an object for conversion or a byte[]. + * @return a DomainParameters + */ + public static DomainParameters getInstance(Object obj) + { + if (obj instanceof DomainParameters) + { + return (DomainParameters)obj; + } + else if (obj != null) + { + return new DomainParameters(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + /** + * Base constructor - the full domain parameter set. + * + * @param p the prime p defining the Galois field. + * @param g the generator of the multiplicative subgroup of order g. + * @param q specifies the prime factor of p - 1 + * @param j optionally specifies the value that satisfies the equation p = jq+1 + * @param validationParams parameters for validating these domain parameters. + */ + public DomainParameters(BigInteger p, BigInteger g, BigInteger q, BigInteger j, + ValidationParams validationParams) + { + if (p == null) + { + throw new IllegalArgumentException("'p' cannot be null"); + } + if (g == null) + { + throw new IllegalArgumentException("'g' cannot be null"); + } + if (q == null) + { + throw new IllegalArgumentException("'q' cannot be null"); + } + + this.p = new ASN1Integer(p); + this.g = new ASN1Integer(g); + this.q = new ASN1Integer(q); + + if (j != null) + { + this.j = new ASN1Integer(j); + } + else + { + this.j = null; + } + this.validationParams = validationParams; + } + + private DomainParameters(ASN1Sequence seq) + { + if (seq.size() < 3 || seq.size() > 5) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + Enumeration e = seq.getObjects(); + this.p = ASN1Integer.getInstance(e.nextElement()); + this.g = ASN1Integer.getInstance(e.nextElement()); + this.q = ASN1Integer.getInstance(e.nextElement()); + + ASN1Encodable next = getNext(e); + + if (next != null && next instanceof ASN1Integer) + { + this.j = ASN1Integer.getInstance(next); + next = getNext(e); + } + else + { + this.j = null; + } + + if (next != null) + { + this.validationParams = ValidationParams.getInstance(next.toASN1Primitive()); + } + else + { + this.validationParams = null; + } + } + + private static ASN1Encodable getNext(Enumeration e) + { + return e.hasMoreElements() ? (ASN1Encodable)e.nextElement() : null; + } + + /** + * Return the prime p defining the Galois field. + * + * @return the prime p. + */ + public BigInteger getP() + { + return this.p.getPositiveValue(); + } + + /** + * Return the generator of the multiplicative subgroup of order g. + * + * @return the generator g. + */ + public BigInteger getG() + { + return this.g.getPositiveValue(); + } + + /** + * Return q, the prime factor of p - 1 + * + * @return q value + */ + public BigInteger getQ() + { + return this.q.getPositiveValue(); + } + + /** + * Return the value that satisfies the equation p = jq+1 (if present). + * + * @return j value or null. + */ + public BigInteger getJ() + { + if (this.j == null) + { + return null; + } + + return this.j.getPositiveValue(); + } + + /** + * Return the validation parameters for this set (if present). + * + * @return validation parameters, or null if absent. + */ + public ValidationParams getValidationParams() + { + return this.validationParams; + } + + /** + * Return an ASN.1 primitive representation of this object. + * + * @return a DERSequence containing the parameter values. + */ + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.p); + v.add(this.g); + v.add(this.q); + + if (this.j != null) + { + v.add(this.j); + } + + if (this.validationParams != null) + { + v.add(this.validationParams); + } + + return new DERSequence(v); + } +} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java index fef664f..5abcca9 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java @@ -4,6 +4,10 @@ import java.util.Enumeration; import java.util.Vector; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +// BEGIN android-removed +// import org.bouncycastle.asn1.anssi.ANSSINamedCurves; +// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; +// END android-removed import org.bouncycastle.asn1.nist.NISTNamedCurves; import org.bouncycastle.asn1.sec.SECNamedCurves; // BEGIN android-removed @@ -32,19 +36,99 @@ public class ECNamedCurveTable ecP = SECNamedCurves.getByName(name); } + if (ecP == null) + { + ecP = NISTNamedCurves.getByName(name); + } + // BEGIN android-removed // if (ecP == null) // { // ecP = TeleTrusTNamedCurves.getByName(name); // } + // + // if (ecP == null) + // { + // ecP = ANSSINamedCurves.getByName(name); + // } // END android-removed - if (ecP == null) + return ecP; + } + + /** + * return the object identifier signified by the passed in name. Null + * if there is no object identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID( + String name) + { + ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name); + + if (oid == null) { - ecP = NISTNamedCurves.getByName(name); + oid = SECNamedCurves.getOID(name); } - return ecP; + if (oid == null) + { + oid = NISTNamedCurves.getOID(name); + } + + // BEGIN android-removed + // if (oid == null) + // { + // oid = TeleTrusTNamedCurves.getOID(name); + // } + // + // if (oid == null) + // { + // oid = ANSSINamedCurves.getOID(name); + // } + // END android-removed + + return oid; + } + + /** + * return a X9ECParameters object representing the passed in named + * curve. + * + * @param oid the object id of the curve requested + * @return a standard name for the curve. + */ + public static String getName( + ASN1ObjectIdentifier oid) + { + String name = NISTNamedCurves.getName(oid); + + if (name == null) + { + name = SECNamedCurves.getName(oid); + } + + // BEGIN android-removed + // if (name == null) + // { + // name = TeleTrusTNamedCurves.getName(oid); + // } + // END android-removed + + if (name == null) + { + name = X962NamedCurves.getName(oid); + } + + // BEGIN android-removed + // if (name == null) + // { + // name = ECGOST3410NamedCurves.getName(oid); + // } + // END android-removed + + return name; } /** @@ -64,15 +148,20 @@ public class ECNamedCurveTable ecP = SECNamedCurves.getByOID(oid); } + // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup + // BEGIN android-removed // if (ecP == null) // { // ecP = TeleTrusTNamedCurves.getByOID(oid); // } + // + // if (ecP == null) + // { + // ecP = ANSSINamedCurves.getByOID(oid); + // } // END android-removed - // NOTE: All the NIST curves are currently from SEC, so no point in redundant OID lookup - return ecP; } @@ -90,6 +179,7 @@ public class ECNamedCurveTable addEnumeration(v, NISTNamedCurves.getNames()); // BEGIN android-removed // addEnumeration(v, TeleTrusTNamedCurves.getNames()); + // addEnumeration(v, ANSSINamedCurves.getNames()); // END android-removed return v.elements(); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java new file mode 100644 index 0000000..34ad746 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java @@ -0,0 +1,99 @@ +package org.bouncycastle.asn1.x9; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Object; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERSequence; + +/** + * ValidationParams ::= SEQUENCE { + * seed BIT STRING, + * pgenCounter INTEGER + * } + */ +public class ValidationParams + extends ASN1Object +{ + private DERBitString seed; + private ASN1Integer pgenCounter; + + public static ValidationParams getInstance(ASN1TaggedObject obj, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + public static ValidationParams getInstance(Object obj) + { + if (obj instanceof ValidationParams) + { + return (ValidationParams)obj; + } + else if (obj != null) + { + return new ValidationParams(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ValidationParams(byte[] seed, int pgenCounter) + { + if (seed == null) + { + throw new IllegalArgumentException("'seed' cannot be null"); + } + + this.seed = new DERBitString(seed); + this.pgenCounter = new ASN1Integer(pgenCounter); + } + + public ValidationParams(DERBitString seed, ASN1Integer pgenCounter) + { + if (seed == null) + { + throw new IllegalArgumentException("'seed' cannot be null"); + } + if (pgenCounter == null) + { + throw new IllegalArgumentException("'pgenCounter' cannot be null"); + } + + this.seed = seed; + this.pgenCounter = pgenCounter; + } + + private ValidationParams(ASN1Sequence seq) + { + if (seq.size() != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + } + + this.seed = DERBitString.getInstance(seq.getObjectAt(0)); + this.pgenCounter = ASN1Integer.getInstance(seq.getObjectAt(1)); + } + + public byte[] getSeed() + { + return this.seed.getBytes(); + } + + public BigInteger getPgenCounter() + { + return this.pgenCounter.getPositiveValue(); + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(this.seed); + v.add(this.pgenCounter); + return new DERSequence(v); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java index 764017e..84574a3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java @@ -19,17 +19,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { + BigInteger n = new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16); + BigInteger h = BigInteger.valueOf(1); + ECCurve cFp192v1 = new ECCurve.Fp( new BigInteger("6277101735386680763835789423207666416083908700390324961279"), new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), - new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), + n, h); return new X9ECParameters( cFp192v1, - cFp192v1.decodePoint( + new X9ECPoint(cFp192v1, Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), - new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16), - BigInteger.valueOf(1), + n, h, Hex.decode("3045AE6FC8422f64ED579528D38120EAE12196D5")); } }; @@ -38,17 +41,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { + BigInteger n = new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16); + BigInteger h = BigInteger.valueOf(1); + ECCurve cFp192v2 = new ECCurve.Fp( new BigInteger("6277101735386680763835789423207666416083908700390324961279"), new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), - new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16)); + new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16), + n, h); return new X9ECParameters( cFp192v2, - cFp192v2.decodePoint( + new X9ECPoint(cFp192v2, Hex.decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")), - new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16), - BigInteger.valueOf(1), + n, h, Hex.decode("31a92ee2029fd10d901b113e990710f0d21ac6b6")); } }; @@ -57,17 +63,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { + BigInteger n = new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16); + BigInteger h = BigInteger.valueOf(1); + ECCurve cFp192v3 = new ECCurve.Fp( new BigInteger("6277101735386680763835789423207666416083908700390324961279"), new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), - new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16)); + new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16), + n, h); return new X9ECParameters( cFp192v3, - cFp192v3.decodePoint( + new X9ECPoint(cFp192v3, Hex.decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")), - new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16), - BigInteger.valueOf(1), + n, h, Hex.decode("c469684435deb378c4b65ca9591e2a5763059a2e")); } }; @@ -76,17 +85,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { + BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16); + BigInteger h = BigInteger.valueOf(1); + ECCurve cFp239v1 = new ECCurve.Fp( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), + n, h); return new X9ECParameters( cFp239v1, - cFp239v1.decodePoint( + new X9ECPoint(cFp239v1, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), - new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16), - BigInteger.valueOf(1), + n, h, Hex.decode("e43bb460f0b80cc0c0b075798e948060f8321b7d")); } }; @@ -95,17 +107,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { + BigInteger n = new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16); + BigInteger h = BigInteger.valueOf(1); + ECCurve cFp239v2 = new ECCurve.Fp( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), - new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16)); + new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16), + n, h); return new X9ECParameters( cFp239v2, - cFp239v2.decodePoint( + new X9ECPoint(cFp239v2, Hex.decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")), - new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16), - BigInteger.valueOf(1), + n, h, Hex.decode("e8b4011604095303ca3b8099982be09fcb9ae616")); } }; @@ -114,17 +129,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { + BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16); + BigInteger h = BigInteger.valueOf(1); + ECCurve cFp239v3 = new ECCurve.Fp( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), - new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16)); + new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16), + n, h); return new X9ECParameters( cFp239v3, - cFp239v3.decodePoint( + new X9ECPoint(cFp239v3, Hex.decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")), - new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16), - BigInteger.valueOf(1), + n, h, Hex.decode("7d7374168ffe3471b60a857686a19475d3bfa2ff")); } }; @@ -133,17 +151,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { + BigInteger n = new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16); + BigInteger h = BigInteger.valueOf(1); + ECCurve cFp256v1 = new ECCurve.Fp( new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"), new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16), - new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)); + new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16), + n, h); return new X9ECParameters( cFp256v1, - cFp256v1.decodePoint( + new X9ECPoint(cFp256v1, Hex.decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")), - new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16), - BigInteger.valueOf(1), + n, h, Hex.decode("c49d360886e704936a6678e1139d26b7819f7e90")); } }; @@ -167,7 +188,7 @@ public class X962NamedCurves return new X9ECParameters( c2m163v1, - c2m163v1.decodePoint( + new X9ECPoint(c2m163v1, Hex.decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")), c2m163v1n, c2m163v1h, Hex.decode("D2C0FB15760860DEF1EEF4D696E6768756151754")); @@ -190,7 +211,7 @@ public class X962NamedCurves return new X9ECParameters( c2m163v2, - c2m163v2.decodePoint( + new X9ECPoint(c2m163v2, Hex.decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")), c2m163v2n, c2m163v2h, null); @@ -213,7 +234,7 @@ public class X962NamedCurves return new X9ECParameters( c2m163v3, - c2m163v3.decodePoint( + new X9ECPoint(c2m163v3, Hex.decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")), c2m163v3n, c2m163v3h, null); @@ -236,7 +257,7 @@ public class X962NamedCurves return new X9ECParameters( c2m176w1, - c2m176w1.decodePoint( + new X9ECPoint(c2m176w1, Hex.decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")), c2m176w1n, c2m176w1h, null); @@ -259,7 +280,7 @@ public class X962NamedCurves return new X9ECParameters( c2m191v1, - c2m191v1.decodePoint( + new X9ECPoint(c2m191v1, Hex.decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")), c2m191v1n, c2m191v1h, Hex.decode("4E13CA542744D696E67687561517552F279A8C84")); @@ -282,7 +303,7 @@ public class X962NamedCurves return new X9ECParameters( c2m191v2, - c2m191v2.decodePoint( + new X9ECPoint(c2m191v2, Hex.decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")), c2m191v2n, c2m191v2h, null); @@ -305,7 +326,7 @@ public class X962NamedCurves return new X9ECParameters( c2m191v3, - c2m191v3.decodePoint( + new X9ECPoint(c2m191v3, Hex.decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")), c2m191v3n, c2m191v3h, null); @@ -328,7 +349,7 @@ public class X962NamedCurves return new X9ECParameters( c2m208w1, - c2m208w1.decodePoint( + new X9ECPoint(c2m208w1, Hex.decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")), c2m208w1n, c2m208w1h, null); @@ -351,7 +372,7 @@ public class X962NamedCurves return new X9ECParameters( c2m239v1, - c2m239v1.decodePoint( + new X9ECPoint(c2m239v1, Hex.decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")), c2m239v1n, c2m239v1h, null); @@ -374,7 +395,7 @@ public class X962NamedCurves return new X9ECParameters( c2m239v2, - c2m239v2.decodePoint( + new X9ECPoint(c2m239v2, Hex.decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")), c2m239v2n, c2m239v2h, null); @@ -397,7 +418,7 @@ public class X962NamedCurves return new X9ECParameters( c2m239v3, - c2m239v3.decodePoint( + new X9ECPoint(c2m239v3, Hex.decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")), c2m239v3n, c2m239v3h, null); @@ -420,7 +441,7 @@ public class X962NamedCurves return new X9ECParameters( c2m272w1, - c2m272w1.decodePoint( + new X9ECPoint(c2m272w1, Hex.decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")), c2m272w1n, c2m272w1h, null); @@ -443,7 +464,7 @@ public class X962NamedCurves return new X9ECParameters( c2m304w1, - c2m304w1.decodePoint( + new X9ECPoint(c2m304w1, Hex.decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")), c2m304w1n, c2m304w1h, null); @@ -466,7 +487,7 @@ public class X962NamedCurves return new X9ECParameters( c2m359v1, - c2m359v1.decodePoint( + new X9ECPoint(c2m359v1, Hex.decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")), c2m359v1n, c2m359v1h, null); @@ -489,7 +510,7 @@ public class X962NamedCurves return new X9ECParameters( c2m368w1, - c2m368w1.decodePoint( + new X9ECPoint(c2m368w1, Hex.decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")), c2m368w1n, c2m368w1h, null); @@ -512,7 +533,7 @@ public class X962NamedCurves return new X9ECParameters( c2m431r1, - c2m431r1.decodePoint( + new X9ECPoint(c2m431r1, Hex.decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")), c2m431r1n, c2m431r1h, null); @@ -525,7 +546,7 @@ public class X962NamedCurves static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) { - objIds.put(name, oid); + objIds.put(name.toLowerCase(), oid); names.put(oid, name); curves.put(oid, holder); } @@ -560,14 +581,8 @@ public class X962NamedCurves public static X9ECParameters getByName( String name) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); - - if (oid != null) - { - return getByOID(oid); - } - - return null; + ASN1ObjectIdentifier oid = getOID(name); + return oid == null ? null : getByOID(oid); } /** @@ -580,13 +595,7 @@ public class X962NamedCurves ASN1ObjectIdentifier oid) { X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid); - - if (holder != null) - { - return holder.getParameters(); - } - - return null; + return holder == null ? null : holder.getParameters(); } /** @@ -616,6 +625,6 @@ public class X962NamedCurves */ public static Enumeration getNames() { - return objIds.keys(); + return names.elements(); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java index 1c395d2..a06aa85 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java @@ -1,5 +1,7 @@ package org.bouncycastle.asn1.x9; +import java.io.IOException; + import org.bouncycastle.asn1.ASN1Choice; import org.bouncycastle.asn1.ASN1Null; import org.bouncycastle.asn1.ASN1Object; @@ -7,6 +9,9 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; +/** + * The Parameters ASN.1 CHOICE from X9.62. + */ public class X962Parameters extends ASN1Object implements ASN1Choice @@ -25,7 +30,19 @@ public class X962Parameters { return new X962Parameters((ASN1Primitive)obj); } - + + if (obj instanceof byte[]) + { + try + { + return new X962Parameters(ASN1Primitive.fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to parse encoded data: " + e.getMessage()); + } + } + throw new IllegalArgumentException("unknown object in getInstance()"); } @@ -48,6 +65,15 @@ public class X962Parameters this.params = namedCurve; } + public X962Parameters( + ASN1Null obj) + { + this.params = obj; + } + + /** + * @deprecated use getInstance() + */ public X962Parameters( ASN1Primitive obj) { @@ -74,7 +100,7 @@ public class X962Parameters *
      * Parameters ::= CHOICE {
      *    ecParameters ECParameters,
-     *    namedCurve   CURVES.&id({CurveNames}),
+     *    namedCurve   CURVES.&id({CurveNames}),
      *    implicitlyCA NULL
      * }
      * 
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java index f233657..f1bac2b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java @@ -11,6 +11,7 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.math.ec.ECAlgorithms; import org.bouncycastle.math.ec.ECCurve; /** @@ -46,6 +47,8 @@ public class X9Curve X9FieldID fieldID, ASN1Sequence seq) { + // TODO Is it possible to get the order(n) and cofactor(h) too? + fieldIdentifier = fieldID.getIdentifier(); if (fieldIdentifier.equals(prime_field)) { @@ -86,7 +89,6 @@ public class X9Curve } X9FieldElement x9A = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(0)); X9FieldElement x9B = new X9FieldElement(m, k1, k2, k3, (ASN1OctetString)seq.getObjectAt(1)); - // TODO Is it possible to get the order (n) and cofactor(h) too? curve = new ECCurve.F2m(m, k1, k2, k3, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger()); } else @@ -102,11 +104,11 @@ public class X9Curve private void setFieldIdentifier() { - if (curve instanceof ECCurve.Fp) + if (ECAlgorithms.isFpCurve(curve)) { fieldIdentifier = prime_field; } - else if (curve instanceof ECCurve.F2m) + else if (ECAlgorithms.isF2mCurve(curve)) { fieldIdentifier = characteristic_two_field; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java index 60f9008..8516365 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java @@ -9,8 +9,10 @@ import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.math.ec.ECAlgorithms; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.field.PolynomialExtensionField; /** * ASN.1 def for Elliptic-Curve ECParameters structure. See @@ -24,7 +26,7 @@ public class X9ECParameters private X9FieldID fieldID; private ECCurve curve; - private ECPoint g; + private X9ECPoint g; private BigInteger n; private BigInteger h; private byte[] seed; @@ -47,11 +49,11 @@ public class X9ECParameters if (p instanceof X9ECPoint) { - this.g = ((X9ECPoint)p).getPoint(); + this.g = ((X9ECPoint)p); } else { - this.g = new X9ECPoint(curve, (ASN1OctetString)p).getPoint(); + this.g = new X9ECPoint(curve, (ASN1OctetString)p); } this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue(); @@ -83,7 +85,16 @@ public class X9ECParameters ECPoint g, BigInteger n) { - this(curve, g, n, ONE, null); + this(curve, g, n, null, null); + } + + public X9ECParameters( + ECCurve curve, + X9ECPoint g, + BigInteger n, + BigInteger h) + { + this(curve, g, n, h, null); } public X9ECParameters( @@ -101,25 +112,47 @@ public class X9ECParameters BigInteger n, BigInteger h, byte[] seed) + { + this(curve, new X9ECPoint(g), n, h, seed); + } + + public X9ECParameters( + ECCurve curve, + X9ECPoint g, + BigInteger n, + BigInteger h, + byte[] seed) { this.curve = curve; - this.g = g.normalize(); + this.g = g; this.n = n; this.h = h; this.seed = seed; - if (curve instanceof ECCurve.Fp) + if (ECAlgorithms.isFpCurve(curve)) { - this.fieldID = new X9FieldID(((ECCurve.Fp)curve).getQ()); + this.fieldID = new X9FieldID(curve.getField().getCharacteristic()); } - else + else if (ECAlgorithms.isF2mCurve(curve)) { - if (curve instanceof ECCurve.F2m) + PolynomialExtensionField field = (PolynomialExtensionField)curve.getField(); + int[] exponents = field.getMinimalPolynomial().getExponentsPresent(); + if (exponents.length == 3) { - ECCurve.F2m curveF2m = (ECCurve.F2m)curve; - this.fieldID = new X9FieldID(curveF2m.getM(), curveF2m.getK1(), - curveF2m.getK2(), curveF2m.getK3()); + this.fieldID = new X9FieldID(exponents[2], exponents[1]); } + else if (exponents.length == 5) + { + this.fieldID = new X9FieldID(exponents[4], exponents[1], exponents[2], exponents[3]); + } + else + { + throw new IllegalArgumentException("Only trinomial and pentomial curves are supported"); + } + } + else + { + throw new IllegalArgumentException("'curve' is of an unsupported type"); } } @@ -130,7 +163,7 @@ public class X9ECParameters public ECPoint getG() { - return g; + return g.getPoint(); } public BigInteger getN() @@ -140,11 +173,6 @@ public class X9ECParameters public BigInteger getH() { - if (h == null) - { - return ONE; // TODO - this should be calculated, it will cause issues with custom curves. - } - return h; } @@ -153,6 +181,36 @@ public class X9ECParameters return seed; } + /** + * Return the ASN.1 entry representing the Curve. + * + * @return the X9Curve for the curve in these parameters. + */ + public X9Curve getCurveEntry() + { + return new X9Curve(curve, seed); + } + + /** + * Return the ASN.1 entry representing the FieldID. + * + * @return the X9FieldID for the FieldID in these parameters. + */ + public X9FieldID getFieldIDEntry() + { + return fieldID; + } + + /** + * Return the ASN.1 entry representing the base point G. + * + * @return the X9ECPoint for the base point in these parameters. + */ + public X9ECPoint getBaseEntry() + { + return g; + } + /** * Produce an object suitable for an ASN1OutputStream. *
@@ -170,10 +228,10 @@ public class X9ECParameters
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
-        v.add(new ASN1Integer(1));
+        v.add(new ASN1Integer(ONE));
         v.add(fieldID);
         v.add(new X9Curve(curve, seed));
-        v.add(new X9ECPoint(g));
+        v.add(g);
         v.add(new ASN1Integer(n));
 
         if (h != null)
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java
index 47361f8..96130c6 100644
--- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java
@@ -4,7 +4,7 @@ public abstract class X9ECParametersHolder
 {
     private X9ECParameters params;
 
-    public X9ECParameters getParameters()
+    public synchronized X9ECParameters getParameters()
     {
         if (params == null)
         {
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
index cbb9116..57b0fda 100644
--- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
@@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1Primitive;
 import org.bouncycastle.asn1.DEROctetString;
 import org.bouncycastle.math.ec.ECCurve;
 import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Arrays;
 
 /**
  * class for describing an ECPoint as a DER object.
@@ -13,26 +14,61 @@ import org.bouncycastle.math.ec.ECPoint;
 public class X9ECPoint
     extends ASN1Object
 {
-    ECPoint p;
+    private final ASN1OctetString encoding;
+
+    private ECCurve c;
+    private ECPoint p;
 
     public X9ECPoint(
         ECPoint p)
+    {
+        this(p, false);
+    }
+
+    public X9ECPoint(
+        ECPoint p,
+        boolean compressed)
     {
         this.p = p.normalize();
+        this.encoding = new DEROctetString(p.getEncoded(compressed));
+    }
+
+    public X9ECPoint(
+        ECCurve          c,
+        byte[]           encoding)
+    {
+        this.c = c;
+        this.encoding = new DEROctetString(Arrays.clone(encoding));
     }
 
     public X9ECPoint(
         ECCurve          c,
         ASN1OctetString  s)
     {
-        this.p = c.decodePoint(s.getOctets());
+        this(c, s.getOctets());
+    }
+
+    public byte[] getPointEncoding()
+    {
+        return Arrays.clone(encoding.getOctets());
     }
 
     public ECPoint getPoint()
     {
+        if (p == null)
+        {
+            p = c.decodePoint(encoding.getOctets()).normalize();
+        }
+
         return p;
     }
 
+    public boolean isPointCompressed()
+    {
+        byte[] octets = encoding.getOctets();
+        return octets != null && octets.length > 0 && (octets[0] == 2 || octets[0] == 3);
+    }
+
     /**
      * Produce an object suitable for an ASN1OutputStream.
      * 
@@ -43,6 +79,6 @@ public class X9ECPoint
      */
     public ASN1Primitive toASN1Primitive()
     {
-        return new DEROctetString(p.getEncoded());
+        return encoding;
     }
 }
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
index a210352..cb74234 100644
--- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
@@ -32,6 +32,20 @@ public class X9FieldID
         this.parameters = new ASN1Integer(primeP);
     }
 
+    /**
+     * Constructor for elliptic curves over binary fields
+     * F2m.
+     * @param m  The exponent m of
+     * F2m.
+     * @param k1 The integer k1 where xm +
+     * xk1 + 1
+     * represents the reduction polynomial f(z).
+     */
+    public X9FieldID(int m, int k1)
+    {
+        this(m, k1, 0, 0);
+    }
+
     /**
      * Constructor for elliptic curves over binary fields
      * F2m.
@@ -55,11 +69,21 @@ public class X9FieldID
         
         if (k2 == 0) 
         {
+            if (k3 != 0)
+            {
+                throw new IllegalArgumentException("inconsistent k values");
+            }
+
             fieldIdParams.add(tpBasis);
             fieldIdParams.add(new ASN1Integer(k1));
         } 
         else 
         {
+            if (k2 <= k1 || k3 <= k2)
+            {
+                throw new IllegalArgumentException("inconsistent k values");
+            }
+
             fieldIdParams.add(ppBasis);
             ASN1EncodableVector pentanomialParams = new ASN1EncodableVector();
             pentanomialParams.add(new ASN1Integer(k1));
diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
index eabf90e..1317b4a 100644
--- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
+++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
@@ -63,78 +63,78 @@ public interface X9ObjectIdentifiers
     /**
      * Named curves base
      * 

- * OID: 1.2.840.10045.1 + * OID: 1.2.840.10045.3 */ static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3"); /** * Two Curves *

- * OID: 1.2.840.10045.1.0 + * OID: 1.2.840.10045.3.0 */ static final ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0"); - /** Two Curve c2pnb163v1, OID: 1.2.840.10045.1.0.1 */ + /** Two Curve c2pnb163v1, OID: 1.2.840.10045.3.0.1 */ static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1"); - /** Two Curve c2pnb163v2, OID: 1.2.840.10045.1.0.2 */ + /** Two Curve c2pnb163v2, OID: 1.2.840.10045.3.0.2 */ static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2"); - /** Two Curve c2pnb163v3, OID: 1.2.840.10045.1.0.3 */ + /** Two Curve c2pnb163v3, OID: 1.2.840.10045.3.0.3 */ static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3"); - /** Two Curve c2pnb176w1, OID: 1.2.840.10045.1.0.4 */ + /** Two Curve c2pnb176w1, OID: 1.2.840.10045.3.0.4 */ static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4"); - /** Two Curve c2tnb191v1, OID: 1.2.840.10045.1.0.5 */ + /** Two Curve c2tnb191v1, OID: 1.2.840.10045.3.0.5 */ static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5"); - /** Two Curve c2tnb191v2, OID: 1.2.840.10045.1.0.6 */ + /** Two Curve c2tnb191v2, OID: 1.2.840.10045.3.0.6 */ static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6"); - /** Two Curve c2tnb191v3, OID: 1.2.840.10045.1.0.7 */ + /** Two Curve c2tnb191v3, OID: 1.2.840.10045.3.0.7 */ static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7"); - /** Two Curve c2onb191v4, OID: 1.2.840.10045.1.0.8 */ + /** Two Curve c2onb191v4, OID: 1.2.840.10045.3.0.8 */ static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8"); - /** Two Curve c2onb191v5, OID: 1.2.840.10045.1.0.9 */ + /** Two Curve c2onb191v5, OID: 1.2.840.10045.3.0.9 */ static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9"); - /** Two Curve c2pnb208w1, OID: 1.2.840.10045.1.0.10 */ + /** Two Curve c2pnb208w1, OID: 1.2.840.10045.3.0.10 */ static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10"); - /** Two Curve c2tnb239v1, OID: 1.2.840.10045.1.0.11 */ + /** Two Curve c2tnb239v1, OID: 1.2.840.10045.3.0.11 */ static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11"); - /** Two Curve c2tnb239v2, OID: 1.2.840.10045.1.0.12 */ + /** Two Curve c2tnb239v2, OID: 1.2.840.10045.3.0.12 */ static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12"); - /** Two Curve c2tnb239v3, OID: 1.2.840.10045.1.0.13 */ + /** Two Curve c2tnb239v3, OID: 1.2.840.10045.3.0.13 */ static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13"); - /** Two Curve c2onb239v4, OID: 1.2.840.10045.1.0.14 */ + /** Two Curve c2onb239v4, OID: 1.2.840.10045.3.0.14 */ static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14"); - /** Two Curve c2onb239v5, OID: 1.2.840.10045.1.0.15 */ + /** Two Curve c2onb239v5, OID: 1.2.840.10045.3.0.15 */ static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15"); - /** Two Curve c2pnb272w1, OID: 1.2.840.10045.1.0.16 */ + /** Two Curve c2pnb272w1, OID: 1.2.840.10045.3.0.16 */ static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16"); - /** Two Curve c2pnb304w1, OID: 1.2.840.10045.1.0.17 */ + /** Two Curve c2pnb304w1, OID: 1.2.840.10045.3.0.17 */ static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17"); - /** Two Curve c2tnb359v1, OID: 1.2.840.10045.1.0.18 */ + /** Two Curve c2tnb359v1, OID: 1.2.840.10045.3.0.18 */ static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18"); - /** Two Curve c2pnb368w1, OID: 1.2.840.10045.1.0.19 */ + /** Two Curve c2pnb368w1, OID: 1.2.840.10045.3.0.19 */ static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19"); - /** Two Curve c2tnb431r1, OID: 1.2.840.10045.1.0.20 */ + /** Two Curve c2tnb431r1, OID: 1.2.840.10045.3.0.20 */ static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20"); /** * Prime Curves *

- * OID: 1.2.840.10045.1.1 + * OID: 1.2.840.10045.3.1 */ static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1"); - /** Prime Curve prime192v1, OID: 1.2.840.10045.1.1.1 */ + /** Prime Curve prime192v1, OID: 1.2.840.10045.3.1.1 */ static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1"); - /** Prime Curve prime192v2, OID: 1.2.840.10045.1.1.2 */ + /** Prime Curve prime192v2, OID: 1.2.840.10045.3.1.2 */ static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2"); - /** Prime Curve prime192v3, OID: 1.2.840.10045.1.1.3 */ + /** Prime Curve prime192v3, OID: 1.2.840.10045.3.1.3 */ static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3"); - /** Prime Curve prime239v1, OID: 1.2.840.10045.1.1.4 */ + /** Prime Curve prime239v1, OID: 1.2.840.10045.3.1.4 */ static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4"); - /** Prime Curve prime239v2, OID: 1.2.840.10045.1.1.5 */ + /** Prime Curve prime239v2, OID: 1.2.840.10045.3.1.5 */ static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5"); - /** Prime Curve prime239v3, OID: 1.2.840.10045.1.1.6 */ + /** Prime Curve prime239v3, OID: 1.2.840.10045.3.1.6 */ static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6"); - /** Prime Curve prime256v1, OID: 1.2.840.10045.1.1.7 */ + /** Prime Curve prime256v1, OID: 1.2.840.10045.3.1.7 */ static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7"); /** @@ -204,4 +204,21 @@ public interface X9ObjectIdentifiers static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7"); /** X9.42 MQV1 OID: 1.2.840.10046.3.8 */ static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8"); + + /** + * X9.44 + *

+     *    x9-44 OID ::= {
+     *      iso(1) identified-organization(3) tc68(133) country(16) x9(840)
+     *      x9Standards(9) x9-44(44)
+     *   }
+     * 
+ */ + + ASN1ObjectIdentifier x9_44 = new ASN1ObjectIdentifier("1.3.133.16.840.9.44"); + + ASN1ObjectIdentifier x9_44_components = x9_44.branch("1"); + + ASN1ObjectIdentifier id_kdf_kdf2 = x9_44_components.branch("1"); + ASN1ObjectIdentifier id_kdf_kdf3 = x9_44_components.branch("2"); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java index dd056ac..8ab2cdc 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java @@ -48,13 +48,13 @@ public class BufferedBlockCipher pgpCFB = (idx > 0 && name.startsWith("PGP", idx)); - if (pgpCFB) + if (pgpCFB || cipher instanceof StreamCipher) { partialBlockOkay = true; } else { - partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("GCFB", idx) ||name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx))); + partialBlockOkay = (idx > 0 && (name.startsWith("OpenPGP", idx))); } } @@ -115,7 +115,14 @@ public class BufferedBlockCipher if (pgpCFB) { - leftOver = total % buf.length - (cipher.getBlockSize() + 2); + if (forEncryption) + { + leftOver = total % buf.length - (cipher.getBlockSize() + 2); + } + else + { + leftOver = total % buf.length; + } } else { @@ -141,7 +148,7 @@ public class BufferedBlockCipher } /** - * process a single byte, producing an output block if neccessary. + * process a single byte, producing an output block if necessary. * * @param in the input byte. * @param out the space for any output that might be produced. diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/SkippingCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/SkippingCipher.java new file mode 100644 index 0000000..f8cc648 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/SkippingCipher.java @@ -0,0 +1,31 @@ +package org.bouncycastle.crypto; + +/** + * Ciphers producing a key stream which can be reset to particular points in the stream implement this. + */ +public interface SkippingCipher +{ + /** + * Skip numberOfBytes forwards, or backwards. + * + * @param numberOfBytes the number of bytes to skip (positive forward, negative backwards). + * @return the number of bytes actually skipped. + * @throws java.lang.IllegalArgumentException if numberOfBytes is an invalid value. + */ + long skip(long numberOfBytes); + + /** + * Reset the cipher and then skip forward to a given position. + * + * @param position the number of bytes in to set the cipher state to. + * @return the byte position moved to. + */ + long seekTo(long position); + + /** + * Return the current "position" of the cipher + * + * @return the current byte position. + */ + long getPosition(); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/SkippingStreamCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/SkippingStreamCipher.java new file mode 100644 index 0000000..a707a81 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/SkippingStreamCipher.java @@ -0,0 +1,9 @@ +package org.bouncycastle.crypto; + +/** + * General interface for a stream cipher that supports skipping. + */ +public interface SkippingStreamCipher + extends StreamCipher, SkippingCipher +{ +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java index 8fdd232..09aadfb 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java @@ -1,108 +1,58 @@ package org.bouncycastle.crypto; /** - * a wrapper for block ciphers with a single byte block size, so that they - * can be treated like stream ciphers. + * A parent class for block cipher modes that do not require block aligned data to be processed, but can function in + * a streaming mode. */ -public class StreamBlockCipher - implements StreamCipher +public abstract class StreamBlockCipher + implements BlockCipher, StreamCipher { - private BlockCipher cipher; + private final BlockCipher cipher; - private byte[] oneByte = new byte[1]; - - /** - * basic constructor. - * - * @param cipher the block cipher to be wrapped. - * @exception IllegalArgumentException if the cipher has a block size other than - * one. - */ - public StreamBlockCipher( - BlockCipher cipher) + protected StreamBlockCipher(BlockCipher cipher) { - if (cipher.getBlockSize() != 1) - { - throw new IllegalArgumentException("block cipher block size != 1."); - } - this.cipher = cipher; } /** - * initialise the underlying cipher. + * return the underlying block cipher that we are wrapping. * - * @param forEncryption true if we are setting up for encryption, false otherwise. - * @param params the necessary parameters for the underlying cipher to be initialised. + * @return the underlying block cipher that we are wrapping. */ - public void init( - boolean forEncryption, - CipherParameters params) + public BlockCipher getUnderlyingCipher() { - cipher.init(forEncryption, params); + return cipher; } - /** - * return the name of the algorithm we are wrapping. - * - * @return the name of the algorithm we are wrapping. - */ - public String getAlgorithmName() + public final byte returnByte(byte in) { - return cipher.getAlgorithmName(); + return calculateByte(in); } - /** - * encrypt/decrypt a single byte returning the result. - * - * @param in the byte to be processed. - * @return the result of processing the input byte. - */ - public byte returnByte( - byte in) - { - oneByte[0] = in; - - cipher.processBlock(oneByte, 0, oneByte, 0); - - return oneByte[0]; - } - - /** - * process a block of bytes from in putting the result into out. - * - * @param in the input byte array. - * @param inOff the offset into the in array where the data to be processed starts. - * @param len the number of bytes to be processed. - * @param out the output buffer the processed bytes go into. - * @param outOff the offset into the output byte array the processed data stars at. - * @exception DataLengthException if the output buffer is too small. - */ - public void processBytes( - byte[] in, - int inOff, - int len, - byte[] out, - int outOff) + public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException { if (outOff + len > out.length) { - throw new DataLengthException("output buffer too small in processBytes()"); + throw new DataLengthException("output buffer too short"); } - for (int i = 0; i != len; i++) + if (inOff + len > in.length) { - cipher.processBlock(in, inOff + i, out, outOff + i); + throw new DataLengthException("input buffer too small"); } - } - /** - * reset the underlying cipher. This leaves it in the same state - * it was at after the last init (if there was one). - */ - public void reset() - { - cipher.reset(); + int inStart = inOff; + int inEnd = inOff + len; + int outStart = outOff; + + while (inStart < inEnd) + { + out[outStart++] = calculateByte(in[inStart++]); + } + + return len; } -} + + protected abstract byte calculateByte(byte b); +} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java index 2a55d4f..c1255e9 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java @@ -40,9 +40,10 @@ public interface StreamCipher * @param len the number of bytes to be processed. * @param out the output buffer the processed bytes go into. * @param outOff the offset into the output byte array the processed data starts at. + * @return the number of bytes produced - should always be len. * @exception DataLengthException if the output buffer is too small. */ - public void processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) + public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException; /** diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java new file mode 100644 index 0000000..d79fece --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java @@ -0,0 +1,17 @@ +package org.bouncycastle.crypto.digests; + +/** + * Encodable digests allow you to download an encoded copy of their internal state. This is useful for the situation where + * you need to generate a signature on an external device and it allows for "sign with last round", so a copy of the + * internal state of the digest, plus the last few blocks of the message are all that needs to be sent, rather than the + * entire message. + */ +public interface EncodableDigest +{ + /** + * Return an encoded byte array for the digest's internal state + * + * @return an encoding of the digests internal state. + */ + byte[] getEncodedState(); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java index 15f3ebb..011e97c 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java @@ -2,6 +2,7 @@ package org.bouncycastle.crypto.digests; import org.bouncycastle.crypto.ExtendedDigest; import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; /** * base implementation of MD4 family style digest as outlined in @@ -11,8 +12,9 @@ public abstract class GeneralDigest implements ExtendedDigest, Memoable { private static final int BYTE_LENGTH = 64; - private byte[] xBuf; - private int xBufOff; + + private final byte[] xBuf = new byte[4]; + private int xBufOff; private long byteCount; @@ -21,7 +23,6 @@ public abstract class GeneralDigest */ protected GeneralDigest() { - xBuf = new byte[4]; xBufOff = 0; } @@ -32,11 +33,16 @@ public abstract class GeneralDigest */ protected GeneralDigest(GeneralDigest t) { - xBuf = new byte[t.xBuf.length]; - copyIn(t); } + protected GeneralDigest(byte[] encodedState) + { + System.arraycopy(encodedState, 0, xBuf, 0, xBuf.length); + xBufOff = Pack.bigEndianToInt(encodedState, 4); + byteCount = Pack.bigEndianToLong(encodedState, 8); + } + protected void copyIn(GeneralDigest t) { System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length); @@ -64,39 +70,44 @@ public abstract class GeneralDigest int inOff, int len) { + len = Math.max(0, len); + // // fill the current word // - while ((xBufOff != 0) && (len > 0)) + int i = 0; + if (xBufOff != 0) { - update(in[inOff]); - - inOff++; - len--; + while (i < len) + { + xBuf[xBufOff++] = in[inOff + i++]; + if (xBufOff == 4) + { + processWord(xBuf, 0); + xBufOff = 0; + break; + } + } } // // process whole words. // - while (len > xBuf.length) + int limit = ((len - i) & ~3) + i; + for (; i < limit; i += 4) { - processWord(in, inOff); - - inOff += xBuf.length; - len -= xBuf.length; - byteCount += xBuf.length; + processWord(in, inOff + i); } // // load in the remainder. // - while (len > 0) + while (i < len) { - update(in[inOff]); - - inOff++; - len--; + xBuf[xBufOff++] = in[inOff + i++]; } + + byteCount += len; } public void finish() @@ -129,6 +140,13 @@ public abstract class GeneralDigest } } + protected void populateState(byte[] state) + { + System.arraycopy(xBuf, 0, state, 0, xBufOff); + Pack.intToBigEndian(xBufOff, state, 4); + Pack.longToBigEndian(byteCount, state, 8); + } + public int getByteLength() { return BYTE_LENGTH; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java index 5c79e4e..8ea474b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java @@ -1,18 +1,18 @@ package org.bouncycastle.crypto.digests; import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; /** * Base class for SHA-384 and SHA-512. */ public abstract class LongDigest - implements ExtendedDigest, Memoable + implements ExtendedDigest, Memoable, EncodableDigest { private static final int BYTE_LENGTH = 128; - - private byte[] xBuf; + + private byte[] xBuf = new byte[8]; private int xBufOff; private long byteCount1; @@ -28,7 +28,6 @@ public abstract class LongDigest */ protected LongDigest() { - xBuf = new byte[8]; xBufOff = 0; reset(); @@ -41,8 +40,6 @@ public abstract class LongDigest */ protected LongDigest(LongDigest t) { - xBuf = new byte[t.xBuf.length]; - copyIn(t); } @@ -67,6 +64,56 @@ public abstract class LongDigest wOff = t.wOff; } + protected void populateState(byte[] state) + { + System.arraycopy(xBuf, 0, state, 0, xBufOff); + Pack.intToBigEndian(xBufOff, state, 8); + Pack.longToBigEndian(byteCount1, state, 12); + Pack.longToBigEndian(byteCount2, state, 20); + Pack.longToBigEndian(H1, state, 28); + Pack.longToBigEndian(H2, state, 36); + Pack.longToBigEndian(H3, state, 44); + Pack.longToBigEndian(H4, state, 52); + Pack.longToBigEndian(H5, state, 60); + Pack.longToBigEndian(H6, state, 68); + Pack.longToBigEndian(H7, state, 76); + Pack.longToBigEndian(H8, state, 84); + + Pack.intToBigEndian(wOff, state, 92); + for (int i = 0; i < wOff; i++) + { + Pack.longToBigEndian(W[i], state, 96 + (i * 8)); + } + } + + protected void restoreState(byte[] encodedState) + { + xBufOff = Pack.bigEndianToInt(encodedState, 8); + System.arraycopy(encodedState, 0, xBuf, 0, xBufOff); + byteCount1 = Pack.bigEndianToLong(encodedState, 12); + byteCount2 = Pack.bigEndianToLong(encodedState, 20); + + H1 = Pack.bigEndianToLong(encodedState, 28); + H2 = Pack.bigEndianToLong(encodedState, 36); + H3 = Pack.bigEndianToLong(encodedState, 44); + H4 = Pack.bigEndianToLong(encodedState, 52); + H5 = Pack.bigEndianToLong(encodedState, 60); + H6 = Pack.bigEndianToLong(encodedState, 68); + H7 = Pack.bigEndianToLong(encodedState, 76); + H8 = Pack.bigEndianToLong(encodedState, 84); + + wOff = Pack.bigEndianToInt(encodedState, 92); + for (int i = 0; i < wOff; i++) + { + W[i] = Pack.bigEndianToLong(encodedState, 96 + (i * 8)); + } + } + + protected int getEncodedStateSize() + { + return 96 + (wOff * 8); + } + public void update( byte in) { @@ -165,7 +212,7 @@ public abstract class LongDigest { return BYTE_LENGTH; } - + protected void processWord( byte[] in, int inOff) @@ -228,7 +275,7 @@ public abstract class LongDigest long g = H7; long h = H8; - int t = 0; + int t = 0; for(int i = 0; i < 10; i ++) { // t = 8 * i @@ -271,7 +318,7 @@ public abstract class LongDigest e += a; a += Sum0(b) + Maj(b, c, d); } - + H1 += a; H2 += b; H3 += c; @@ -358,4 +405,5 @@ public abstract class LongDigest 0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL, 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L }; + } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java index 21b1024..450dda4 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java @@ -1,7 +1,7 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; /** * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349. @@ -11,6 +11,7 @@ import org.bouncycastle.util.Memoable; */ public class SHA1Digest extends GeneralDigest + implements EncodableDigest { private static final int DIGEST_LENGTH = 20; @@ -38,6 +39,23 @@ public class SHA1Digest copyIn(t); } + public SHA1Digest(byte[] encodedState) + { + super(encodedState); + + H1 = Pack.bigEndianToInt(encodedState, 16); + H2 = Pack.bigEndianToInt(encodedState, 20); + H3 = Pack.bigEndianToInt(encodedState, 24); + H4 = Pack.bigEndianToInt(encodedState, 28); + H5 = Pack.bigEndianToInt(encodedState, 32); + + xOff = Pack.bigEndianToInt(encodedState, 36); + for (int i = 0; i != xOff; i++) + { + X[i] = Pack.bigEndianToInt(encodedState, 40 + (i * 4)); + } + } + private void copyIn(SHA1Digest t) { H1 = t.H1; @@ -302,6 +320,27 @@ public class SHA1Digest super.copyIn(d); copyIn(d); } + + public byte[] getEncodedState() + { + byte[] state = new byte[40 + xOff * 4]; + + super.populateState(state); + + Pack.intToBigEndian(H1, state, 16); + Pack.intToBigEndian(H2, state, 20); + Pack.intToBigEndian(H3, state, 24); + Pack.intToBigEndian(H4, state, 28); + Pack.intToBigEndian(H5, state, 32); + Pack.intToBigEndian(xOff, state, 36); + + for (int i = 0; i != xOff; i++) + { + Pack.intToBigEndian(X[i], state, 40 + (i * 4)); + } + + return state; + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java index d430321..4f2b284 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA224Digest.java @@ -1,8 +1,8 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; /** @@ -18,6 +18,7 @@ import org.bouncycastle.util.Memoable; */ public class SHA224Digest extends GeneralDigest + implements EncodableDigest { private static final int DIGEST_LENGTH = 28; @@ -62,6 +63,26 @@ public class SHA224Digest xOff = t.xOff; } + public SHA224Digest(byte[] encodedState) + { + super(encodedState); + + H1 = Pack.bigEndianToInt(encodedState, 16); + H2 = Pack.bigEndianToInt(encodedState, 20); + H3 = Pack.bigEndianToInt(encodedState, 24); + H4 = Pack.bigEndianToInt(encodedState, 28); + H5 = Pack.bigEndianToInt(encodedState, 32); + H6 = Pack.bigEndianToInt(encodedState, 36); + H7 = Pack.bigEndianToInt(encodedState, 40); + H8 = Pack.bigEndianToInt(encodedState, 44); + + xOff = Pack.bigEndianToInt(encodedState, 48); + for (int i = 0; i != xOff; i++) + { + X[i] = Pack.bigEndianToInt(encodedState, 52 + (i * 4)); + } + } + public String getAlgorithmName() { return "SHA-224"; @@ -307,5 +328,29 @@ public class SHA224Digest doCopy(d); } + + public byte[] getEncodedState() + { + byte[] state = new byte[52 + xOff * 4]; + + super.populateState(state); + + Pack.intToBigEndian(H1, state, 16); + Pack.intToBigEndian(H2, state, 20); + Pack.intToBigEndian(H3, state, 24); + Pack.intToBigEndian(H4, state, 28); + Pack.intToBigEndian(H5, state, 32); + Pack.intToBigEndian(H6, state, 36); + Pack.intToBigEndian(H7, state, 40); + Pack.intToBigEndian(H8, state, 44); + Pack.intToBigEndian(xOff, state, 48); + + for (int i = 0; i != xOff; i++) + { + Pack.intToBigEndian(X[i], state, 52 + (i * 4)); + } + + return state; + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java index a2ceda3..600d234 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java @@ -1,8 +1,8 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; /** @@ -18,6 +18,7 @@ import org.bouncycastle.util.Memoable; */ public class SHA256Digest extends GeneralDigest + implements EncodableDigest { private static final int DIGEST_LENGTH = 32; @@ -62,6 +63,27 @@ public class SHA256Digest xOff = t.xOff; } + public SHA256Digest(byte[] encodedState) + { + super(encodedState); + + H1 = Pack.bigEndianToInt(encodedState, 16); + H2 = Pack.bigEndianToInt(encodedState, 20); + H3 = Pack.bigEndianToInt(encodedState, 24); + H4 = Pack.bigEndianToInt(encodedState, 28); + H5 = Pack.bigEndianToInt(encodedState, 32); + H6 = Pack.bigEndianToInt(encodedState, 36); + H7 = Pack.bigEndianToInt(encodedState, 40); + H8 = Pack.bigEndianToInt(encodedState, 44); + + xOff = Pack.bigEndianToInt(encodedState, 48); + for (int i = 0; i != xOff; i++) + { + X[i] = Pack.bigEndianToInt(encodedState, 52 + (i * 4)); + } + } + + public String getAlgorithmName() { return "SHA-256"; @@ -310,5 +332,29 @@ public class SHA256Digest copyIn(d); } + + public byte[] getEncodedState() + { + byte[] state = new byte[52 + xOff * 4]; + + super.populateState(state); + + Pack.intToBigEndian(H1, state, 16); + Pack.intToBigEndian(H2, state, 20); + Pack.intToBigEndian(H3, state, 24); + Pack.intToBigEndian(H4, state, 28); + Pack.intToBigEndian(H5, state, 32); + Pack.intToBigEndian(H6, state, 36); + Pack.intToBigEndian(H7, state, 40); + Pack.intToBigEndian(H8, state, 44); + Pack.intToBigEndian(xOff, state, 48); + + for (int i = 0; i != xOff; i++) + { + Pack.intToBigEndian(X[i], state, 52 + (i * 4)); + } + + return state; + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java index 75d195d..fc9fa1e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java @@ -1,7 +1,7 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; /** @@ -36,6 +36,11 @@ public class SHA384Digest super(t); } + public SHA384Digest(byte[] encodedState) + { + restoreState(encodedState); + } + public String getAlgorithmName() { return "SHA-384"; @@ -96,4 +101,11 @@ public class SHA384Digest super.copyIn(d); } + + public byte[] getEncodedState() + { + byte[] encoded = new byte[getEncodedStateSize()]; + super.populateState(encoded); + return encoded; + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java index 7db63ad..644bafa 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java @@ -1,7 +1,7 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; /** @@ -36,6 +36,11 @@ public class SHA512Digest super(t); } + public SHA512Digest(byte[] encodedState) + { + restoreState(encodedState); + } + public String getAlgorithmName() { return "SHA-512"; @@ -98,5 +103,12 @@ public class SHA512Digest copyIn(d); } + + public byte[] getEncodedState() + { + byte[] encoded = new byte[getEncodedStateSize()]; + super.populateState(encoded); + return encoded; + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java new file mode 100644 index 0000000..e3c596d --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java @@ -0,0 +1,774 @@ +package org.bouncycastle.crypto.ec; + +import java.math.BigInteger; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.sec.SECObjectIdentifiers; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.asn1.x9.X9ECParametersHolder; +import org.bouncycastle.asn1.x9.X9ECPoint; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +// BEGIN android-removed +// import org.bouncycastle.math.ec.custom.djb.Curve25519; +// import org.bouncycastle.math.ec.custom.sec.SecP128R1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecP160K1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecP160R1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecP160R2Curve; +// END android-removed +import org.bouncycastle.math.ec.custom.sec.SecP192K1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP192R1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP224K1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP224R1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP256K1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP384R1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP521R1Curve; +// BEGIN android-removed +// import org.bouncycastle.math.ec.custom.sec.SecT113R1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT113R2Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT131R1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT131R2Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT163K1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT163R1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT163R2Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT193R1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT193R2Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT233K1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT233R1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT239K1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT283K1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT283R1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT409K1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT409R1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT571K1Curve; +// import org.bouncycastle.math.ec.custom.sec.SecT571R1Curve; +// END android-removed +import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism; +import org.bouncycastle.math.ec.endo.GLVTypeBParameters; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +public class CustomNamedCurves +{ + private static ECCurve configureCurve(ECCurve curve) + { + return curve; + } + + private static ECCurve configureCurveGLV(ECCurve c, GLVTypeBParameters p) + { + return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create(); + } + + // BEGIN android-removed + // /* + // * curve25519 + // */ + // static X9ECParametersHolder curve25519 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = null; + // ECCurve curve = configureCurve(new Curve25519()); + // + // /* + // * NOTE: Curve25519 was specified in Montgomery form. Rewriting in Weierstrass form + // * involves substitution of variables, so the base-point x coordinate is 9 + (486662 / 3). + // * + // * The Curve25519 paper doesn't say which of the two possible y values the base + // * point has. The choice here is guided by language in the Ed25519 paper. + // * + // * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14) + // */ + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A" + // + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9")); + // + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + // + // /* + // * secp128r1 + // */ + // static X9ECParametersHolder secp128r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679"); + // ECCurve curve = configureCurve(new SecP128R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "161FF7528B899B2D0C28607CA52C5B86" + // + "CF5AC8395BAFEB13C02DA292DDED7A83")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + // + // /* + // * secp160k1 + // */ + // static X9ECParametersHolder secp160k1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = null; + // GLVTypeBParameters glv = new GLVTypeBParameters( + // new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16), + // new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16), + // new BigInteger[]{ + // new BigInteger("9162fbe73984472a0a9e", 16), + // new BigInteger("-96341f1138933bc2f505", 16) }, + // new BigInteger[]{ + // new BigInteger("127971af8721782ecffa3", 16), + // new BigInteger("9162fbe73984472a0a9e", 16) }, + // new BigInteger("9162fbe73984472a0a9d0590", 16), + // new BigInteger("96341f1138933bc2f503fd44", 16), + // 176); + // ECCurve curve = configureCurveGLV(new SecP160K1Curve(), glv); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB" + // + "938CF935318FDCED6BC28286531733C3F03C4FEE")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + // + // /* + // * secp160r1 + // */ + // static X9ECParametersHolder secp160r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345"); + // ECCurve curve = configureCurve(new SecP160R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "4A96B5688EF573284664698968C38BB913CBFC82" + // + "23A628553168947D59DCC912042351377AC5FB32")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + // + // /* + // * secp160r2 + // */ + // static X9ECParametersHolder secp160r2 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("B99B99B099B323E02709A4D696E6768756151751"); + // ECCurve curve = configureCurve(new SecP160R2Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "52DCB034293A117E1F4FF11B30F7199D3144CE6D" + // + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + // END android-removed + + /* + * secp192k1 + */ + static X9ECParametersHolder secp192k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = null; + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16), + new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16), + new BigInteger[]{ + new BigInteger("71169be7330b3038edb025f1", 16), + new BigInteger("-b3fb3400dec5c4adceb8655c", 16) }, + new BigInteger[]{ + new BigInteger("12511cfe811d0f4e6bc688b4d", 16), + new BigInteger("71169be7330b3038edb025f1", 16) }, + new BigInteger("71169be7330b3038edb025f1d0f9", 16), + new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16), + 208); + ECCurve curve = configureCurveGLV(new SecP192K1Curve(), glv); + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" + + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* + * secp192r1 + */ + static X9ECParametersHolder secp192r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5"); + ECCurve curve = configureCurve(new SecP192R1Curve()); + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012" + + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* + * secp224k1 + */ + static X9ECParametersHolder secp224k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = null; + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16), + new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16), + new BigInteger[]{ + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16), + new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) }, + new BigInteger[]{ + new BigInteger("1243ae1b4d71613bc9f780a03690e", 16), + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) }, + new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16), + new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16), + 240); + ECCurve curve = configureCurveGLV(new SecP224K1Curve(), glv); + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" + + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* + * secp224r1 + */ + static X9ECParametersHolder secp224r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); + ECCurve curve = configureCurve(new SecP224R1Curve()); + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" + + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* + * secp256k1 + */ + static X9ECParametersHolder secp256k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = null; + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16), + new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16), + new BigInteger[]{ + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16), + new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) }, + new BigInteger[]{ + new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16), + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) }, + new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16), + new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16), + 272); + ECCurve curve = configureCurveGLV(new SecP256K1Curve(), glv); + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" + + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* + * secp256r1 + */ + static X9ECParametersHolder secp256r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90"); + ECCurve curve = configureCurve(new SecP256R1Curve()); + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" + + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* + * secp384r1 + */ + static X9ECParametersHolder secp384r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73"); + ECCurve curve = configureCurve(new SecP384R1Curve()); + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" + + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* + * secp521r1 + */ + static X9ECParametersHolder secp521r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA"); + ECCurve curve = configureCurve(new SecP521R1Curve()); + X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" + + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + // BEGIN android-removed + // /* + // * sect113r1 + // */ + // static X9ECParametersHolder sect113r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("10E723AB14D696E6768756151756FEBF8FCB49A9"); + // ECCurve curve = configureCurve(new SecT113R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "009D73616F35F4AB1407D73562C10F" + // + "00A52830277958EE84D1315ED31886")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect113r2 + // */ + // static X9ECParametersHolder sect113r2 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("10C0FB15760860DEF1EEF4D696E676875615175D"); + // ECCurve curve = configureCurve(new SecT113R2Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "01A57A6A7B26CA5EF52FCDB8164797" + // + "00B3ADC94ED1FE674C06E695BABA1D")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect131r1 + // */ + // static X9ECParametersHolder sect131r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("4D696E676875615175985BD3ADBADA21B43A97E2"); + // ECCurve curve = configureCurve(new SecT131R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "0081BAF91FDF9833C40F9C181343638399" + // + "078C6E7EA38C001F73C8134B1B4EF9E150")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect131r2 + // */ + // static X9ECParametersHolder sect131r2 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("985BD3ADBAD4D696E676875615175A21B43A97E3"); + // ECCurve curve = configureCurve(new SecT131R2Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "0356DCD8F2F95031AD652D23951BB366A8" + // + "0648F06D867940A5366D9E265DE9EB240F")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect163k1 + // */ + // static X9ECParametersHolder sect163k1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = null; + // ECCurve curve = configureCurve(new SecT163K1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8" + // + "0289070FB05D38FF58321F2E800536D538CCDAA3D9")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect163r1 + // */ + // static X9ECParametersHolder sect163r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("24B7B137C8A14D696E6768756151756FD0DA2E5C"); + // ECCurve curve = configureCurve(new SecT163R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "0369979697AB43897789566789567F787A7876A654" + // + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect163r2 + // */ + // static X9ECParametersHolder sect163r2 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("85E25BFE5C86226CDB12016F7553F9D0E693A268"); + // ECCurve curve = configureCurve(new SecT163R2Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "03F0EBA16286A2D57EA0991168D4994637E8343E36" + // + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect193r1 + // */ + // static X9ECParametersHolder sect193r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("103FAEC74D696E676875615175777FC5B191EF30"); + // ECCurve curve = configureCurve(new SecT193R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1" + // + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect193r2 + // */ + // static X9ECParametersHolder sect193r2 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("10B7B4D696E676875615175137C8A16FD0DA2211"); + // ECCurve curve = configureCurve(new SecT193R2Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F" + // + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect233k1 + // */ + // static X9ECParametersHolder sect233k1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = null; + // ECCurve curve = configureCurve(new SecT233K1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126" + // + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect233r1 + // */ + // static X9ECParametersHolder sect233r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3"); + // ECCurve curve = configureCurve(new SecT233R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B" + // + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect239k1 + // */ + // static X9ECParametersHolder sect239k1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = null; + // ECCurve curve = configureCurve(new SecT239K1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC" + // + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect283k1 + // */ + // static X9ECParametersHolder sect283k1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = null; + // ECCurve curve = configureCurve(new SecT283K1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836" + // + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect283r1 + // */ + // static X9ECParametersHolder sect283r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE"); + // ECCurve curve = configureCurve(new SecT283R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053" + // + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect409k1 + // */ + // static X9ECParametersHolder sect409k1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = null; + // ECCurve curve = configureCurve(new SecT409K1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746" + // + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect409r1 + // */ + // static X9ECParametersHolder sect409r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("4099B5A457F9D69F79213D094C4BCD4D4262210B"); + // ECCurve curve = configureCurve(new SecT409R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7" + // + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect571k1 + // */ + // static X9ECParametersHolder sect571k1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = null; + // ECCurve curve = configureCurve(new SecT571K1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972" + // + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + + // /* + // * sect571r1 + // */ + // static X9ECParametersHolder sect571r1 = new X9ECParametersHolder() + // { + // protected X9ECParameters createParameters() + // { + // byte[] S = Hex.decode("2AA058F73A0E33AB486B0F610410C53A7F132310"); + // ECCurve curve = configureCurve(new SecT571R1Curve()); + // X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + // + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19" + // + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B")); + // return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + // } + // }; + // END android-removed + + + static final Hashtable nameToCurve = new Hashtable(); + static final Hashtable nameToOID = new Hashtable(); + static final Hashtable oidToCurve = new Hashtable(); + static final Hashtable oidToName = new Hashtable(); + static final Vector names = new Vector(); + + static void defineCurve(String name, X9ECParametersHolder holder) + { + names.addElement(name); + name = Strings.toLowerCase(name); + nameToCurve.put(name, holder); + } + + static void defineCurveWithOID(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) + { + names.addElement(name); + oidToName.put(oid, name); + oidToCurve.put(oid, holder); + name = Strings.toLowerCase(name); + nameToOID.put(name, oid); + nameToCurve.put(name, holder); + } + + static void defineCurveAlias(String name, ASN1ObjectIdentifier oid) + { + Object curve = oidToCurve.get(oid); + if (curve == null) + { + throw new IllegalStateException(); + } + + name = Strings.toLowerCase(name); + nameToOID.put(name, oid); + nameToCurve.put(name, curve); + } + + static + { + // BEGIN android-removed + // defineCurve("curve25519", curve25519); + // END android-removed + +// defineCurveWithOID("secp112r1", SECObjectIdentifiers.secp112r1, secp112r1); +// defineCurveWithOID("secp112r2", SECObjectIdentifiers.secp112r2, secp112r2); + // BEGIN android-removed + // defineCurveWithOID("secp128r1", SECObjectIdentifiers.secp128r1, secp128r1); + // END android-removed +// defineCurveWithOID("secp128r2", SECObjectIdentifiers.secp128r2, secp128r2); + // BEGIN android-removed + // defineCurveWithOID("secp160k1", SECObjectIdentifiers.secp160k1, secp160k1); + // defineCurveWithOID("secp160r1", SECObjectIdentifiers.secp160r1, secp160r1); + // defineCurveWithOID("secp160r2", SECObjectIdentifiers.secp160r2, secp160r2); + // END android-removed + defineCurveWithOID("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1); + defineCurveWithOID("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1); + defineCurveWithOID("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1); + defineCurveWithOID("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1); + defineCurveWithOID("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1); + defineCurveWithOID("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1); + defineCurveWithOID("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1); + defineCurveWithOID("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1); + + // BEGIN android-removed + // defineCurveWithOID("sect113r1", SECObjectIdentifiers.sect113r1, sect113r1); + // defineCurveWithOID("sect113r2", SECObjectIdentifiers.sect113r2, sect113r2); + // defineCurveWithOID("sect131r1", SECObjectIdentifiers.sect131r1, sect131r1); + // defineCurveWithOID("sect131r2", SECObjectIdentifiers.sect131r2, sect131r2); + // defineCurveWithOID("sect163k1", SECObjectIdentifiers.sect163k1, sect163k1); + // defineCurveWithOID("sect163r1", SECObjectIdentifiers.sect163r1, sect163r1); + // defineCurveWithOID("sect163r2", SECObjectIdentifiers.sect163r2, sect163r2); + // defineCurveWithOID("sect193r1", SECObjectIdentifiers.sect193r1, sect193r1); + // defineCurveWithOID("sect193r2", SECObjectIdentifiers.sect193r2, sect193r2); + // defineCurveWithOID("sect233k1", SECObjectIdentifiers.sect233k1, sect233k1); + // defineCurveWithOID("sect233r1", SECObjectIdentifiers.sect233r1, sect233r1); + // defineCurveWithOID("sect239k1", SECObjectIdentifiers.sect239k1, sect239k1); + // defineCurveWithOID("sect283k1", SECObjectIdentifiers.sect283k1, sect283k1); + // defineCurveWithOID("sect283r1", SECObjectIdentifiers.sect283r1, sect283r1); + // defineCurveWithOID("sect409k1", SECObjectIdentifiers.sect409k1, sect409k1); + // defineCurveWithOID("sect409r1", SECObjectIdentifiers.sect409r1, sect409r1); + // defineCurveWithOID("sect571k1", SECObjectIdentifiers.sect571k1, sect571k1); + // defineCurveWithOID("sect571r1", SECObjectIdentifiers.sect571r1, sect571r1); + + // defineCurveAlias("B-163", SECObjectIdentifiers.sect163r2); + // defineCurveAlias("B-233", SECObjectIdentifiers.sect233r1); + // defineCurveAlias("B-283", SECObjectIdentifiers.sect283r1); + // defineCurveAlias("B-409", SECObjectIdentifiers.sect409r1); + // defineCurveAlias("B-571", SECObjectIdentifiers.sect571r1); + + // defineCurveAlias("K-163", SECObjectIdentifiers.sect163k1); + // defineCurveAlias("K-233", SECObjectIdentifiers.sect233k1); + // defineCurveAlias("K-283", SECObjectIdentifiers.sect283k1); + // defineCurveAlias("K-409", SECObjectIdentifiers.sect409k1); + // defineCurveAlias("K-571", SECObjectIdentifiers.sect571k1); + // END android-removed + + defineCurveAlias("P-192", SECObjectIdentifiers.secp192r1); + defineCurveAlias("P-224", SECObjectIdentifiers.secp224r1); + defineCurveAlias("P-256", SECObjectIdentifiers.secp256r1); + defineCurveAlias("P-384", SECObjectIdentifiers.secp384r1); + defineCurveAlias("P-521", SECObjectIdentifiers.secp521r1); + } + + public static X9ECParameters getByName(String name) + { + X9ECParametersHolder holder = (X9ECParametersHolder)nameToCurve.get(Strings.toLowerCase(name)); + return holder == null ? null : holder.getParameters(); + } + + /** + * return the X9ECParameters object for the named curve represented by the passed in object + * identifier. Null if the curve isn't present. + * + * @param oid + * an object identifier representing a named curve, if present. + */ + public static X9ECParameters getByOID(ASN1ObjectIdentifier oid) + { + X9ECParametersHolder holder = (X9ECParametersHolder)oidToCurve.get(oid); + return holder == null ? null : holder.getParameters(); + } + + /** + * return the object identifier signified by the passed in name. Null if there is no object + * identifier associated with name. + * + * @return the object identifier associated with name, if present. + */ + public static ASN1ObjectIdentifier getOID(String name) + { + return (ASN1ObjectIdentifier)nameToOID.get(Strings.toLowerCase(name)); + } + + /** + * return the named curve name represented by the given object identifier. + */ + public static String getName(ASN1ObjectIdentifier oid) + { + return (String)oidToName.get(oid); + } + + /** + * returns an enumeration containing the name strings for curves contained in this structure. + */ + public static Enumeration getNames() + { + return names.elements(); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java index d8ec62b..71ca7f7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java @@ -17,16 +17,21 @@ import org.bouncycastle.crypto.params.ParametersWithRandom; public class PKCS1Encoding implements AsymmetricBlockCipher { + /** + * @deprecated use NOT_STRICT_LENGTH_ENABLED_PROPERTY + */ + public static final String STRICT_LENGTH_ENABLED_PROPERTY = "org.bouncycastle.pkcs1.strict"; + /** * some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to - * work with one of these set the system property org.bouncycastle.pkcs1.strict to false. + * work with one of these set the system property org.bouncycastle.pkcs1.not_strict to true. *

- * The system property is checked during construction of the encoding object, it is set to - * true by default. + * The system property is checked during construction of the encoding object, it is set to + * false by default. *

*/ - public static final String STRICT_LENGTH_ENABLED_PROPERTY = "org.bouncycastle.pkcs1.strict"; - + public static final String NOT_STRICT_LENGTH_ENABLED_PROPERTY = "org.bouncycastle.pkcs1.not_strict"; + private static final int HEADER_LENGTH = 10; private SecureRandom random; @@ -34,6 +39,8 @@ public class PKCS1Encoding private boolean forEncryption; private boolean forPrivateKey; private boolean useStrictLength; + private int pLen = -1; + private byte[] fallback = null; /** * Basic constructor. @@ -46,6 +53,42 @@ public class PKCS1Encoding this.useStrictLength = useStrict(); } + /** + * Constructor for decryption with a fixed plaintext length. + * + * @param cipher The cipher to use for cryptographic operation. + * @param pLen Length of the expected plaintext. + */ + public PKCS1Encoding( + AsymmetricBlockCipher cipher, + int pLen) + { + this.engine = cipher; + this.useStrictLength = useStrict(); + this.pLen = pLen; + } + + /** + * Constructor for decryption with a fixed plaintext length and a fallback + * value that is returned, if the padding is incorrect. + * + * @param cipher + * The cipher to use for cryptographic operation. + * @param fallback + * The fallback value, we don't do an arraycopy here. + */ + public PKCS1Encoding( + AsymmetricBlockCipher cipher, + byte[] fallback) + { + this.engine = cipher; + this.useStrictLength = useStrict(); + this.fallback = fallback; + this.pLen = fallback.length; + } + + + // // for J2ME compatibility // @@ -59,6 +102,18 @@ public class PKCS1Encoding return System.getProperty(STRICT_LENGTH_ENABLED_PROPERTY); } }); + String notStrict = (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return System.getProperty(NOT_STRICT_LENGTH_ENABLED_PROPERTY); + } + }); + + if (notStrict != null) + { + return !notStrict.equals("true"); + } return strict == null || strict.equals("true"); } @@ -83,8 +138,11 @@ public class PKCS1Encoding } else { - this.random = new SecureRandom(); kParam = (AsymmetricKeyParameter)param; + if (!kParam.isPrivate() && forEncryption) + { + this.random = new SecureRandom(); + } } engine.init(forEncryption, param); @@ -183,6 +241,121 @@ public class PKCS1Encoding return engine.processBlock(block, 0, block.length); } + + /** + * Checks if the argument is a correctly PKCS#1.5 encoded Plaintext + * for encryption. + * + * @param encoded The Plaintext. + * @param pLen Expected length of the plaintext. + * @return Either 0, if the encoding is correct, or -1, if it is incorrect. + */ + private static int checkPkcs1Encoding(byte[] encoded, int pLen) { + int correct = 0; + /* + * Check if the first two bytes are 0 2 + */ + correct |= (encoded[0] ^ 2); + + /* + * Now the padding check, check for no 0 byte in the padding + */ + int plen = encoded.length - ( + pLen /* Lenght of the PMS */ + + 1 /* Final 0-byte before PMS */ + ); + + for (int i = 1; i < plen; i++) { + int tmp = encoded[i]; + tmp |= tmp >> 1; + tmp |= tmp >> 2; + tmp |= tmp >> 4; + correct |= (tmp & 1) - 1; + } + + /* + * Make sure the padding ends with a 0 byte. + */ + correct |= encoded[encoded.length - (pLen +1)]; + + /* + * Return 0 or 1, depending on the result. + */ + correct |= correct >> 1; + correct |= correct >> 2; + correct |= correct >> 4; + return ~((correct & 1) - 1); + } + + + /** + * Decode PKCS#1.5 encoding, and return a random value if the padding is not correct. + * + * @param in The encrypted block. + * @param inOff Offset in the encrypted block. + * @param inLen Length of the encrypted block. + * //@param pLen Length of the desired output. + * @return The plaintext without padding, or a random value if the padding was incorrect. + * + * @throws InvalidCipherTextException + */ + private byte[] decodeBlockOrRandom(byte[] in, int inOff, int inLen) + throws InvalidCipherTextException + { + if (!forPrivateKey) + { + throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing"); + } + + byte[] block = engine.processBlock(in, inOff, inLen); + byte[] random = null; + if (this.fallback == null) + { + random = new byte[this.pLen]; + this.random.nextBytes(random); + } + else + { + random = fallback; + } + + /* + * TODO: This is a potential dangerous side channel. However, you can + * fix this by changing the RSA engine in a way, that it will always + * return blocks of the same length and prepend them with 0 bytes if + * needed. + */ + if (block.length < getOutputBlockSize()) + { + throw new InvalidCipherTextException("block truncated"); + } + + /* + * TODO: Potential side channel. Fix it by making the engine always + * return blocks of the correct length. + */ + if (useStrictLength && block.length != engine.getOutputBlockSize()) + { + throw new InvalidCipherTextException("block incorrect size"); + } + + /* + * Check the padding. + */ + int correct = PKCS1Encoding.checkPkcs1Encoding(block, this.pLen); + + /* + * Now, to a constant time constant memory copy of the decrypted value + * or the random value, depending on the validity of the padding. + */ + byte[] result = new byte[this.pLen]; + for (int i = 0; i < this.pLen; i++) + { + result[i] = (byte)((block[i + (block.length - pLen)] & (~correct)) | (random[i] & correct)); + } + + return result; + } /** * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format. @@ -193,7 +366,16 @@ public class PKCS1Encoding int inLen) throws InvalidCipherTextException { - byte[] block = engine.processBlock(in, inOff, inLen); + /* + * If the length of the expected plaintext is known, we use a constant-time decryption. + * If the decryption fails, we return a random value. + */ + if (this.pLen != -1) + { + return this.decodeBlockOrRandom(in, inOff, inLen); + } + + byte[] block = engine.processBlock(in, inOff, inLen); if (block.length < getOutputBlockSize()) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java index 756197c..924dff3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java @@ -5,6 +5,7 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Pack; /** * an implementation of the AES (Rijndael), from FIPS-197. @@ -230,12 +231,22 @@ private static final int[] Tinv0 = private static final int m1 = 0x80808080; private static final int m2 = 0x7f7f7f7f; private static final int m3 = 0x0000001b; + private static final int m4 = 0xC0C0C0C0; + private static final int m5 = 0x3f3f3f3f; private static int FFmulX(int x) { return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3)); } + private static int FFmulX2(int x) + { + int t0 = (x & m5) << 2; + int t1 = (x & m4); + t1 ^= (t1 >>> 1); + return t0 ^ (t1 >>> 2) ^ (t1 >>> 5); + } + /* The following defines provide alternative definitions of FFmulX that might give improved performance if a fast 32-bit multiply is not available. @@ -248,12 +259,13 @@ private static final int[] Tinv0 = private static int inv_mcol(int x) { - int f2 = FFmulX(x); - int f4 = FFmulX(f2); - int f8 = FFmulX(f4); - int f9 = x ^ f8; - - return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24); + int t0, t1; + t0 = x; + t1 = t0 ^ shift(t0, 8); + t0 ^= FFmulX(t1); + t1 ^= FFmulX2(t0); + t0 ^= t1 ^ shift(t1, 16); + return t0; } private static int subWord(int x) @@ -267,59 +279,128 @@ private static final int[] Tinv0 = * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits * This code is written assuming those are the only possible values */ - private int[][] generateWorkingKey( - byte[] key, - boolean forEncryption) + private int[][] generateWorkingKey(byte[] key, boolean forEncryption) { - int KC = key.length / 4; // key length in words - int t; - - if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length)) + int keyLen = key.length; + if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0) { throw new IllegalArgumentException("Key length not 128/192/256 bits."); } + int KC = keyLen >>> 2; ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes int[][] W = new int[ROUNDS+1][4]; // 4 words in a block - - // - // copy the key into the round key array - // - - t = 0; - int i = 0; - while (i < key.length) + + switch (KC) + { + case 4: + { + int t0 = Pack.littleEndianToInt(key, 0); W[0][0] = t0; + int t1 = Pack.littleEndianToInt(key, 4); W[0][1] = t1; + int t2 = Pack.littleEndianToInt(key, 8); W[0][2] = t2; + int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3; + + for (int i = 1; i <= 10; ++i) { - W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24); - i+=4; - t++; + int u = subWord(shift(t3, 8)) ^ rcon[i - 1]; + t0 ^= u; W[i][0] = t0; + t1 ^= t0; W[i][1] = t1; + t2 ^= t1; W[i][2] = t2; + t3 ^= t2; W[i][3] = t3; } - - // - // while not enough round key material calculated - // calculate new values - // - int k = (ROUNDS + 1) << 2; - for (i = KC; (i < k); i++) + + break; + } + case 6: + { + int t0 = Pack.littleEndianToInt(key, 0); W[0][0] = t0; + int t1 = Pack.littleEndianToInt(key, 4); W[0][1] = t1; + int t2 = Pack.littleEndianToInt(key, 8); W[0][2] = t2; + int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3; + int t4 = Pack.littleEndianToInt(key, 16); W[1][0] = t4; + int t5 = Pack.littleEndianToInt(key, 20); W[1][1] = t5; + + int rcon = 1; + int u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1; + t0 ^= u; W[1][2] = t0; + t1 ^= t0; W[1][3] = t1; + t2 ^= t1; W[2][0] = t2; + t3 ^= t2; W[2][1] = t3; + t4 ^= t3; W[2][2] = t4; + t5 ^= t4; W[2][3] = t5; + + for (int i = 3; i < 12; i += 3) { - int temp = W[(i-1)>>2][(i-1)&3]; - if ((i % KC) == 0) - { - temp = subWord(shift(temp, 8)) ^ rcon[(i / KC)-1]; - } - else if ((KC > 6) && ((i % KC) == 4)) - { - temp = subWord(temp); - } - - W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp; + u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1; + t0 ^= u; W[i ][0] = t0; + t1 ^= t0; W[i ][1] = t1; + t2 ^= t1; W[i ][2] = t2; + t3 ^= t2; W[i ][3] = t3; + t4 ^= t3; W[i + 1][0] = t4; + t5 ^= t4; W[i + 1][1] = t5; + u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1; + t0 ^= u; W[i + 1][2] = t0; + t1 ^= t0; W[i + 1][3] = t1; + t2 ^= t1; W[i + 2][0] = t2; + t3 ^= t2; W[i + 2][1] = t3; + t4 ^= t3; W[i + 2][2] = t4; + t5 ^= t4; W[i + 2][3] = t5; } + u = subWord(shift(t5, 8)) ^ rcon; + t0 ^= u; W[12][0] = t0; + t1 ^= t0; W[12][1] = t1; + t2 ^= t1; W[12][2] = t2; + t3 ^= t2; W[12][3] = t3; + + break; + } + case 8: + { + int t0 = Pack.littleEndianToInt(key, 0); W[0][0] = t0; + int t1 = Pack.littleEndianToInt(key, 4); W[0][1] = t1; + int t2 = Pack.littleEndianToInt(key, 8); W[0][2] = t2; + int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3; + int t4 = Pack.littleEndianToInt(key, 16); W[1][0] = t4; + int t5 = Pack.littleEndianToInt(key, 20); W[1][1] = t5; + int t6 = Pack.littleEndianToInt(key, 24); W[1][2] = t6; + int t7 = Pack.littleEndianToInt(key, 28); W[1][3] = t7; + + int u, rcon = 1; + + for (int i = 2; i < 14; i += 2) + { + u = subWord(shift(t7, 8)) ^ rcon; rcon <<= 1; + t0 ^= u; W[i ][0] = t0; + t1 ^= t0; W[i ][1] = t1; + t2 ^= t1; W[i ][2] = t2; + t3 ^= t2; W[i ][3] = t3; + u = subWord(t3); + t4 ^= u; W[i + 1][0] = t4; + t5 ^= t4; W[i + 1][1] = t5; + t6 ^= t5; W[i + 1][2] = t6; + t7 ^= t6; W[i + 1][3] = t7; + } + + u = subWord(shift(t7, 8)) ^ rcon; + t0 ^= u; W[14][0] = t0; + t1 ^= t0; W[14][1] = t1; + t2 ^= t1; W[14][2] = t2; + t3 ^= t2; W[14][3] = t3; + + break; + } + default: + { + throw new IllegalStateException("Should never get here"); + } + } + if (!forEncryption) { for (int j = 1; j < ROUNDS; j++) { - for (i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { W[j][i] = inv_mcol(W[j][i]); } @@ -473,74 +554,65 @@ private static final int[] Tinv0 = private void encryptBlock(int[][] KW) { - int r, r0, r1, r2, r3; - - C0 ^= KW[0][0]; - C1 ^= KW[0][1]; - C2 ^= KW[0][2]; - C3 ^= KW[0][3]; - - r = 1; + int t0 = this.C0 ^ KW[0][0]; + int t1 = this.C1 ^ KW[0][1]; + int t2 = this.C2 ^ KW[0][2]; + int r = 1, r0, r1, r2, r3 = this.C3 ^ KW[0][3]; while (r < ROUNDS - 1) { - r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255],16) ^ shift(T0[(C3>>24)&255],8) ^ KW[r][0]; - r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1]; - r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2]; - r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3]; - C0 = T0[r0&255] ^ shift(T0[(r1>>8)&255], 24) ^ shift(T0[(r2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0]; - C1 = T0[r1&255] ^ shift(T0[(r2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(r0>>24)&255], 8) ^ KW[r][1]; - C2 = T0[r2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(r0>>16)&255], 16) ^ shift(T0[(r1>>24)&255], 8) ^ KW[r][2]; - C3 = T0[r3&255] ^ shift(T0[(r0>>8)&255], 24) ^ shift(T0[(r1>>16)&255], 16) ^ shift(T0[(r2>>24)&255], 8) ^ KW[r++][3]; + r0 = T0[t0&255] ^ shift(T0[(t1>>8)&255], 24) ^ shift(T0[(t2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0]; + r1 = T0[t1&255] ^ shift(T0[(t2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(t0>>24)&255], 8) ^ KW[r][1]; + r2 = T0[t2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(t0>>16)&255], 16) ^ shift(T0[(t1>>24)&255], 8) ^ KW[r][2]; + r3 = T0[r3&255] ^ shift(T0[(t0>>8)&255], 24) ^ shift(T0[(t1>>16)&255], 16) ^ shift(T0[(t2>>24)&255], 8) ^ KW[r++][3]; + t0 = T0[r0&255] ^ shift(T0[(r1>>8)&255], 24) ^ shift(T0[(r2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0]; + t1 = T0[r1&255] ^ shift(T0[(r2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(r0>>24)&255], 8) ^ KW[r][1]; + t2 = T0[r2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(r0>>16)&255], 16) ^ shift(T0[(r1>>24)&255], 8) ^ KW[r][2]; + r3 = T0[r3&255] ^ shift(T0[(r0>>8)&255], 24) ^ shift(T0[(r1>>16)&255], 16) ^ shift(T0[(r2>>24)&255], 8) ^ KW[r++][3]; } - r0 = T0[C0&255] ^ shift(T0[(C1>>8)&255], 24) ^ shift(T0[(C2>>16)&255], 16) ^ shift(T0[(C3>>24)&255], 8) ^ KW[r][0]; - r1 = T0[C1&255] ^ shift(T0[(C2>>8)&255], 24) ^ shift(T0[(C3>>16)&255], 16) ^ shift(T0[(C0>>24)&255], 8) ^ KW[r][1]; - r2 = T0[C2&255] ^ shift(T0[(C3>>8)&255], 24) ^ shift(T0[(C0>>16)&255], 16) ^ shift(T0[(C1>>24)&255], 8) ^ KW[r][2]; - r3 = T0[C3&255] ^ shift(T0[(C0>>8)&255], 24) ^ shift(T0[(C1>>16)&255], 16) ^ shift(T0[(C2>>24)&255], 8) ^ KW[r++][3]; + r0 = T0[t0&255] ^ shift(T0[(t1>>8)&255], 24) ^ shift(T0[(t2>>16)&255], 16) ^ shift(T0[(r3>>24)&255], 8) ^ KW[r][0]; + r1 = T0[t1&255] ^ shift(T0[(t2>>8)&255], 24) ^ shift(T0[(r3>>16)&255], 16) ^ shift(T0[(t0>>24)&255], 8) ^ KW[r][1]; + r2 = T0[t2&255] ^ shift(T0[(r3>>8)&255], 24) ^ shift(T0[(t0>>16)&255], 16) ^ shift(T0[(t1>>24)&255], 8) ^ KW[r][2]; + r3 = T0[r3&255] ^ shift(T0[(t0>>8)&255], 24) ^ shift(T0[(t1>>16)&255], 16) ^ shift(T0[(t2>>24)&255], 8) ^ KW[r++][3]; // the final round's table is a simple function of S so we don't use a whole other four tables for it - C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0]; - C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1]; - C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; - C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; - + this.C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0]; + this.C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1]; + this.C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; + this.C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; } private void decryptBlock(int[][] KW) { - int r, r0, r1, r2, r3; - - C0 ^= KW[ROUNDS][0]; - C1 ^= KW[ROUNDS][1]; - C2 ^= KW[ROUNDS][2]; - C3 ^= KW[ROUNDS][3]; - - r = ROUNDS-1; + int t0 = this.C0 ^ KW[ROUNDS][0]; + int t1 = this.C1 ^ KW[ROUNDS][1]; + int t2 = this.C2 ^ KW[ROUNDS][2]; - while (r>1) + int r = ROUNDS - 1, r0, r1, r2, r3 = this.C3 ^ KW[ROUNDS][3]; + while (r > 1) { - r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0]; - r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1]; - r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2]; - r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r--][3]; - C0 = Tinv0[r0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(r2>>16)&255], 16) ^ shift(Tinv0[(r1>>24)&255], 8) ^ KW[r][0]; - C1 = Tinv0[r1&255] ^ shift(Tinv0[(r0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(r2>>24)&255], 8) ^ KW[r][1]; - C2 = Tinv0[r2&255] ^ shift(Tinv0[(r1>>8)&255], 24) ^ shift(Tinv0[(r0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2]; - C3 = Tinv0[r3&255] ^ shift(Tinv0[(r2>>8)&255], 24) ^ shift(Tinv0[(r1>>16)&255], 16) ^ shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--][3]; + r0 = Tinv0[t0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(t2>>16)&255], 16) ^ shift(Tinv0[(t1>>24)&255], 8) ^ KW[r][0]; + r1 = Tinv0[t1&255] ^ shift(Tinv0[(t0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(t2>>24)&255], 8) ^ KW[r][1]; + r2 = Tinv0[t2&255] ^ shift(Tinv0[(t1>>8)&255], 24) ^ shift(Tinv0[(t0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2]; + r3 = Tinv0[r3&255] ^ shift(Tinv0[(t2>>8)&255], 24) ^ shift(Tinv0[(t1>>16)&255], 16) ^ shift(Tinv0[(t0>>24)&255], 8) ^ KW[r--][3]; + t0 = Tinv0[r0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(r2>>16)&255], 16) ^ shift(Tinv0[(r1>>24)&255], 8) ^ KW[r][0]; + t1 = Tinv0[r1&255] ^ shift(Tinv0[(r0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(r2>>24)&255], 8) ^ KW[r][1]; + t2 = Tinv0[r2&255] ^ shift(Tinv0[(r1>>8)&255], 24) ^ shift(Tinv0[(r0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2]; + r3 = Tinv0[r3&255] ^ shift(Tinv0[(r2>>8)&255], 24) ^ shift(Tinv0[(r1>>16)&255], 16) ^ shift(Tinv0[(r0>>24)&255], 8) ^ KW[r--][3]; } - r0 = Tinv0[C0&255] ^ shift(Tinv0[(C3>>8)&255], 24) ^ shift(Tinv0[(C2>>16)&255], 16) ^ shift(Tinv0[(C1>>24)&255], 8) ^ KW[r][0]; - r1 = Tinv0[C1&255] ^ shift(Tinv0[(C0>>8)&255], 24) ^ shift(Tinv0[(C3>>16)&255], 16) ^ shift(Tinv0[(C2>>24)&255], 8) ^ KW[r][1]; - r2 = Tinv0[C2&255] ^ shift(Tinv0[(C1>>8)&255], 24) ^ shift(Tinv0[(C0>>16)&255], 16) ^ shift(Tinv0[(C3>>24)&255], 8) ^ KW[r][2]; - r3 = Tinv0[C3&255] ^ shift(Tinv0[(C2>>8)&255], 24) ^ shift(Tinv0[(C1>>16)&255], 16) ^ shift(Tinv0[(C0>>24)&255], 8) ^ KW[r][3]; + r0 = Tinv0[t0&255] ^ shift(Tinv0[(r3>>8)&255], 24) ^ shift(Tinv0[(t2>>16)&255], 16) ^ shift(Tinv0[(t1>>24)&255], 8) ^ KW[r][0]; + r1 = Tinv0[t1&255] ^ shift(Tinv0[(t0>>8)&255], 24) ^ shift(Tinv0[(r3>>16)&255], 16) ^ shift(Tinv0[(t2>>24)&255], 8) ^ KW[r][1]; + r2 = Tinv0[t2&255] ^ shift(Tinv0[(t1>>8)&255], 24) ^ shift(Tinv0[(t0>>16)&255], 16) ^ shift(Tinv0[(r3>>24)&255], 8) ^ KW[r][2]; + r3 = Tinv0[r3&255] ^ shift(Tinv0[(t2>>8)&255], 24) ^ shift(Tinv0[(t1>>16)&255], 16) ^ shift(Tinv0[(t0>>24)&255], 8) ^ KW[r][3]; // the final round's table is a simple function of Si so we don't use a whole other four tables for it - C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; - C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1]; - C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2]; - C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3]; + this.C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; + this.C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1]; + this.C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2]; + this.C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3]; } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java index ff4b2f8..11e1bce 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java @@ -5,6 +5,7 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Pack; /** * an implementation of the AES (Rijndael), from FIPS-197. @@ -110,8 +111,9 @@ public class AESFastEngine 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 }; // precomputation tables of calculations for rounds - private static final int[] T0 = + private static final int[] T = { + // T0 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, @@ -163,10 +165,9 @@ public class AESFastEngine 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, - 0x3a16162c}; + 0x3a16162c, - private static final int[] T1 = - { + // T1 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, @@ -218,10 +219,9 @@ public class AESFastEngine 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, - 0x16162c3a}; + 0x16162c3a, - private static final int[] T2 = - { + // T2 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, @@ -273,10 +273,9 @@ public class AESFastEngine 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, - 0x162c3a16}; + 0x162c3a16, - private static final int[] T3 = - { + // T3 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, @@ -330,8 +329,9 @@ public class AESFastEngine 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616}; - private static final int[] Tinv0 = + private static final int[] Tinv = { + // Tinv0 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, @@ -383,10 +383,9 @@ public class AESFastEngine 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, - 0x4257b8d0}; + 0x4257b8d0, - private static final int[] Tinv1 = - { + // Tinv1 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, @@ -438,10 +437,9 @@ public class AESFastEngine 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, - 0x57b8d042}; + 0x57b8d042, - private static final int[] Tinv2 = - { + // Tinv2 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, @@ -493,10 +491,9 @@ public class AESFastEngine 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3, 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, - 0xb8d04257}; + 0xb8d04257, - private static final int[] Tinv3 = - { + // Tinv3 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, @@ -560,12 +557,22 @@ public class AESFastEngine private static final int m1 = 0x80808080; private static final int m2 = 0x7f7f7f7f; private static final int m3 = 0x0000001b; + private static final int m4 = 0xC0C0C0C0; + private static final int m5 = 0x3f3f3f3f; private static int FFmulX(int x) { return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3)); } + private static int FFmulX2(int x) + { + int t0 = (x & m5) << 2; + int t1 = (x & m4); + t1 ^= (t1 >>> 1); + return t0 ^ (t1 >>> 2) ^ (t1 >>> 5); + } + /* The following defines provide alternative definitions of FFmulX that might give improved performance if a fast 32-bit multiply is not available. @@ -578,18 +585,20 @@ public class AESFastEngine private static int inv_mcol(int x) { - int f2 = FFmulX(x); - int f4 = FFmulX(f2); - int f8 = FFmulX(f4); - int f9 = x ^ f8; - - return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24); + int t0, t1; + t0 = x; + t1 = t0 ^ shift(t0, 8); + t0 ^= FFmulX(t1); + t1 ^= FFmulX2(t0); + t0 ^= t1 ^ shift(t1, 16); + return t0; } - private static int subWord(int x) { - return (S[x&255]&255 | ((S[(x>>8)&255]&255)<<8) | ((S[(x>>16)&255]&255)<<16) | S[(x>>24)&255]<<24); + int i0 = x, i1 = x >>> 8, i2 = x >>> 16, i3 = x >>> 24; + i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255; + return i0 | i1 << 8 | i2 << 16 | i3 << 24; } /** @@ -598,59 +607,128 @@ public class AESFastEngine * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits * This code is written assuming those are the only possible values */ - private int[][] generateWorkingKey( - byte[] key, - boolean forEncryption) + private int[][] generateWorkingKey(byte[] key, boolean forEncryption) { - int KC = key.length / 4; // key length in words - int t; - - if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length)) + int keyLen = key.length; + if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0) { throw new IllegalArgumentException("Key length not 128/192/256 bits."); } + int KC = keyLen >>> 2; ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes int[][] W = new int[ROUNDS+1][4]; // 4 words in a block - - // - // copy the key into the round key array - // - - t = 0; - int i = 0; - while (i < key.length) + + switch (KC) { - W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24); - i+=4; - t++; + case 4: + { + int t0 = Pack.littleEndianToInt(key, 0); W[0][0] = t0; + int t1 = Pack.littleEndianToInt(key, 4); W[0][1] = t1; + int t2 = Pack.littleEndianToInt(key, 8); W[0][2] = t2; + int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3; + + for (int i = 1; i <= 10; ++i) + { + int u = subWord(shift(t3, 8)) ^ rcon[i - 1]; + t0 ^= u; W[i][0] = t0; + t1 ^= t0; W[i][1] = t1; + t2 ^= t1; W[i][2] = t2; + t3 ^= t2; W[i][3] = t3; + } + + break; } - - // - // while not enough round key material calculated - // calculate new values - // - int k = (ROUNDS + 1) << 2; - for (i = KC; (i < k); i++) + case 6: { - int temp = W[(i - 1) >> 2][(i - 1) & 3]; - if ((i % KC) == 0) + int t0 = Pack.littleEndianToInt(key, 0); W[0][0] = t0; + int t1 = Pack.littleEndianToInt(key, 4); W[0][1] = t1; + int t2 = Pack.littleEndianToInt(key, 8); W[0][2] = t2; + int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3; + int t4 = Pack.littleEndianToInt(key, 16); W[1][0] = t4; + int t5 = Pack.littleEndianToInt(key, 20); W[1][1] = t5; + + int rcon = 1; + int u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1; + t0 ^= u; W[1][2] = t0; + t1 ^= t0; W[1][3] = t1; + t2 ^= t1; W[2][0] = t2; + t3 ^= t2; W[2][1] = t3; + t4 ^= t3; W[2][2] = t4; + t5 ^= t4; W[2][3] = t5; + + for (int i = 3; i < 12; i += 3) { - temp = subWord(shift(temp, 8)) ^ rcon[(i / KC) - 1]; + u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1; + t0 ^= u; W[i ][0] = t0; + t1 ^= t0; W[i ][1] = t1; + t2 ^= t1; W[i ][2] = t2; + t3 ^= t2; W[i ][3] = t3; + t4 ^= t3; W[i + 1][0] = t4; + t5 ^= t4; W[i + 1][1] = t5; + u = subWord(shift(t5, 8)) ^ rcon; rcon <<= 1; + t0 ^= u; W[i + 1][2] = t0; + t1 ^= t0; W[i + 1][3] = t1; + t2 ^= t1; W[i + 2][0] = t2; + t3 ^= t2; W[i + 2][1] = t3; + t4 ^= t3; W[i + 2][2] = t4; + t5 ^= t4; W[i + 2][3] = t5; } - else if ((KC > 6) && ((i % KC) == 4)) + + u = subWord(shift(t5, 8)) ^ rcon; + t0 ^= u; W[12][0] = t0; + t1 ^= t0; W[12][1] = t1; + t2 ^= t1; W[12][2] = t2; + t3 ^= t2; W[12][3] = t3; + + break; + } + case 8: + { + int t0 = Pack.littleEndianToInt(key, 0); W[0][0] = t0; + int t1 = Pack.littleEndianToInt(key, 4); W[0][1] = t1; + int t2 = Pack.littleEndianToInt(key, 8); W[0][2] = t2; + int t3 = Pack.littleEndianToInt(key, 12); W[0][3] = t3; + int t4 = Pack.littleEndianToInt(key, 16); W[1][0] = t4; + int t5 = Pack.littleEndianToInt(key, 20); W[1][1] = t5; + int t6 = Pack.littleEndianToInt(key, 24); W[1][2] = t6; + int t7 = Pack.littleEndianToInt(key, 28); W[1][3] = t7; + + int u, rcon = 1; + + for (int i = 2; i < 14; i += 2) { - temp = subWord(temp); + u = subWord(shift(t7, 8)) ^ rcon; rcon <<= 1; + t0 ^= u; W[i ][0] = t0; + t1 ^= t0; W[i ][1] = t1; + t2 ^= t1; W[i ][2] = t2; + t3 ^= t2; W[i ][3] = t3; + u = subWord(t3); + t4 ^= u; W[i + 1][0] = t4; + t5 ^= t4; W[i + 1][1] = t5; + t6 ^= t5; W[i + 1][2] = t6; + t7 ^= t6; W[i + 1][3] = t7; } - W[i >> 2][i & 3] = W[(i - KC) >> 2][(i - KC) & 3] ^ temp; + u = subWord(shift(t7, 8)) ^ rcon; + t0 ^= u; W[14][0] = t0; + t1 ^= t0; W[14][1] = t1; + t2 ^= t1; W[14][2] = t2; + t3 ^= t2; W[14][3] = t3; + + break; + } + default: + { + throw new IllegalStateException("Should never get here"); + } } if (!forEncryption) { for (int j = 1; j < ROUNDS; j++) { - for (i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { W[j][i] = inv_mcol(W[j][i]); } @@ -727,19 +805,19 @@ public class AESFastEngine throw new OutputLengthException("output buffer too short"); } + unpackBlock(in, inOff); + if (forEncryption) { - unpackBlock(in, inOff); encryptBlock(WorkingKey); - packBlock(out, outOff); } else { - unpackBlock(in, inOff); decryptBlock(WorkingKey); - packBlock(out, outOff); } + packBlock(out, outOff); + return BLOCK_SIZE; } @@ -747,129 +825,184 @@ public class AESFastEngine { } - private void unpackBlock( - byte[] bytes, - int off) + private void unpackBlock(byte[] bytes, int off) { - int index = off; - - C0 = (bytes[index++] & 0xff); - C0 |= (bytes[index++] & 0xff) << 8; - C0 |= (bytes[index++] & 0xff) << 16; - C0 |= bytes[index++] << 24; - - C1 = (bytes[index++] & 0xff); - C1 |= (bytes[index++] & 0xff) << 8; - C1 |= (bytes[index++] & 0xff) << 16; - C1 |= bytes[index++] << 24; - - C2 = (bytes[index++] & 0xff); - C2 |= (bytes[index++] & 0xff) << 8; - C2 |= (bytes[index++] & 0xff) << 16; - C2 |= bytes[index++] << 24; - - C3 = (bytes[index++] & 0xff); - C3 |= (bytes[index++] & 0xff) << 8; - C3 |= (bytes[index++] & 0xff) << 16; - C3 |= bytes[index++] << 24; + this.C0 = Pack.littleEndianToInt(bytes, off); + this.C1 = Pack.littleEndianToInt(bytes, off + 4); + this.C2 = Pack.littleEndianToInt(bytes, off + 8); + this.C3 = Pack.littleEndianToInt(bytes, off + 12); } - private void packBlock( - byte[] bytes, - int off) + private void packBlock(byte[] bytes, int off) { - int index = off; - - bytes[index++] = (byte)C0; - bytes[index++] = (byte)(C0 >> 8); - bytes[index++] = (byte)(C0 >> 16); - bytes[index++] = (byte)(C0 >> 24); - - bytes[index++] = (byte)C1; - bytes[index++] = (byte)(C1 >> 8); - bytes[index++] = (byte)(C1 >> 16); - bytes[index++] = (byte)(C1 >> 24); - - bytes[index++] = (byte)C2; - bytes[index++] = (byte)(C2 >> 8); - bytes[index++] = (byte)(C2 >> 16); - bytes[index++] = (byte)(C2 >> 24); - - bytes[index++] = (byte)C3; - bytes[index++] = (byte)(C3 >> 8); - bytes[index++] = (byte)(C3 >> 16); - bytes[index++] = (byte)(C3 >> 24); + Pack.intToLittleEndian(this.C0, bytes, off); + Pack.intToLittleEndian(this.C1, bytes, off + 4); + Pack.intToLittleEndian(this.C2, bytes, off + 8); + Pack.intToLittleEndian(this.C3, bytes, off + 12); } private void encryptBlock(int[][] KW) { - int r, r0, r1, r2, r3; - - C0 ^= KW[0][0]; - C1 ^= KW[0][1]; - C2 ^= KW[0][2]; - C3 ^= KW[0][3]; - - r = 1; + int t0 = this.C0 ^ KW[0][0]; + int t1 = this.C1 ^ KW[0][1]; + int t2 = this.C2 ^ KW[0][2]; + + /* + * Fast engine has precomputed rotr(T0, 8/16/24) tables T1/T2/T3. + * + * Placing all precomputes in one array requires offsets additions for 8/16/24 rotations but + * avoids additional array range checks on 3 more arrays (which on HotSpot are more + * expensive than the offset additions). + */ + int r = 1, r0, r1, r2, r3 = this.C3 ^ KW[0][3]; + int i0, i1, i2, i3; + while (r < ROUNDS - 1) { - r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r][0]; - r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r][1]; - r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r][2]; - r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++][3]; - C0 = T0[r0&255] ^ T1[(r1>>8)&255] ^ T2[(r2>>16)&255] ^ T3[(r3>>24)&255] ^ KW[r][0]; - C1 = T0[r1&255] ^ T1[(r2>>8)&255] ^ T2[(r3>>16)&255] ^ T3[(r0>>24)&255] ^ KW[r][1]; - C2 = T0[r2&255] ^ T1[(r3>>8)&255] ^ T2[(r0>>16)&255] ^ T3[(r1>>24)&255] ^ KW[r][2]; - C3 = T0[r3&255] ^ T1[(r0>>8)&255] ^ T2[(r1>>16)&255] ^ T3[(r2>>24)&255] ^ KW[r++][3]; + i0 = t0; i1 = t1 >>> 8; i2 = t2 >>> 16; i3 = r3 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r0 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][0]; + + i0 = t1; i1 = t2 >>> 8; i2 = r3 >>> 16; i3 = t0 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r1 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][1]; + + i0 = t2; i1 = r3 >>> 8; i2 = t0 >>> 16; i3 = t1 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r2 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][2]; + + i0 = r3; i1 = t0 >>> 8; i2 = t1 >>> 16; i3 = t2 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r3 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r++][3]; + + i0 = r0; i1 = r1 >>> 8; i2 = r2 >>> 16; i3 = r3 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + t0 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][0]; + + i0 = r1; i1 = r2 >>> 8; i2 = r3 >>> 16; i3 = r0 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + t1 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][1]; + + i0 = r2; i1 = r3 >>> 8; i2 = r0 >>> 16; i3 = r1 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + t2 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][2]; + + i0 = r3; i1 = r0 >>> 8; i2 = r1 >>> 16; i3 = r2 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r3 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r++][3]; } - r0 = T0[C0&255] ^ T1[(C1>>8)&255] ^ T2[(C2>>16)&255] ^ T3[(C3>>24)&255] ^ KW[r][0]; - r1 = T0[C1&255] ^ T1[(C2>>8)&255] ^ T2[(C3>>16)&255] ^ T3[(C0>>24)&255] ^ KW[r][1]; - r2 = T0[C2&255] ^ T1[(C3>>8)&255] ^ T2[(C0>>16)&255] ^ T3[(C1>>24)&255] ^ KW[r][2]; - r3 = T0[C3&255] ^ T1[(C0>>8)&255] ^ T2[(C1>>16)&255] ^ T3[(C2>>24)&255] ^ KW[r++][3]; - + i0 = t0; i1 = t1 >>> 8; i2 = t2 >>> 16; i3 = r3 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r0 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][0]; + + i0 = t1; i1 = t2 >>> 8; i2 = r3 >>> 16; i3 = t0 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r1 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][1]; + + i0 = t2; i1 = r3 >>> 8; i2 = t0 >>> 16; i3 = t1 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r2 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r][2]; + + i0 = r3; i1 = t0 >>> 8; i2 = t1 >>> 16; i3 = t2 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r3 = T[i0] ^ T[256 + i1] ^ T[512 + i2] ^ T[768 + i3] ^ KW[r++][3]; + // the final round's table is a simple function of S so we don't use a whole other four tables for it - C0 = (S[r0&255]&255) ^ ((S[(r1>>8)&255]&255)<<8) ^ ((S[(r2>>16)&255]&255)<<16) ^ (S[(r3>>24)&255]<<24) ^ KW[r][0]; - C1 = (S[r1&255]&255) ^ ((S[(r2>>8)&255]&255)<<8) ^ ((S[(r3>>16)&255]&255)<<16) ^ (S[(r0>>24)&255]<<24) ^ KW[r][1]; - C2 = (S[r2&255]&255) ^ ((S[(r3>>8)&255]&255)<<8) ^ ((S[(r0>>16)&255]&255)<<16) ^ (S[(r1>>24)&255]<<24) ^ KW[r][2]; - C3 = (S[r3&255]&255) ^ ((S[(r0>>8)&255]&255)<<8) ^ ((S[(r1>>16)&255]&255)<<16) ^ (S[(r2>>24)&255]<<24) ^ KW[r][3]; + i0 = r0; i1 = r1 >>> 8; i2 = r2 >>> 16; i3 = r3 >>> 24; + i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255; + this.C0 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][0]; + i0 = r1; i1 = r2 >>> 8; i2 = r3 >>> 16; i3 = r0 >>> 24; + i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255; + this.C1 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][1]; + + i0 = r2; i1 = r3 >>> 8; i2 = r0 >>> 16; i3 = r1 >>> 24; + i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255; + this.C2 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][2]; + + i0 = r3; i1 = r0 >>> 8; i2 = r1 >>> 16; i3 = r2 >>> 24; + i0 = S[i0 & 255] & 255; i1 = S[i1 & 255] & 255; i2 = S[i2 & 255] & 255; i3 = S[i3 & 255] & 255; + this.C3 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[r][3]; } private void decryptBlock(int[][] KW) { - int r0, r1, r2, r3; + int t0 = this.C0 ^ KW[ROUNDS][0]; + int t1 = this.C1 ^ KW[ROUNDS][1]; + int t2 = this.C2 ^ KW[ROUNDS][2]; - C0 ^= KW[ROUNDS][0]; - C1 ^= KW[ROUNDS][1]; - C2 ^= KW[ROUNDS][2]; - C3 ^= KW[ROUNDS][3]; + int r = ROUNDS - 1, r0, r1, r2, r3 = this.C3 ^ KW[ROUNDS][3]; + int i0, i1, i2, i3; - int r = ROUNDS-1; - - while (r>1) + while (r > 1) { - r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r][0]; - r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r][1]; - r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r][2]; - r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r--][3]; - C0 = Tinv0[r0&255] ^ Tinv1[(r3>>8)&255] ^ Tinv2[(r2>>16)&255] ^ Tinv3[(r1>>24)&255] ^ KW[r][0]; - C1 = Tinv0[r1&255] ^ Tinv1[(r0>>8)&255] ^ Tinv2[(r3>>16)&255] ^ Tinv3[(r2>>24)&255] ^ KW[r][1]; - C2 = Tinv0[r2&255] ^ Tinv1[(r1>>8)&255] ^ Tinv2[(r0>>16)&255] ^ Tinv3[(r3>>24)&255] ^ KW[r][2]; - C3 = Tinv0[r3&255] ^ Tinv1[(r2>>8)&255] ^ Tinv2[(r1>>16)&255] ^ Tinv3[(r0>>24)&255] ^ KW[r--][3]; + i0 = t0; i1 = r3 >>> 8; i2 = t2 >>> 16; i3 = t1 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r0 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][0]; + + i0 = t1; i1 = t0 >>> 8; i2 = r3 >>> 16; i3 = t2 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r1 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][1]; + + i0 = t2; i1 = t1 >>> 8; i2 = t0 >>> 16; i3 = r3 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r2 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][2]; + + i0 = r3; i1 = t2 >>> 8; i2 = t1 >>> 16; i3 = t0 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r3 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r--][3]; + + i0 = r0; i1 = r3 >>> 8; i2 = r2 >>> 16; i3 = r1 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + t0 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][0]; + + i0 = r1; i1 = r0 >>> 8; i2 = r3 >>> 16; i3 = r2 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + t1 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][1]; + + i0 = r2; i1 = r1 >>> 8; i2 = r0 >>> 16; i3 = r3 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + t2 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r][2]; + + i0 = r3; i1 = r2 >>> 8; i2 = r1 >>> 16; i3 = r0 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r3 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[r--][3]; } - r0 = Tinv0[C0&255] ^ Tinv1[(C3>>8)&255] ^ Tinv2[(C2>>16)&255] ^ Tinv3[(C1>>24)&255] ^ KW[r][0]; - r1 = Tinv0[C1&255] ^ Tinv1[(C0>>8)&255] ^ Tinv2[(C3>>16)&255] ^ Tinv3[(C2>>24)&255] ^ KW[r][1]; - r2 = Tinv0[C2&255] ^ Tinv1[(C1>>8)&255] ^ Tinv2[(C0>>16)&255] ^ Tinv3[(C3>>24)&255] ^ KW[r][2]; - r3 = Tinv0[C3&255] ^ Tinv1[(C2>>8)&255] ^ Tinv2[(C1>>16)&255] ^ Tinv3[(C0>>24)&255] ^ KW[r][3]; - + i0 = t0; i1 = r3 >>> 8; i2 = t2 >>> 16; i3 = t1 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r0 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][0]; + + i0 = t1; i1 = t0 >>> 8; i2 = r3 >>> 16; i3 = t2 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r1 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][1]; + + i0 = t2; i1 = t1 >>> 8; i2 = t0 >>> 16; i3 = r3 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r2 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][2]; + + i0 = r3; i1 = t2 >>> 8; i2 = t1 >>> 16; i3 = t0 >>> 24; + i0 &= 255; i1 &= 255; i2 &= 255; i3 &= 255; + r3 = Tinv[i0] ^ Tinv[256 + i1] ^ Tinv[512 + i2] ^ Tinv[768 + i3] ^ KW[1][3]; + // the final round's table is a simple function of Si so we don't use a whole other four tables for it - C0 = (Si[r0&255]&255) ^ ((Si[(r3>>8)&255]&255)<<8) ^ ((Si[(r2>>16)&255]&255)<<16) ^ (Si[(r1>>24)&255]<<24) ^ KW[0][0]; - C1 = (Si[r1&255]&255) ^ ((Si[(r0>>8)&255]&255)<<8) ^ ((Si[(r3>>16)&255]&255)<<16) ^ (Si[(r2>>24)&255]<<24) ^ KW[0][1]; - C2 = (Si[r2&255]&255) ^ ((Si[(r1>>8)&255]&255)<<8) ^ ((Si[(r0>>16)&255]&255)<<16) ^ (Si[(r3>>24)&255]<<24) ^ KW[0][2]; - C3 = (Si[r3&255]&255) ^ ((Si[(r2>>8)&255]&255)<<8) ^ ((Si[(r1>>16)&255]&255)<<16) ^ (Si[(r0>>24)&255]<<24) ^ KW[0][3]; + i0 = r0; i1 = r3 >>> 8; i2 = r2 >>> 16; i3 = r1 >>> 24; + i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255; + this.C0 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][0]; + + i0 = r1; i1 = r0 >>> 8; i2 = r3 >>> 16; i3 = r2 >>> 24; + i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255; + this.C1 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][1]; + + i0 = r2; i1 = r1 >>> 8; i2 = r0 >>> 16; i3 = r3 >>> 24; + i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255; + this.C2 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][2]; + + i0 = r3; i1 = r2 >>> 8; i2 = r1 >>> 16; i3 = r0 >>> 24; + i0 = Si[i0 & 255] & 255; i1 = Si[i1 & 255] & 255; i2 = Si[i2 & 255] & 255; i3 = Si[i3 & 255] & 255; + this.C3 = i0 ^ i1 << 8 ^ i2 << 16 ^ i3 << 24 ^ KW[0][3]; } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java index 5d316ac..6d3e5ac 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java @@ -9,8 +9,21 @@ package org.bouncycastle.crypto.engines; public class AESWrapEngine extends RFC3394WrapEngine { + /** + * Create a regular AESWrapEngine specifying the encrypt for wrapping, decrypt for unwrapping. + */ public AESWrapEngine() { super(new AESEngine()); } + + /** + * Create an AESWrapEngine where the underlying cipher is set to decrypt for wrapping, encrypt for unwrapping. + * + * @param useReverseDirection true if underlying cipher should be used in decryption mode, false otherwise. + */ + public AESWrapEngine(boolean useReverseDirection) + { + super(new AESEngine(), useReverseDirection); + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java index 9b1e404..6980fd0 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java @@ -301,7 +301,7 @@ public class DESEngine * generate an integer based working key based on our secret key * and what we processing we are planning to do. * - * Acknowledgements for this routine go to James Gillogly & Phil Karn. + * Acknowledgements for this routine go to James Gillogly & Phil Karn. * (whoever, and wherever they are!). */ protected int[] generateWorkingKey( diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java index d0c04f2..ba75c8d 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java @@ -17,12 +17,11 @@ import org.bouncycastle.util.Arrays; /** * Wrap keys according to - * - * draft-ietf-smime-key-wrap-01.txt. + * + * RFC 3217. *

* Note: *

    - *
  • this is based on a draft, and as such is subject to change - don't use this class for anything requiring long term storage. *
  • if you are using this to wrap triple-des keys you need to set the * parity bits on the key and, if it's a two-key triple-des key, pad it * yourself. @@ -62,8 +61,8 @@ public class DESedeWrapEngine /** * Method init * - * @param forWrapping - * @param param + * @param forWrapping true if for wrapping, false otherwise. + * @param param necessary parameters, may include KeyParameter, ParametersWithRandom, and ParametersWithIV */ public void init(boolean forWrapping, CipherParameters param) { @@ -132,9 +131,9 @@ public class DESedeWrapEngine /** * Method wrap * - * @param in - * @param inOff - * @param inLen + * @param in byte array containing the encoded key. + * @param inOff off set into in that the data starts at. + * @param inLen length of the data. * @return the wrapped bytes. */ public byte[] wrap(byte[] in, int inOff, int inLen) @@ -203,9 +202,9 @@ public class DESedeWrapEngine /** * Method unwrap * - * @param in - * @param inOff - * @param inLen + * @param in byte array containing the wrapped key. + * @param inOff off set into in that the data starts at. + * @param inLen length of the data. * @return the unwrapped bytes. * @throws InvalidCipherTextException */ @@ -309,10 +308,11 @@ public class DESedeWrapEngine * - Compute the 20 octet SHA-1 hash on the key being wrapped. * - Use the first 8 octets of this hash as the checksum value. * - * @param key + * For details see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum. + * + * @param key the key to check, * @return the CMS checksum. * @throws RuntimeException - * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum */ private byte[] calculateCMSKeyChecksum( byte[] key) @@ -328,10 +328,11 @@ public class DESedeWrapEngine } /** - * @param key - * @param checksum + * For details see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum + * + * @param key key to be validated. + * @param checksum the checksum. * @return true if okay, false otherwise. - * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum */ private boolean checkCMSKeyChecksum( byte[] key, diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java index 4de7ea6..c1ceaa4 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java @@ -68,7 +68,7 @@ public class RC4Engine implements StreamCipher return (byte)(in ^ engineState[(engineState[x] + engineState[y]) & 0xff]); } - public void processBytes( + public int processBytes( byte[] in, int inOff, int len, @@ -99,6 +99,8 @@ public class RC4Engine implements StreamCipher out[i+outOff] = (byte)(in[i + inOff] ^ engineState[(engineState[x] + engineState[y]) & 0xff]); } + + return len; } public void reset() diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java index cfd86fb..d2886e7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java @@ -21,6 +21,7 @@ public class RFC3394WrapEngine implements Wrapper { private BlockCipher engine; + private boolean wrapCipherMode; private KeyParameter param; private boolean forWrapping; @@ -28,9 +29,26 @@ public class RFC3394WrapEngine (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6 }; + /** + * Create a RFC 3394 WrapEngine specifying the encrypt for wrapping, decrypt for unwrapping. + * + * @param engine the block cipher to be used for wrapping. + */ public RFC3394WrapEngine(BlockCipher engine) + { + this(engine, false); + } + + /** + * Create a RFC 3394 WrapEngine specifying the direction for wrapping and unwrapping.. + * + * @param engine the block cipher to be used for wrapping. + * @param useReverseDirection true if engine should be used in decryption mode for wrapping, false otherwise. + */ + public RFC3394WrapEngine(BlockCipher engine, boolean useReverseDirection) { this.engine = engine; + this.wrapCipherMode = (useReverseDirection) ? false : true; } public void init( @@ -87,7 +105,7 @@ public class RFC3394WrapEngine System.arraycopy(iv, 0, block, 0, iv.length); System.arraycopy(in, inOff, block, iv.length, inLen); - engine.init(true, param); + engine.init(wrapCipherMode, param); for (int j = 0; j != 6; j++) { @@ -140,7 +158,7 @@ public class RFC3394WrapEngine System.arraycopy(in, inOff, a, 0, iv.length); System.arraycopy(in, inOff + iv.length, block, 0, inLen - iv.length); - engine.init(false, param); + engine.init(!wrapCipherMode, param); n = n - 1; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java index c9765bf..d74e2b3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java @@ -110,6 +110,11 @@ public class RSABlindedEngine BigInteger rInv = r.modInverse(m); result = blindedResult.multiply(rInv).mod(m); + // defence against Arjen Lenstra’s CRT attack + if (!input.equals(result.modPow(e, m))) + { + throw new IllegalStateException("RSA engine faulty decryption/signing detected"); + } } else { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java index 3cab983..19a2ecf 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java @@ -6,6 +6,8 @@ import org.bouncycastle.crypto.params.DESedeParameters; public class DESedeKeyGenerator extends DESKeyGenerator { + private static final int MAX_IT = 20; + /** * initialise the key generator - if strength is set to zero * the key generated will be 192 bits in size, otherwise @@ -42,6 +44,7 @@ public class DESedeKeyGenerator public byte[] generateKey() { byte[] newKey = new byte[strength]; + int count = 0; do { @@ -49,7 +52,12 @@ public class DESedeKeyGenerator DESedeParameters.setOddParity(newKey); } - while (DESedeParameters.isWeakKey(newKey, 0, newKey.length)); + while (++count < MAX_IT && (DESedeParameters.isWeakKey(newKey, 0, newKey.length) || !DESedeParameters.isRealEDEKey(newKey, 0))); + + if (DESedeParameters.isWeakKey(newKey, 0, newKey.length) || !DESedeParameters.isRealEDEKey(newKey, 0)) + { + throw new IllegalStateException("Unable to generate DES-EDE key"); + } return newKey; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java index e0d86fc..6795ec9 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java @@ -4,6 +4,7 @@ import java.math.BigInteger; import java.security.SecureRandom; import org.bouncycastle.crypto.params.DHParameters; +import org.bouncycastle.math.ec.WNafUtil; import org.bouncycastle.util.BigIntegers; class DHKeyGeneratorHelper @@ -19,12 +20,19 @@ class DHKeyGeneratorHelper BigInteger calculatePrivate(DHParameters dhParams, SecureRandom random) { - BigInteger p = dhParams.getP(); int limit = dhParams.getL(); if (limit != 0) { - return new BigInteger(limit, random).setBit(limit - 1); + int minWeight = limit >>> 2; + for (;;) + { + BigInteger x = new BigInteger(limit, random).setBit(limit - 1); + if (WNafUtil.getNafWeight(x) >= minWeight) + { + return x; + } + } } BigInteger min = TWO; @@ -34,14 +42,22 @@ class DHKeyGeneratorHelper min = ONE.shiftLeft(m - 1); } - BigInteger max = p.subtract(TWO); BigInteger q = dhParams.getQ(); - if (q != null) + if (q == null) { - max = q.subtract(TWO); + q = dhParams.getP(); } + BigInteger max = q.subtract(TWO); - return BigIntegers.createRandomInRange(min, max, random); + int minWeight = max.bitLength() >>> 2; + for (;;) + { + BigInteger x = BigIntegers.createRandomInRange(min, max, random); + if (WNafUtil.getNafWeight(x) >= minWeight) + { + return x; + } + } } BigInteger calculatePublic(DHParameters dhParams, BigInteger x) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java index 05c7839..a0728b2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java @@ -6,6 +6,7 @@ import java.security.SecureRandom; // BEGIN android-added import java.util.logging.Logger; // END android-added +import org.bouncycastle.math.ec.WNafUtil; import org.bouncycastle.util.BigIntegers; class DHParametersHelper @@ -31,6 +32,7 @@ class DHParametersHelper // END android-added BigInteger p, q; int qLength = size - 1; + int minWeight = size >>> 2; for (;;) { @@ -42,10 +44,28 @@ class DHParametersHelper // p <- 2q + 1 p = q.shiftLeft(1).add(ONE); - if (p.isProbablePrime(certainty) && (certainty <= 2 || q.isProbablePrime(certainty))) + if (!p.isProbablePrime(certainty)) { - break; + continue; } + + if (certainty > 2 && !q.isProbablePrime(certainty - 2)) + { + continue; + } + + /* + * Require a minimum weight of the NAF representation, since low-weight primes may be + * weak against a version of the number-field-sieve for the discrete-logarithm-problem. + * + * See "The number field sieve for integers of low weight", Oliver Schirokauer. + */ + if (WNafUtil.getNafWeight(p) < minWeight) + { + continue; + } + + break; } // BEGIN android-added long end = System.currentTimeMillis(); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java index 93f49cf..ff3df35 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java @@ -1,5 +1,8 @@ package org.bouncycastle.crypto.generators; +import java.math.BigInteger; +import java.security.SecureRandom; + import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; import org.bouncycastle.crypto.KeyGenerationParameters; @@ -7,11 +10,9 @@ import org.bouncycastle.crypto.params.DSAKeyGenerationParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import org.bouncycastle.math.ec.WNafUtil; import org.bouncycastle.util.BigIntegers; -import java.math.BigInteger; -import java.security.SecureRandom; - /** * a DSA key pair generator. * @@ -45,13 +46,20 @@ public class DSAKeyPairGenerator private static BigInteger generatePrivateKey(BigInteger q, SecureRandom random) { - // TODO Prefer this method? (change test cases that used fixed random) - // B.1.1 Key Pair Generation Using Extra Random Bits -// BigInteger c = new BigInteger(q.bitLength() + 64, random); -// return c.mod(q.subtract(ONE)).add(ONE); - // B.1.2 Key Pair Generation by Testing Candidates - return BigIntegers.createRandomInRange(ONE, q.subtract(ONE), random); + int minWeight = q.bitLength() >>> 2; + for (;;) + { + // TODO Prefer this method? (change test cases that used fixed random) + // B.1.1 Key Pair Generation Using Extra Random Bits +// BigInteger x = new BigInteger(q.bitLength() + 64, random).mod(q.subtract(ONE)).add(ONE); + + BigInteger x = BigIntegers.createRandomInRange(ONE, q.subtract(ONE), random); + if (WNafUtil.getNafWeight(x) >= minWeight) + { + return x; + } + } } private static BigInteger calculatePublicKey(BigInteger p, BigInteger g, BigInteger x) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java index d70ee8f..61b4bea 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java @@ -19,17 +19,17 @@ import org.bouncycastle.util.encoders.Hex; */ public class DSAParametersGenerator { - private Digest digest; - private int L, N; - private int certainty; - private SecureRandom random; - private static final BigInteger ZERO = BigInteger.valueOf(0); private static final BigInteger ONE = BigInteger.valueOf(1); private static final BigInteger TWO = BigInteger.valueOf(2); - private boolean use186_3; - private int usageIndex; + private Digest digest; + private int L, N; + private int certainty; + private int iterations; + private SecureRandom random; + private boolean use186_3; + private int usageIndex; public DSAParametersGenerator() { @@ -46,7 +46,7 @@ public class DSAParametersGenerator /** * initialise the key generator. * - * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments) + * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments) * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80). * @param random random byte source. */ @@ -55,11 +55,13 @@ public class DSAParametersGenerator int certainty, SecureRandom random) { - this.use186_3 = false; this.L = size; this.N = getDefaultN(size); this.certainty = certainty; + this.iterations = Math.max(getMinimumIterations(L), (certainty + 1) / 2); this.random = random; + this.use186_3 = false; + this.usageIndex = -1; } /** @@ -73,13 +75,7 @@ public class DSAParametersGenerator public void init( DSAParameterGenerationParameters params) { - // TODO Should we enforce the minimum 'certainty' values as per C.3 Table C.1? - this.use186_3 = true; - this.L = params.getL(); - this.N = params.getN(); - this.certainty = params.getCertainty(); - this.random = params.getRandom(); - this.usageIndex = params.getUsageIndex(); + int L = params.getL(), N = params.getN(); if ((L < 1024 || L > 3072) || L % 1024 != 0) { @@ -102,6 +98,14 @@ public class DSAParametersGenerator { throw new IllegalStateException("Digest output size too small for value of N"); } + + this.L = L; + this.N = N; + this.certainty = params.getCertainty(); + this.iterations = Math.max(getMinimumIterations(L), (certainty + 1) / 2); + this.random = params.getRandom(); + this.use186_3 = true; + this.usageIndex = params.getUsageIndex(); } /** @@ -137,10 +141,10 @@ public class DSAParametersGenerator { random.nextBytes(seed); - hash(digest, seed, part1); + hash(digest, seed, part1, 0); System.arraycopy(seed, 0, part2, 0, seed.length); inc(part2); - hash(digest, part2, part2); + hash(digest, part2, part2, 0); for (int i = 0; i != u.length; i++) { @@ -152,7 +156,7 @@ public class DSAParametersGenerator BigInteger q = new BigInteger(1, u); - if (!q.isProbablePrime(certainty)) + if (!isProbablePrime(q)) { continue; } @@ -162,18 +166,20 @@ public class DSAParametersGenerator for (int counter = 0; counter < 4096; ++counter) { - for (int k = 0; k < n; k++) { - inc(offset); - hash(digest, offset, part1); - System.arraycopy(part1, 0, w, w.length - (k + 1) * part1.length, part1.length); - } + for (int k = 1; k <= n; k++) + { + inc(offset); + hash(digest, offset, w, w.length - k * part1.length); + } - inc(offset); - hash(digest, offset, part1); - System.arraycopy(part1, part1.length - ((w.length - (n) * part1.length)), w, 0, w.length - n * part1.length); + int remaining = w.length - (n * part1.length); + inc(offset); + hash(digest, offset, part1, 0); + System.arraycopy(part1, part1.length - remaining, w, 0, remaining); - w[0] |= (byte)0x80; + w[0] |= (byte)0x80; + } BigInteger x = new BigInteger(1, w); @@ -186,7 +192,7 @@ public class DSAParametersGenerator continue; } - if (p.isProbablePrime(certainty)) + if (isProbablePrime(p)) { BigInteger g = calculateGenerator_FIPS186_2(p, q, random); @@ -238,6 +244,7 @@ public class DSAParametersGenerator // 4. b = L - 1 - (n * outlen). int b = (L - 1) % outlen; + byte[] w = new byte[L / 8]; byte[] output = new byte[d.getDigestSize()]; for (;;) { @@ -245,16 +252,15 @@ public class DSAParametersGenerator random.nextBytes(seed); // 6. U = Hash (domain_parameter_seed) mod 2^(N–1). - hash(d, seed, output); + hash(d, seed, output, 0); BigInteger U = new BigInteger(1, output).mod(ONE.shiftLeft(N - 1)); // 7. q = 2^(N–1) + U + 1 – ( U mod 2). - BigInteger q = ONE.shiftLeft(N - 1).add(U).add(ONE).subtract(U.mod(TWO)); + BigInteger q = U.setBit(0).setBit(N - 1); // 8. Test whether or not q is prime as specified in Appendix C.3. - // TODO Review C.3 for primality checking - if (!q.isProbablePrime(certainty)) + if (!isProbablePrime(q)) { // 9. If q is not a prime, then go to step 5. continue; @@ -271,24 +277,23 @@ public class DSAParametersGenerator // 11.1 For j = 0 to n do // Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen). // 11.2 W = V0 + (V1 ∗ 2^outlen) + ... + (V^(n–1) ∗ 2^((n–1) ∗ outlen)) + ((Vn mod 2^b) ∗ 2^(n ∗ outlen)). - // TODO Assemble w as a byte array - BigInteger W = ZERO; - for (int j = 0, exp = 0; j <= n; ++j, exp += outlen) { - inc(offset); - hash(d, offset, output); - - BigInteger Vj = new BigInteger(1, output); - if (j == n) + for (int j = 1; j <= n; ++j) { - Vj = Vj.mod(ONE.shiftLeft(b)); + inc(offset); + hash(d, offset, w, w.length - j * output.length); } - W = W.add(Vj.shiftLeft(exp)); + int remaining = w.length - (n * output.length); + inc(offset); + hash(d, offset, output, 0); + System.arraycopy(output, output.length - remaining, w, 0, remaining); + +// 11.3 X = W + 2^(L–1). Comment: 0 ≤ W < 2^(L–1); hence, 2^(L–1) ≤ X < 2^L. + w[0] |= (byte)0x80; } -// 11.3 X = W + 2^(L–1). Comment: 0 ≤ W < 2L–1; hence, 2L–1 ≤ X < 2L. - BigInteger X = W.add(ONE.shiftLeft(L - 1)); + BigInteger X = new BigInteger(1, w); // 11.4 c = X mod 2q. BigInteger c = X.mod(q.shiftLeft(1)); @@ -296,15 +301,14 @@ public class DSAParametersGenerator // 11.5 p = X - (c - 1). Comment: p ≡ 1 (mod 2q). BigInteger p = X.subtract(c.subtract(ONE)); -// 11.6 If (p < 2^(L - 1)), then go to step 11.9 +// 11.6 If (p < 2^(L-1)), then go to step 11.9 if (p.bitLength() != L) { continue; } // 11.7 Test whether or not p is prime as specified in Appendix C.3. - // TODO Review C.3 for primality checking - if (p.isProbablePrime(certainty)) + if (isProbablePrime(p)) { // 11.8 If p is determined to be prime, then return VALID and the values of p, q and // (optionally) the values of domain_parameter_seed and counter. @@ -331,6 +335,16 @@ public class DSAParametersGenerator } } + private boolean isProbablePrime(BigInteger x) + { + /* + * TODO Use Primes class for FIPS 186-4 C.3 primality checking - but it breaks existing + * tests using FixedSecureRandom + */ +// return !Primes.hasAnySmallFactors(x) && Primes.isMRProbablePrime(x, random, iterations); + return x.isProbablePrime(certainty); + } + private static BigInteger calculateGenerator_FIPS186_3_Unverifiable(BigInteger p, BigInteger q, SecureRandom r) { @@ -354,7 +368,7 @@ public class DSAParametersGenerator for (int count = 1; count < (1 << 16); ++count) { inc(U); - hash(d, U, w); + hash(d, U, w, 0); BigInteger W = new BigInteger(1, w); BigInteger g = W.modPow(e, p); if (g.compareTo(TWO) >= 0) @@ -366,10 +380,10 @@ public class DSAParametersGenerator return null; } - private static void hash(Digest d, byte[] input, byte[] output) + private static void hash(Digest d, byte[] input, byte[] output, int outputPos) { d.update(input, 0, input.length); - d.doFinal(output, 0); + d.doFinal(output, outputPos); } private static int getDefaultN(int L) @@ -377,6 +391,12 @@ public class DSAParametersGenerator return L > 1024 ? 256 : 160; } + private static int getMinimumIterations(int L) + { + // Values based on FIPS 186-4 C.3 Table C.1 + return L <= 1024 ? 40 : (48 + 8 * ((L - 1) / 1024)); + } + private static void inc(byte[] buf) { for (int i = buf.length - 1; i >= 0; --i) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java index d5f5fc8..c766071 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java @@ -11,7 +11,10 @@ import org.bouncycastle.crypto.params.ECKeyGenerationParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECMultiplier; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.FixedPointCombMultiplier; +import org.bouncycastle.math.ec.WNafUtil; public class ECKeyPairGenerator implements AsymmetricCipherKeyPairGenerator, ECConstants @@ -40,19 +43,36 @@ public class ECKeyPairGenerator public AsymmetricCipherKeyPair generateKeyPair() { BigInteger n = params.getN(); - int nBitLength = n.bitLength(); - BigInteger d; + int nBitLength = n.bitLength(); + int minWeight = nBitLength >>> 2; - do + BigInteger d; + for (;;) { d = new BigInteger(nBitLength, random); + + if (d.compareTo(TWO) < 0 || (d.compareTo(n) >= 0)) + { + continue; + } + + if (WNafUtil.getNafWeight(d) < minWeight) + { + continue; + } + + break; } - while (d.equals(ZERO) || (d.compareTo(n) >= 0)); - ECPoint Q = params.getG().multiply(d); + ECPoint Q = createBasePointMultiplier().multiply(params.getG(), d); return new AsymmetricCipherKeyPair( new ECPublicKeyParameters(Q, params), new ECPrivateKeyParameters(d, params)); } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java index 082a1c8..9a2239e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java @@ -10,6 +10,7 @@ import org.bouncycastle.crypto.digests.AndroidDigestFactory; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; /** * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2. @@ -116,7 +117,7 @@ public class PKCS5S2ParametersGenerator { keySize = keySize / 8; - byte[] dKey = generateDerivedKey(keySize); + byte[] dKey = Arrays.copyOfRange(generateDerivedKey(keySize), 0, keySize); return new KeyParameter(dKey, 0, keySize); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java index f58069d..f23f654 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java @@ -1,13 +1,15 @@ package org.bouncycastle.crypto.generators; +import java.math.BigInteger; + import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; import org.bouncycastle.crypto.KeyGenerationParameters; import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; - -import java.math.BigInteger; +import org.bouncycastle.math.Primes; +import org.bouncycastle.math.ec.WNafUtil; /** * an RSA key pair generator. @@ -18,16 +20,18 @@ public class RSAKeyPairGenerator private static final BigInteger ONE = BigInteger.valueOf(1); private RSAKeyGenerationParameters param; + private int iterations; - public void init( - KeyGenerationParameters param) + public void init(KeyGenerationParameters param) { this.param = (RSAKeyGenerationParameters)param; + this.iterations = getNumberOfIterations(this.param.getStrength(), this.param.getCertainty()); } public AsymmetricCipherKeyPair generateKeyPair() { - BigInteger p, q, n, d, e, pSub1, qSub1, phi; + AsymmetricCipherKeyPair result = null; + boolean done = false; // // p and q values should have a length of half the strength in bits @@ -35,113 +39,193 @@ public class RSAKeyPairGenerator int strength = param.getStrength(); int pbitlength = (strength + 1) / 2; int qbitlength = strength - pbitlength; - int mindiffbits = strength / 3; - - e = param.getPublicExponent(); - - // TODO Consider generating safe primes for p, q (see DHParametersHelper.generateSafePrimes) - // (then p-1 and q-1 will not consist of only small factors - see "Pollard's algorithm") + int mindiffbits = (strength / 2) - 100; - // - // generate p, prime and (p-1) relatively prime to e - // - for (;;) + if (mindiffbits < strength / 3) { - p = new BigInteger(pbitlength, 1, param.getRandom()); - - if (p.mod(e).equals(ONE)) - { - continue; - } - - if (!p.isProbablePrime(param.getCertainty())) - { - continue; - } - - if (e.gcd(p.subtract(ONE)).equals(ONE)) - { - break; - } + mindiffbits = strength / 3; } - // - // generate a modulus of the required length - // - for (;;) + int minWeight = strength >> 2; + + // d lower bound is 2^(strength / 2) + BigInteger dLowerBound = BigInteger.valueOf(2).pow(strength / 2); + // squared bound (sqrt(2)*2^(nlen/2-1))^2 + BigInteger squaredBound = ONE.shiftLeft(strength - 1); + // 2^(nlen/2 - 100) + BigInteger minDiff = ONE.shiftLeft(mindiffbits); + + while (!done) { - // generate q, prime and (q-1) relatively prime to e, - // and not equal to p + BigInteger p, q, n, d, e, pSub1, qSub1, gcd, lcm; + + e = param.getPublicExponent(); + + p = chooseRandomPrime(pbitlength, e, squaredBound); + + // + // generate a modulus of the required length // - for (;;) + for (; ; ) { - q = new BigInteger(qbitlength, 1, param.getRandom()); + q = chooseRandomPrime(qbitlength, e, squaredBound); - if (q.subtract(p).abs().bitLength() < mindiffbits) + // p and q should not be too close together (or equal!) + BigInteger diff = q.subtract(p).abs(); + if (diff.bitLength() < mindiffbits || diff.compareTo(minDiff) <= 0) { continue; } - - if (q.mod(e).equals(ONE)) + + // + // calculate the modulus + // + n = p.multiply(q); + + if (n.bitLength() != strength) { + // + // if we get here our primes aren't big enough, make the largest + // of the two p and try again + // + p = p.max(q); continue; } - - if (!q.isProbablePrime(param.getCertainty())) + + /* + * Require a minimum weight of the NAF representation, since low-weight composites may + * be weak against a version of the number-field-sieve for factoring. + * + * See "The number field sieve for integers of low weight", Oliver Schirokauer. + */ + if (WNafUtil.getNafWeight(n) < minWeight) { + p = chooseRandomPrime(pbitlength, e, squaredBound); continue; } - - if (e.gcd(q.subtract(ONE)).equals(ONE)) - { - break; - } + + break; } + if (p.compareTo(q) < 0) + { + gcd = p; + p = q; + q = gcd; + } + + pSub1 = p.subtract(ONE); + qSub1 = q.subtract(ONE); + gcd = pSub1.gcd(qSub1); + lcm = pSub1.divide(gcd).multiply(qSub1); + // - // calculate the modulus + // calculate the private exponent // - n = p.multiply(q); + d = e.modInverse(lcm); - if (n.bitLength() == param.getStrength()) + if (d.compareTo(dLowerBound) <= 0) { - break; - } + continue; + } + else + { + done = true; + } // - // if we get here our primes aren't big enough, make the largest - // of the two p and try again + // calculate the CRT factors // - p = p.max(q); + BigInteger dP, dQ, qInv; + + dP = d.remainder(pSub1); + dQ = d.remainder(qSub1); + qInv = q.modInverse(p); + + result = new AsymmetricCipherKeyPair( + new RSAKeyParameters(false, n, e), + new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv)); } - if (p.compareTo(q) < 0) + return result; + } + + /** + * Choose a random prime value for use with RSA + * + * @param bitlength the bit-length of the returned prime + * @param e the RSA public exponent + * @return A prime p, with (p-1) relatively prime to e + */ + protected BigInteger chooseRandomPrime(int bitlength, BigInteger e, BigInteger sqrdBound) + { + for (int i = 0; i != 5 * bitlength; i++) { - phi = p; - p = q; - q = phi; - } + BigInteger p = new BigInteger(bitlength, 1, param.getRandom()); - pSub1 = p.subtract(ONE); - qSub1 = q.subtract(ONE); - phi = pSub1.multiply(qSub1); + if (p.mod(e).equals(ONE)) + { + continue; + } - // - // calculate the private exponent - // - d = e.modInverse(phi); + if (p.multiply(p).compareTo(sqrdBound) < 0) + { + continue; + } - // - // calculate the CRT factors - // - BigInteger dP, dQ, qInv; + if (!isProbablePrime(p)) + { + continue; + } - dP = d.remainder(pSub1); - dQ = d.remainder(qSub1); - qInv = q.modInverse(p); + if (!e.gcd(p.subtract(ONE)).equals(ONE)) + { + continue; + } - return new AsymmetricCipherKeyPair( - new RSAKeyParameters(false, n, e), - new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv)); + return p; + } + + throw new IllegalStateException("unable to generate prime number for RSA key"); + } + + protected boolean isProbablePrime(BigInteger x) + { + /* + * Primes class for FIPS 186-4 C.3 primality checking + */ + return !Primes.hasAnySmallFactors(x) && Primes.isMRProbablePrime(x, param.getRandom(), iterations); + } + + private static int getNumberOfIterations(int bits, int certainty) + { + /* + * NOTE: We enforce a minimum 'certainty' of 100 for bits >= 1024 (else 80). Where the + * certainty is higher than the FIPS 186-4 tables (C.2/C.3) cater to, extra iterations + * are added at the "worst case rate" for the excess. + */ + if (bits >= 1536) + { + return certainty <= 100 ? 3 + : certainty <= 128 ? 4 + : 4 + (certainty - 128 + 1) / 2; + } + else if (bits >= 1024) + { + return certainty <= 100 ? 4 + : certainty <= 112 ? 5 + : 5 + (certainty - 112 + 1) / 2; + } + else if (bits >= 512) + { + return certainty <= 80 ? 5 + : certainty <= 100 ? 7 + : 7 + (certainty - 100 + 1) / 2; + } + else + { + return certainty <= 80 ? 40 + : 40 + (certainty - 80 + 1) / 2; + } } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java index 71b7595..fe46119 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java @@ -7,6 +7,16 @@ import org.bouncycastle.crypto.InvalidCipherTextException; /** * A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data. + *

    + * Implementations of this interface may operate in a packet mode (where all input data is buffered and + * processed dugin the call to {@link #doFinal(byte[], int)}), or in a streaming mode (where output data is + * incrementally produced with each call to {@link #processByte(byte, byte[], int)} or + * {@link #processBytes(byte[], int, int, byte[], int)}. + *

    + * This is important to consider during decryption: in a streaming mode, unauthenticated plaintext data + * may be output prior to the call to {@link #doFinal(byte[], int)} that results in an authentication + * failure. The higher level protocol utilising this cipher must ensure the plaintext data is handled + * appropriately until the end of data is reached and the entire ciphertext is authenticated. * @see org.bouncycastle.crypto.params.AEADParameters */ public interface AEADBlockCipher @@ -101,6 +111,11 @@ public interface AEADBlockCipher /** * return the size of the output buffer required for a processBytes * an input of len bytes. + *

    + * The returned size may be dependent on the initialisation of this cipher + * and may not be accurate once subsequent input data is processed - this method + * should be invoked immediately prior to input data being processed. + *

    * * @param len the length of the input. * @return the space required to accommodate a call to processBytes @@ -111,7 +126,12 @@ public interface AEADBlockCipher /** * return the size of the output buffer required for a processBytes plus a * doFinal with an input of len bytes. - * + *

    + * The returned size may be dependent on the initialisation of this cipher + * and may not be accurate once subsequent input data is processed - this method + * should be invoked immediately prior to a call to final processing of input data + * and a call to {@link #doFinal(byte[], int)}. + *

    * @param len the length of the input. * @return the space required to accommodate a call to processBytes and doFinal * with len bytes of input. diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java index fef51fd..088c728 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java @@ -7,6 +7,7 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.macs.CBCBlockCipherMac; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.ParametersWithIV; @@ -42,7 +43,7 @@ public class CCMBlockCipher this.cipher = c; this.blockSize = c.getBlockSize(); this.macBlock = new byte[blockSize]; - + if (blockSize != 16) { throw new IllegalArgumentException("cipher required with a block size of 16."); @@ -86,7 +87,7 @@ public class CCMBlockCipher } else { - throw new IllegalArgumentException("invalid parameters passed to CCM"); + throw new IllegalArgumentException("invalid parameters passed to CCM: " + params.getClass().getName()); } // NOTE: Very basic support for key re-use, but no performance gain from it @@ -99,7 +100,7 @@ public class CCMBlockCipher { throw new IllegalArgumentException("nonce must have length from 7 to 13 octets"); } - + reset(); } @@ -130,6 +131,10 @@ public class CCMBlockCipher public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff) throws DataLengthException, IllegalStateException { + if (in.length < (inOff + inLen)) + { + throw new DataLengthException("Input buffer too short"); + } data.write(in, inOff, inLen); return 0; @@ -155,15 +160,15 @@ public class CCMBlockCipher /** * Returns a byte array containing the mac calculated as part of the * last encrypt or decrypt operation. - * + * * @return the last mac calculated. */ public byte[] getMac() { byte[] mac = new byte[macSize]; - + System.arraycopy(macBlock, 0, mac, 0, mac.length); - + return mac; } @@ -267,12 +272,14 @@ public class CCMBlockCipher outputLen = inLen + macSize; if (output.length < (outputLen + outOff)) { - throw new DataLengthException("Output buffer too short."); + throw new OutputLengthException("Output buffer too short."); } calculateMac(in, inOff, inLen, macBlock); - ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0 + byte[] encMac = new byte[blockSize]; + + ctrCipher.processBlock(macBlock, 0, encMac, 0); // S0 while (inIndex < (inOff + inLen - blockSize)) // S1... { @@ -289,7 +296,7 @@ public class CCMBlockCipher System.arraycopy(block, 0, output, outIndex, inLen + inOff - inIndex); - System.arraycopy(macBlock, 0, output, outOff + inLen, macSize); + System.arraycopy(encMac, 0, output, outOff + inLen, macSize); } else { @@ -300,7 +307,7 @@ public class CCMBlockCipher outputLen = inLen - macSize; if (output.length < (outputLen + outOff)) { - throw new DataLengthException("Output buffer too short."); + throw new OutputLengthException("Output buffer too short."); } System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize); @@ -350,18 +357,18 @@ public class CCMBlockCipher // build b0 // byte[] b0 = new byte[16]; - + if (hasAssociatedText()) { b0[0] |= 0x40; } - + b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3; b0[0] |= ((15 - nonce.length) - 1) & 0x7; - + System.arraycopy(nonce, 0, b0, 1, nonce.length); - + int q = dataLen; int count = 1; while (q > 0) @@ -370,22 +377,22 @@ public class CCMBlockCipher q >>>= 8; count++; } - + cMac.update(b0, 0, b0.length); - + // // process associated text // if (hasAssociatedText()) { int extra; - + int textLength = getAssociatedTextLength(); if (textLength < ((1 << 16) - (1 << 8))) { cMac.update((byte)(textLength >> 8)); cMac.update((byte)textLength); - + extra = 2; } else // can't go any higher than 2^32 @@ -396,7 +403,7 @@ public class CCMBlockCipher cMac.update((byte)(textLength >> 16)); cMac.update((byte)(textLength >> 8)); cMac.update((byte)textLength); - + extra = 6; } @@ -418,7 +425,7 @@ public class CCMBlockCipher } } } - + // // add the text // diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java index a885169..6167d25 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java @@ -3,6 +3,7 @@ package org.bouncycastle.crypto.modes; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.Arrays; @@ -10,15 +11,17 @@ import org.bouncycastle.util.Arrays; * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher. */ public class CFBBlockCipher - implements BlockCipher + extends StreamBlockCipher { private byte[] IV; private byte[] cfbV; private byte[] cfbOutV; + private byte[] inBuf; private int blockSize; private BlockCipher cipher = null; private boolean encrypting; + private int byteCount; /** * Basic constructor. @@ -31,22 +34,15 @@ public class CFBBlockCipher BlockCipher cipher, int bitBlockSize) { + super(cipher); + this.cipher = cipher; this.blockSize = bitBlockSize / 8; this.IV = new byte[cipher.getBlockSize()]; this.cfbV = new byte[cipher.getBlockSize()]; this.cfbOutV = new byte[cipher.getBlockSize()]; - } - - /** - * return the underlying block cipher that we are wrapping. - * - * @return the underlying block cipher that we are wrapping. - */ - public BlockCipher getUnderlyingCipher() - { - return cipher; + this.inBuf = new byte[blockSize]; } /** @@ -117,6 +113,54 @@ public class CFBBlockCipher return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8); } + protected byte calculateByte(byte in) + throws DataLengthException, IllegalStateException + { + return (encrypting) ? encryptByte(in) : decryptByte(in); + } + + private byte encryptByte(byte in) + { + if (byteCount == 0) + { + cipher.processBlock(cfbV, 0, cfbOutV, 0); + } + + byte rv = (byte)(cfbOutV[byteCount] ^ in); + inBuf[byteCount++] = rv; + + if (byteCount == blockSize) + { + byteCount = 0; + + System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize); + System.arraycopy(inBuf, 0, cfbV, cfbV.length - blockSize, blockSize); + } + + return rv; + } + + private byte decryptByte(byte in) + { + if (byteCount == 0) + { + cipher.processBlock(cfbV, 0, cfbOutV, 0); + } + + inBuf[byteCount] = in; + byte rv = (byte)(cfbOutV[byteCount++] ^ in); + + if (byteCount == blockSize) + { + byteCount = 0; + + System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize); + System.arraycopy(inBuf, 0, cfbV, cfbV.length - blockSize, blockSize); + } + + return rv; + } + /** * return the block size we are operating at. * @@ -147,7 +191,9 @@ public class CFBBlockCipher int outOff) throws DataLengthException, IllegalStateException { - return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff); + processBytes(in, inOff, blockSize, out, outOff); + + return blockSize; } /** @@ -169,31 +215,7 @@ public class CFBBlockCipher int outOff) throws DataLengthException, IllegalStateException { - if ((inOff + blockSize) > in.length) - { - throw new DataLengthException("input buffer too short"); - } - - if ((outOff + blockSize) > out.length) - { - throw new DataLengthException("output buffer too short"); - } - - cipher.processBlock(cfbV, 0, cfbOutV, 0); - - // - // XOR the cfbV with the plaintext producing the ciphertext - // - for (int i = 0; i < blockSize; i++) - { - out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]); - } - - // - // change over the input block. - // - System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize); - System.arraycopy(out, outOff, cfbV, cfbV.length - blockSize, blockSize); + processBytes(in, inOff, blockSize, out, outOff); return blockSize; } @@ -217,31 +239,7 @@ public class CFBBlockCipher int outOff) throws DataLengthException, IllegalStateException { - if ((inOff + blockSize) > in.length) - { - throw new DataLengthException("input buffer too short"); - } - - if ((outOff + blockSize) > out.length) - { - throw new DataLengthException("output buffer too short"); - } - - cipher.processBlock(cfbV, 0, cfbOutV, 0); - - // - // change over the input block. - // - System.arraycopy(cfbV, blockSize, cfbV, 0, cfbV.length - blockSize); - System.arraycopy(in, inOff, cfbV, cfbV.length - blockSize, blockSize); - - // - // XOR the cfbV with the ciphertext producing the plaintext - // - for (int i = 0; i < blockSize; i++) - { - out[outOff + i] = (byte)(cfbOutV[i] ^ in[inOff + i]); - } + processBytes(in, inOff, blockSize, out, outOff); return blockSize; } @@ -263,6 +261,8 @@ public class CFBBlockCipher public void reset() { System.arraycopy(IV, 0, cfbV, 0, IV.length); + Arrays.fill(inBuf, (byte)0); + byteCount = 0; cipher.reset(); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java index 5388b40..64b076d 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java @@ -4,6 +4,7 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.StreamBlockCipher; /** * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to @@ -22,9 +23,8 @@ public class CTSBlockCipher public CTSBlockCipher( BlockCipher cipher) { - if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher) || (cipher instanceof SICBlockCipher)) + if (cipher instanceof StreamBlockCipher) { - // TODO: This is broken - need to introduce marker interface to differentiate block cipher primitive from mode? throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers"); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java index 9e617ec..ed89ef7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java @@ -4,15 +4,17 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.modes.gcm.GCMExponentiator; import org.bouncycastle.crypto.modes.gcm.GCMMultiplier; +import org.bouncycastle.crypto.modes.gcm.GCMUtil; import org.bouncycastle.crypto.modes.gcm.Tables1kGCMExponentiator; import org.bouncycastle.crypto.modes.gcm.Tables8kGCMMultiplier; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; /** * Implements the Galois/Counter mode (GCM) detailed in @@ -22,8 +24,13 @@ public class GCMBlockCipher implements AEADBlockCipher { private static final int BLOCK_SIZE = 16; + // BEGIN android-added + // 2^36-32 : limitation imposed by NIST GCM as otherwise the counter is wrapped and it can leak + // plaintext and authentication key + private static final long MAX_INPUT_SIZE = 68719476704L; + // END android-added - // not final due to a compiler bug + // not final due to a compiler bug private BlockCipher cipher; private GCMMultiplier multiplier; private GCMExponentiator exp; @@ -81,6 +88,10 @@ public class GCMBlockCipher return cipher.getAlgorithmName() + "/GCM"; } + /** + * NOTE: MAC sizes from 32 bits to 128 bits (must be a multiple of 8) are supported. The default is 128 bits. + * Sizes less than 96 are not recommended, but are supported for specialized applications. + */ public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException { @@ -97,12 +108,12 @@ public class GCMBlockCipher initialAssociatedText = param.getAssociatedText(); int macSizeBits = param.getMacSize(); - if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0) + if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0) { throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits); } - macSize = macSizeBits / 8; + macSize = macSizeBits / 8; keyParam = param.getKey(); } else if (params instanceof ParametersWithIV) @@ -119,7 +130,7 @@ public class GCMBlockCipher throw new IllegalArgumentException("invalid parameters passed to GCM"); } - int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize); + int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize); this.bufBlock = new byte[bufLength]; if (nonce == null || nonce.length < 1) @@ -127,9 +138,7 @@ public class GCMBlockCipher throw new IllegalArgumentException("IV must be at least 1 byte"); } - // TODO This should be configurable by init parameters - // (but must be 16 if nonce length not 12) (BLOCK_SIZE?) -// this.tagLength = 16; + // TODO Restrict macSize to 16 if nonce length not 12? // Cipher always used in forward mode // if keyParam is null we're reusing the last key. @@ -144,6 +153,10 @@ public class GCMBlockCipher multiplier.init(H); exp = null; } + else if (this.H == null) + { + throw new IllegalArgumentException("Key must be specified in initial init"); + } this.J0 = new byte[BLOCK_SIZE]; @@ -188,12 +201,20 @@ public class GCMBlockCipher if (forEncryption) { - return totalData + macSize; + return totalData + macSize; } return totalData < macSize ? 0 : totalData - macSize; } + // BEGIN android-added + /** Helper used to ensure that {@link #MAX_INPUT_SIZE} is not exceeded. */ + private long getTotalInputSizeAfterNewInput(int newInputLen) + { + return totalLength + newInputLen + bufOff; + } + // END android-added + public int getUpdateOutputSize(int len) { int totalData = len + bufOff; @@ -210,6 +231,11 @@ public class GCMBlockCipher public void processAADByte(byte in) { + // BEGIN android-added + if (getTotalInputSizeAfterNewInput(1) > MAX_INPUT_SIZE) { + throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes"); + } + // END android-added atBlock[atBlockPos] = in; if (++atBlockPos == BLOCK_SIZE) { @@ -222,6 +248,11 @@ public class GCMBlockCipher public void processAADBytes(byte[] in, int inOff, int len) { + // BEGIN android-added + if (getTotalInputSizeAfterNewInput(len) > MAX_INPUT_SIZE) { + throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes"); + } + // END android-added for (int i = 0; i < len; ++i) { atBlock[atBlockPos] = in[inOff + i]; @@ -259,6 +290,11 @@ public class GCMBlockCipher public int processByte(byte in, byte[] out, int outOff) throws DataLengthException { + // BEGIN android-added + if (getTotalInputSizeAfterNewInput(1) > MAX_INPUT_SIZE) { + throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes"); + } + // END android-added bufBlock[bufOff] = in; if (++bufOff == bufBlock.length) { @@ -271,6 +307,15 @@ public class GCMBlockCipher public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException { + // BEGIN android-added + if (getTotalInputSizeAfterNewInput(len) > MAX_INPUT_SIZE) { + throw new DataLengthException("Input exceeded " + MAX_INPUT_SIZE + " bytes"); + } + // END android-added + if (in.length < (inOff + len)) + { + throw new DataLengthException("Input buffer too short"); + } int resultLen = 0; for (int i = 0; i < len; ++i) @@ -288,6 +333,10 @@ public class GCMBlockCipher private void outputBlock(byte[] output, int offset) { + if (output.length < (offset + BLOCK_SIZE)) + { + throw new OutputLengthException("Output buffer too short"); + } if (totalLength == 0) { initCipher(); @@ -313,13 +362,26 @@ public class GCMBlockCipher } int extra = bufOff; - if (!forEncryption) + + if (forEncryption) + { + if (out.length < (outOff + extra + macSize)) + { + throw new OutputLengthException("Output buffer too short"); + } + } + else { if (extra < macSize) { throw new InvalidCipherTextException("data too short"); } extra -= macSize; + + if (out.length < (outOff + extra)) + { + throw new OutputLengthException("Output buffer too short"); + } } if (extra > 0) @@ -347,7 +409,7 @@ public class GCMBlockCipher // Find the difference between the AAD hashes if (atLengthPre > 0) { - xor(S_at, S_atPre); + GCMUtil.xor(S_at, S_atPre); } // Number of cipher-text blocks produced @@ -363,10 +425,10 @@ public class GCMBlockCipher exp.exponentiateX(c, H_c); // Carry the difference forward - multiply(S_at, H_c); + GCMUtil.multiply(S_at, H_c); // Adjust the current hash - xor(S, S_at); + GCMUtil.xor(S, S_at); } // Final gHASH @@ -376,11 +438,10 @@ public class GCMBlockCipher gHASHBlock(S, X); - // TODO Fix this if tagLength becomes configurable // T = MSBt(GCTRk(J0,S)) byte[] tag = new byte[BLOCK_SIZE]; cipher.processBlock(J0, 0, tag, 0); - xor(tag, S); + GCMUtil.xor(tag, S); int resultLen = extra; @@ -451,7 +512,7 @@ public class GCMBlockCipher { byte[] tmp = getNextCounterBlock(); - xor(tmp, block); + GCMUtil.xor(tmp, block); System.arraycopy(tmp, 0, out, outOff, BLOCK_SIZE); gHASHBlock(S, forEncryption ? tmp : block); @@ -463,7 +524,7 @@ public class GCMBlockCipher { byte[] tmp = getNextCounterBlock(); - xor(tmp, buf, off, len); + GCMUtil.xor(tmp, buf, off, len); System.arraycopy(tmp, 0, out, outOff, len); gHASHPartial(S, forEncryption ? tmp : buf, 0, len); @@ -482,93 +543,27 @@ public class GCMBlockCipher private void gHASHBlock(byte[] Y, byte[] b) { - xor(Y, b); + GCMUtil.xor(Y, b); multiplier.multiplyH(Y); } private void gHASHPartial(byte[] Y, byte[] b, int off, int len) { - xor(Y, b, off, len); + GCMUtil.xor(Y, b, off, len); multiplier.multiplyH(Y); } private byte[] getNextCounterBlock() { - for (int i = 15; i >= 12; --i) - { - byte b = (byte)((counter[i] + 1) & 0xff); - counter[i] = b; - - if (b != 0) - { - break; - } - } + int c = 1; + c += counter[15] & 0xFF; counter[15] = (byte)c; c >>>= 8; + c += counter[14] & 0xFF; counter[14] = (byte)c; c >>>= 8; + c += counter[13] & 0xFF; counter[13] = (byte)c; c >>>= 8; + c += counter[12] & 0xFF; counter[12] = (byte)c; byte[] tmp = new byte[BLOCK_SIZE]; // TODO Sure would be nice if ciphers could operate on int[] cipher.processBlock(counter, 0, tmp, 0); return tmp; } - - private static void multiply(byte[] block, byte[] val) - { - byte[] tmp = Arrays.clone(block); - byte[] c = new byte[16]; - - for (int i = 0; i < 16; ++i) - { - byte bits = val[i]; - for (int j = 7; j >= 0; --j) - { - if ((bits & (1 << j)) != 0) - { - xor(c, tmp); - } - - boolean lsb = (tmp[15] & 1) != 0; - shiftRight(tmp); - if (lsb) - { - // R = new byte[]{ 0xe1, ... }; -// xor(v, R); - tmp[0] ^= (byte)0xe1; - } - } - } - - System.arraycopy(c, 0, block, 0, 16); - } - - private static void shiftRight(byte[] block) - { - int i = 0; - int bit = 0; - for (;;) - { - int b = block[i] & 0xff; - block[i] = (byte) ((b >>> 1) | bit); - if (++i == 16) - { - break; - } - bit = (b & 1) << 7; - } - } - - private static void xor(byte[] block, byte[] val) - { - for (int i = 15; i >= 0; --i) - { - block[i] ^= val[i]; - } - } - - private static void xor(byte[] block, byte[] val, int off, int len) - { - while (len-- > 0) - { - block[len] ^= val[off + len]; - } - } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java index 5297698..d9ff428 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java @@ -3,14 +3,16 @@ package org.bouncycastle.crypto.modes; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; /** * implements a Output-FeedBack (OFB) mode on top of a simple cipher. */ public class OFBBlockCipher - implements BlockCipher + extends StreamBlockCipher { + private int byteCount; private byte[] IV; private byte[] ofbV; private byte[] ofbOutV; @@ -29,6 +31,8 @@ public class OFBBlockCipher BlockCipher cipher, int blockSize) { + super(cipher); + this.cipher = cipher; this.blockSize = blockSize / 8; @@ -37,16 +41,6 @@ public class OFBBlockCipher this.ofbOutV = new byte[cipher.getBlockSize()]; } - /** - * return the underlying block cipher that we are wrapping. - * - * @return the underlying block cipher that we are wrapping. - */ - public BlockCipher getUnderlyingCipher() - { - return cipher; - } - /** * Initialise the cipher and, possibly, the initialisation vector (IV). * If an IV isn't passed as part of the parameter, the IV will be all zeros. @@ -113,7 +107,7 @@ public class OFBBlockCipher return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8); } - + /** * return the block size we are operating at (in bytes). * @@ -144,32 +138,7 @@ public class OFBBlockCipher int outOff) throws DataLengthException, IllegalStateException { - if ((inOff + blockSize) > in.length) - { - throw new DataLengthException("input buffer too short"); - } - - if ((outOff + blockSize) > out.length) - { - throw new DataLengthException("output buffer too short"); - } - - cipher.processBlock(ofbV, 0, ofbOutV, 0); - - // - // XOR the ofbV with the plaintext producing the cipher text (and - // the next input block). - // - for (int i = 0; i < blockSize; i++) - { - out[outOff + i] = (byte)(ofbOutV[i] ^ in[inOff + i]); - } - - // - // change over the input block. - // - System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize); - System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize); + processBytes(in, inOff, blockSize, out, outOff); return blockSize; } @@ -181,7 +150,29 @@ public class OFBBlockCipher public void reset() { System.arraycopy(IV, 0, ofbV, 0, IV.length); + byteCount = 0; cipher.reset(); } + + protected byte calculateByte(byte in) + throws DataLengthException, IllegalStateException + { + if (byteCount == 0) + { + cipher.processBlock(ofbV, 0, ofbOutV, 0); + } + + byte rv = (byte)(ofbOutV[byteCount++] ^ in); + + if (byteCount == blockSize) + { + byteCount = 0; + + System.arraycopy(ofbV, blockSize, ofbV, 0, ofbV.length - blockSize); + System.arraycopy(ofbOutV, 0, ofbV, ofbV.length - blockSize, blockSize); + } + + return rv; + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java index da8c4ae..ae4256f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java @@ -3,22 +3,27 @@ package org.bouncycastle.crypto.modes; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.SkippingStreamCipher; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; /** * Implements the Segmented Integer Counter (SIC) mode on top of a simple * block cipher. This mode is also known as CTR mode. */ public class SICBlockCipher - implements BlockCipher + extends StreamBlockCipher + implements SkippingStreamCipher { private final BlockCipher cipher; private final int blockSize; - + private byte[] IV; private byte[] counter; private byte[] counterOut; - + private int byteCount; /** * Basic constructor. @@ -27,25 +32,16 @@ public class SICBlockCipher */ public SICBlockCipher(BlockCipher c) { + super(c); + this.cipher = c; this.blockSize = cipher.getBlockSize(); this.IV = new byte[blockSize]; this.counter = new byte[blockSize]; this.counterOut = new byte[blockSize]; + this.byteCount = 0; } - - /** - * return the underlying block cipher that we are wrapping. - * - * @return the underlying block cipher that we are wrapping. - */ - public BlockCipher getUnderlyingCipher() - { - return cipher; - } - - public void init( boolean forEncryption, //ignored by this CTR mode CipherParameters params) @@ -53,21 +49,32 @@ public class SICBlockCipher { if (params instanceof ParametersWithIV) { - ParametersWithIV ivParam = (ParametersWithIV)params; - byte[] iv = ivParam.getIV(); - System.arraycopy(iv, 0, IV, 0, IV.length); + ParametersWithIV ivParam = (ParametersWithIV)params; + this.IV = Arrays.clone(ivParam.getIV()); - reset(); + if (blockSize < IV.length) + { + throw new IllegalArgumentException("CTR/SIC mode requires IV no greater than: " + blockSize + " bytes."); + } - // if null it's an IV changed only. - if (ivParam.getParameters() != null) - { - cipher.init(true, ivParam.getParameters()); - } + int maxCounterSize = (8 > blockSize / 2) ? blockSize / 2 : 8; + + if (blockSize - IV.length > maxCounterSize) + { + throw new IllegalArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes."); + } + + // if null it's an IV changed only. + if (ivParam.getParameters() != null) + { + cipher.init(true, ivParam.getParameters()); + } + + reset(); } else { - throw new IllegalArgumentException("SIC mode requires ParametersWithIV"); + throw new IllegalArgumentException("CTR/SIC mode requires ParametersWithIV"); } } @@ -81,33 +88,203 @@ public class SICBlockCipher return cipher.getBlockSize(); } - public int processBlock(byte[] in, int inOff, byte[] out, int outOff) throws DataLengthException, IllegalStateException { - cipher.processBlock(counter, 0, counterOut, 0); + processBytes(in, inOff, blockSize, out, outOff); - // - // XOR the counterOut with the plaintext producing the cipher text - // - for (int i = 0; i < counterOut.length; i++) + return blockSize; + } + + protected byte calculateByte(byte in) + throws DataLengthException, IllegalStateException + { + if (byteCount == 0) { - out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]); + cipher.processBlock(counter, 0, counterOut, 0); + + return (byte)(counterOut[byteCount++] ^ in); } - // increment counter by 1. - for (int i = counter.length - 1; i >= 0 && ++counter[i] == 0; i--) + byte rv = (byte)(counterOut[byteCount++] ^ in); + + if (byteCount == counter.length) + { + byteCount = 0; + + incrementCounterAt(0); + + checkCounter(); + } + + return rv; + } + + private void checkCounter() + { + // if the IV is the same as the blocksize we assume the user knows what they are doing + if (IV.length < blockSize) { - ; // do nothing - pre-increment and test for 0 in counter does the job. + for (int i = 0; i != IV.length; i++) + { + if (counter[i] != IV[i]) + { + throw new IllegalStateException("Counter in CTR/SIC mode out of range."); + } + } } + } - return counter.length; + private void incrementCounterAt(int pos) + { + int i = counter.length - pos; + while (--i >= 0) + { + if (++counter[i] != 0) + { + break; + } + } } + private void incrementCounter(int offSet) + { + byte old = counter[counter.length - 1]; + + counter[counter.length - 1] += offSet; + + if (old != 0 && counter[counter.length - 1] < old) + { + incrementCounterAt(1); + } + } + + private void decrementCounterAt(int pos) + { + int i = counter.length - pos; + while (--i >= 0) + { + if (--counter[i] != -1) + { + return; + } + } + } + + private void adjustCounter(long n) + { + if (n >= 0) + { + long numBlocks = (n + byteCount) / blockSize; + + long rem = numBlocks; + if (rem > 255) + { + for (int i = 5; i >= 1; i--) + { + long diff = 1L << (8 * i); + while (rem >= diff) + { + incrementCounterAt(i); + rem -= diff; + } + } + } + + incrementCounter((int)rem); + + byteCount = (int)((n + byteCount) - (blockSize * numBlocks)); + } + else + { + long numBlocks = (-n - byteCount) / blockSize; + + long rem = numBlocks; + if (rem > 255) + { + for (int i = 5; i >= 1; i--) + { + long diff = 1L << (8 * i); + while (rem > diff) + { + decrementCounterAt(i); + rem -= diff; + } + } + } + + for (long i = 0; i != rem; i++) + { + decrementCounterAt(0); + } + + int gap = (int)(byteCount + n + (blockSize * numBlocks)); + + if (gap >= 0) + { + byteCount = 0; + } + else + { + decrementCounterAt(0); + byteCount = blockSize + gap; + } + } + } public void reset() { - System.arraycopy(IV, 0, counter, 0, counter.length); + Arrays.fill(counter, (byte)0); + System.arraycopy(IV, 0, counter, 0, IV.length); cipher.reset(); + this.byteCount = 0; + } + + public long skip(long numberOfBytes) + { + adjustCounter(numberOfBytes); + + checkCounter(); + + cipher.processBlock(counter, 0, counterOut, 0); + + return numberOfBytes; + } + + public long seekTo(long position) + { + reset(); + + return skip(position); + } + + public long getPosition() + { + byte[] res = new byte[counter.length]; + + System.arraycopy(counter, 0, res, 0, res.length); + + for (int i = res.length - 1; i >= 1; i--) + { + int v; + if (i < IV.length) + { + v = (res[i] & 0xff) - (IV[i] & 0xff); + } + else + { + v = (res[i] & 0xff); + } + + if (v < 0) + { + res[i - 1]--; + v += 256; + } + + res[i] = (byte)v; + } + + return Pack.bigEndianToLong(res, res.length - 8) * blockSize + byteCount; } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java index 3031a44..f08f71f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java @@ -1,13 +1,11 @@ package org.bouncycastle.crypto.modes.gcm; -import org.bouncycastle.crypto.util.Pack; -import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; -abstract class GCMUtil +public abstract class GCMUtil { private static final int E1 = 0xe1000000; - private static final byte E1B = (byte)0xe1; - private static final long E1L = (E1 & 0xFFFFFFFFL) << 24; + private static final long E1L = (E1 & 0xFFFFFFFFL) << 32; private static int[] generateLookup() { @@ -31,170 +29,151 @@ abstract class GCMUtil private static final int[] LOOKUP = generateLookup(); - static byte[] oneAsBytes() + public static byte[] oneAsBytes() { byte[] tmp = new byte[16]; tmp[0] = (byte)0x80; return tmp; } - static int[] oneAsInts() + public static int[] oneAsInts() { int[] tmp = new int[4]; tmp[0] = 1 << 31; return tmp; } - static long[] oneAsLongs() + public static long[] oneAsLongs() { long[] tmp = new long[2]; tmp[0] = 1L << 63; return tmp; } - static byte[] asBytes(int[] x) + public static byte[] asBytes(int[] x) { byte[] z = new byte[16]; Pack.intToBigEndian(x, z, 0); return z; } - static void asBytes(int[] x, byte[] z) + public static void asBytes(int[] x, byte[] z) { Pack.intToBigEndian(x, z, 0); } - static byte[] asBytes(long[] x) + public static byte[] asBytes(long[] x) { byte[] z = new byte[16]; Pack.longToBigEndian(x, z, 0); return z; } - static void asBytes(long[] x, byte[] z) + public static void asBytes(long[] x, byte[] z) { Pack.longToBigEndian(x, z, 0); } - static int[] asInts(byte[] x) + public static int[] asInts(byte[] x) { int[] z = new int[4]; Pack.bigEndianToInt(x, 0, z); return z; } - static void asInts(byte[] x, int[] z) + public static void asInts(byte[] x, int[] z) { Pack.bigEndianToInt(x, 0, z); } - static long[] asLongs(byte[] x) + public static long[] asLongs(byte[] x) { long[] z = new long[2]; Pack.bigEndianToLong(x, 0, z); return z; } - static void asLongs(byte[] x, long[] z) + public static void asLongs(byte[] x, long[] z) { Pack.bigEndianToLong(x, 0, z); } - static void multiply(byte[] x, byte[] y) + public static void multiply(byte[] x, byte[] y) { - byte[] r0 = Arrays.clone(x); - byte[] r1 = new byte[16]; - - for (int i = 0; i < 16; ++i) - { - byte bits = y[i]; - for (int j = 7; j >= 0; --j) - { - if ((bits & (1 << j)) != 0) - { - xor(r1, r0); - } - - if (shiftRight(r0) != 0) - { - r0[0] ^= E1B; - } - } - } - - System.arraycopy(r1, 0, x, 0, 16); + int[] t1 = GCMUtil.asInts(x); + int[] t2 = GCMUtil.asInts(y); + GCMUtil.multiply(t1, t2); + GCMUtil.asBytes(t1, x); } - static void multiply(int[] x, int[] y) + public static void multiply(int[] x, int[] y) { - int[] r0 = Arrays.clone(x); - int[] r1 = new int[4]; - + int r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3]; + int r10 = 0, r11 = 0, r12 = 0, r13 = 0; + for (int i = 0; i < 4; ++i) { int bits = y[i]; - for (int j = 31; j >= 0; --j) + for (int j = 0; j < 32; ++j) { - if ((bits & (1 << j)) != 0) - { - xor(r1, r0); - } - - if (shiftRight(r0) != 0) - { - r0[0] ^= E1; - } + int m1 = bits >> 31; bits <<= 1; + r10 ^= (r00 & m1); + r11 ^= (r01 & m1); + r12 ^= (r02 & m1); + r13 ^= (r03 & m1); + + int m2 = (r03 << 31) >> 8; + r03 = (r03 >>> 1) | (r02 << 31); + r02 = (r02 >>> 1) | (r01 << 31); + r01 = (r01 >>> 1) | (r00 << 31); + r00 = (r00 >>> 1) ^ (m2 & E1); } } - System.arraycopy(r1, 0, x, 0, 4); + x[0] = r10; + x[1] = r11; + x[2] = r12; + x[3] = r13; } - static void multiply(long[] x, long[] y) + public static void multiply(long[] x, long[] y) { - long[] r0 = new long[]{ x[0], x[1] }; - long[] r1 = new long[2]; + long r00 = x[0], r01 = x[1], r10 = 0, r11 = 0; for (int i = 0; i < 2; ++i) { long bits = y[i]; - for (int j = 63; j >= 0; --j) + for (int j = 0; j < 64; ++j) { - if ((bits & (1L << j)) != 0) - { - xor(r1, r0); - } + long m1 = bits >> 63; bits <<= 1; + r10 ^= (r00 & m1); + r11 ^= (r01 & m1); - if (shiftRight(r0) != 0) - { - r0[0] ^= E1L; - } + long m2 = (r01 << 63) >> 8; + r01 = (r01 >>> 1) | (r00 << 63); + r00 = (r00 >>> 1) ^ (m2 & E1L); } } - x[0] = r1[0]; - x[1] = r1[1]; + x[0] = r10; + x[1] = r11; } // P is the value with only bit i=1 set - static void multiplyP(int[] x) + public static void multiplyP(int[] x) { - if (shiftRight(x) != 0) - { - x[0] ^= E1; - } + int m = shiftRight(x) >> 8; + x[0] ^= (m & E1); } - static void multiplyP(int[] x, int[] y) + public static void multiplyP(int[] x, int[] z) { - if (shiftRight(x, y) != 0) - { - y[0] ^= E1; - } + int m = shiftRight(x, z) >> 8; + z[0] ^= (m & E1); } // P is the value with only bit i=1 set - static void multiplyP8(int[] x) + public static void multiplyP8(int[] x) { // for (int i = 8; i != 0; --i) // { @@ -205,74 +184,12 @@ abstract class GCMUtil x[0] ^= LOOKUP[c >>> 24]; } - static void multiplyP8(int[] x, int[] y) + public static void multiplyP8(int[] x, int[] y) { int c = shiftRightN(x, 8, y); y[0] ^= LOOKUP[c >>> 24]; } - static byte shiftRight(byte[] x) - { -// int c = 0; -// for (int i = 0; i < 16; ++i) -// { -// int b = x[i] & 0xff; -// x[i] = (byte)((b >>> 1) | c); -// c = (b & 1) << 7; -// } -// return (byte)c; - - int i = 0, c = 0; - do - { - int b = x[i] & 0xff; - x[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - x[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - x[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - x[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - } - while (i < 16); - return (byte)c; - } - - static byte shiftRight(byte[] x, byte[] z) - { -// int c = 0; -// for (int i = 0; i < 16; ++i) -// { -// int b = x[i] & 0xff; -// z[i] = (byte) ((b >>> 1) | c); -// c = (b & 1) << 7; -// } -// return (byte) c; - - int i = 0, c = 0; - do - { - int b = x[i] & 0xff; - z[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - z[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - z[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - b = x[i] & 0xff; - z[i++] = (byte)((b >>> 1) | c); - c = (b & 1) << 7; - } - while (i < 16); - return (byte)c; - } - static int shiftRight(int[] x) { // int c = 0; @@ -393,7 +310,7 @@ abstract class GCMUtil return b << nInv; } - static void xor(byte[] x, byte[] y) + public static void xor(byte[] x, byte[] y) { int i = 0; do @@ -406,15 +323,15 @@ abstract class GCMUtil while (i < 16); } - static void xor(byte[] x, byte[] y, int yOff, int yLen) + public static void xor(byte[] x, byte[] y, int yOff, int yLen) { - while (yLen-- > 0) + while (--yLen >= 0) { x[yLen] ^= y[yOff + yLen]; } } - static void xor(byte[] x, byte[] y, byte[] z) + public static void xor(byte[] x, byte[] y, byte[] z) { int i = 0; do @@ -427,7 +344,7 @@ abstract class GCMUtil while (i < 16); } - static void xor(int[] x, int[] y) + public static void xor(int[] x, int[] y) { x[0] ^= y[0]; x[1] ^= y[1]; @@ -435,7 +352,7 @@ abstract class GCMUtil x[3] ^= y[3]; } - static void xor(int[] x, int[] y, int[] z) + public static void xor(int[] x, int[] y, int[] z) { z[0] = x[0] ^ y[0]; z[1] = x[1] ^ y[1]; @@ -443,13 +360,13 @@ abstract class GCMUtil z[3] = x[3] ^ y[3]; } - static void xor(long[] x, long[] y) + public static void xor(long[] x, long[] y) { x[0] ^= y[0]; x[1] ^= y[1]; } - static void xor(long[] x, long[] y, long[] z) + public static void xor(long[] x, long[] y, long[] z) { z[0] = x[0] ^ y[0]; z[1] = x[1] ^ y[1]; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java index 8535db5..69c1dce 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java @@ -1,7 +1,7 @@ package org.bouncycastle.crypto.modes.gcm; -import org.bouncycastle.crypto.util.Pack; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; public class Tables8kGCMMultiplier implements GCMMultiplier { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java index 93b149f..8b30398 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java @@ -57,18 +57,19 @@ public class PKCS7Padding throws InvalidCipherTextException { int count = in[in.length - 1] & 0xff; + byte countAsbyte = (byte)count; - if (count > in.length || count == 0) + // constant time version + boolean failed = (count > in.length | count == 0); + + for (int i = 0; i < in.length; i++) { - throw new InvalidCipherTextException("pad block corrupted"); + failed |= (in.length - i <= count) & (in[i] != countAsbyte); } - - for (int i = 1; i <= count; i++) + + if (failed) { - if (in[in.length - i] != count) - { - throw new InvalidCipherTextException("pad block corrupted"); - } + throw new InvalidCipherTextException("pad block corrupted"); } return count; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java index ee3fd60..d5928f7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java @@ -125,7 +125,7 @@ public class PaddedBufferedBlockCipher if (leftOver == 0) { - return total - buf.length; + return Math.max(0, total - buf.length); } return total - leftOver; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java index 3a4bbfc..5b2d0d4 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java @@ -54,4 +54,53 @@ public class DESedeParameters { return isWeakKey(key, offset, key.length - offset); } + + /** + * return true if the passed in key is a real 2/3 part DES-EDE key. + * + * @param key bytes making up the key + * @param offset offset into the byte array the key starts at + */ + public static boolean isRealEDEKey(byte[] key, int offset) + { + return key.length == 16 ? isReal2Key(key, offset) : isReal3Key(key, offset); + } + + /** + * return true if the passed in key is a real 2 part DES-EDE key. + * + * @param key bytes making up the key + * @param offset offset into the byte array the key starts at + */ + public static boolean isReal2Key(byte[] key, int offset) + { + boolean isValid = false; + for (int i = offset; i != offset + 8; i++) + { + if (key[i] != key[i + 8]) + { + isValid = true; + } + } + + return isValid; + } + + /** + * return true if the passed in key is a real 3 part DES-EDE key. + * + * @param key bytes making up the key + * @param offset offset into the byte array the key starts at + */ + public static boolean isReal3Key(byte[] key, int offset) + { + boolean diff12 = false, diff13 = false, diff23 = false; + for (int i = offset; i != offset + 8; i++) + { + diff12 |= (key[i] != key[i + 8]); + diff13 |= (key[i] != key[i + 16]); + diff23 |= (key[i + 8] != key[i + 16]); + } + return diff12 && diff13 && diff23; + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java index b679287..fec6dfd 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java @@ -84,8 +84,7 @@ public class DHParameters { if (l != 0) { - BigInteger bigL = BigInteger.valueOf(2L ^ (l - 1)); - if (bigL.compareTo(p) == 1) + if (l > p.bitLength()) { throw new IllegalArgumentException("when l value specified, it must satisfy 2^(l-1) <= p"); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java new file mode 100644 index 0000000..5b694be --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/ECNamedDomainParameters.java @@ -0,0 +1,35 @@ +package org.bouncycastle.crypto.params; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; + +public class ECNamedDomainParameters + extends ECDomainParameters +{ + private ASN1ObjectIdentifier name; + + public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n) + { + this(name, curve, G, n, null, null); + } + + public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n, BigInteger h) + { + this(name, curve, G, n, h, null); + } + + public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECCurve curve, ECPoint G, BigInteger n, BigInteger h, byte[] seed) + { + super(curve, G, n, h, seed); + + this.name = name; + } + + public ASN1ObjectIdentifier getName() + { + return name; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/KDFParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/KDFParameters.java new file mode 100644 index 0000000..f3bac64 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/KDFParameters.java @@ -0,0 +1,31 @@ +package org.bouncycastle.crypto.params; + +import org.bouncycastle.crypto.DerivationParameters; + +/** + * parameters for Key derivation functions for IEEE P1363a + */ +public class KDFParameters + implements DerivationParameters +{ + byte[] iv; + byte[] shared; + + public KDFParameters( + byte[] shared, + byte[] iv) + { + this.shared = shared; + this.iv = iv; + } + + public byte[] getSharedSecret() + { + return shared; + } + + public byte[] getIV() + { + return iv; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java index dc33ec5..ea98de2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java @@ -1,11 +1,8 @@ package org.bouncycastle.crypto.params; -import org.bouncycastle.crypto.CipherParameters; - public class RC2Parameters - implements CipherParameters + extends KeyParameter { - private byte[] key; private int bits; public RC2Parameters( @@ -18,15 +15,8 @@ public class RC2Parameters byte[] key, int bits) { - this.key = new byte[key.length]; + super(key); this.bits = bits; - - System.arraycopy(key, 0, this.key, 0, key.length); - } - - public byte[] getKey() - { - return key; } public int getEffectiveKeyBits() diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java index 292c408..44f838b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java @@ -45,18 +45,19 @@ public class DSASigner boolean forSigning, CipherParameters param) { + SecureRandom providedRandom = null; + if (forSigning) { if (param instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)param; + ParametersWithRandom rParam = (ParametersWithRandom)param; - this.random = rParam.getRandom(); this.key = (DSAPrivateKeyParameters)rParam.getParameters(); + providedRandom = rParam.getRandom(); } else { - this.random = new SecureRandom(); this.key = (DSAPrivateKeyParameters)param; } } @@ -64,6 +65,8 @@ public class DSASigner { this.key = (DSAPublicKeyParameters)param; } + + this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom); } /** @@ -77,32 +80,28 @@ public class DSASigner byte[] message) { DSAParameters params = key.getParameters(); - BigInteger m = calculateE(params.getQ(), message); + BigInteger q = params.getQ(); + BigInteger m = calculateE(q, message); + BigInteger x = ((DSAPrivateKeyParameters)key).getX(); if (kCalculator.isDeterministic()) { - kCalculator.init(params.getQ(), ((DSAPrivateKeyParameters)key).getX(), message); + kCalculator.init(q, x, message); } else { - kCalculator.init(params.getQ(), random); + kCalculator.init(q, random); } BigInteger k = kCalculator.nextK(); - BigInteger r = params.getG().modPow(k, params.getP()).mod(params.getQ()); - - k = k.modInverse(params.getQ()).multiply( - m.add(((DSAPrivateKeyParameters)key).getX().multiply(r))); - - BigInteger s = k.mod(params.getQ()); + BigInteger r = params.getG().modPow(k, params.getP()).mod(q); - BigInteger[] res = new BigInteger[2]; + k = k.modInverse(q).multiply(m.add(x.multiply(r))); - res[0] = r; - res[1] = s; + BigInteger s = k.mod(q); - return res; + return new BigInteger[]{ r, s }; } /** @@ -116,28 +115,30 @@ public class DSASigner BigInteger s) { DSAParameters params = key.getParameters(); - BigInteger m = calculateE(params.getQ(), message); + BigInteger q = params.getQ(); + BigInteger m = calculateE(q, message); BigInteger zero = BigInteger.valueOf(0); - if (zero.compareTo(r) >= 0 || params.getQ().compareTo(r) <= 0) + if (zero.compareTo(r) >= 0 || q.compareTo(r) <= 0) { return false; } - if (zero.compareTo(s) >= 0 || params.getQ().compareTo(s) <= 0) + if (zero.compareTo(s) >= 0 || q.compareTo(s) <= 0) { return false; } - BigInteger w = s.modInverse(params.getQ()); + BigInteger w = s.modInverse(q); - BigInteger u1 = m.multiply(w).mod(params.getQ()); - BigInteger u2 = r.multiply(w).mod(params.getQ()); + BigInteger u1 = m.multiply(w).mod(q); + BigInteger u2 = r.multiply(w).mod(q); - u1 = params.getG().modPow(u1, params.getP()); - u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, params.getP()); + BigInteger p = params.getP(); + u1 = params.getG().modPow(u1, p); + u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, p); - BigInteger v = u1.multiply(u2).mod(params.getP()).mod(params.getQ()); + BigInteger v = u1.multiply(u2).mod(p).mod(q); return v.equals(r); } @@ -157,4 +158,9 @@ public class DSASigner return new BigInteger(1, trunc); } } + + protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided) + { + return !needed ? null : (provided != null) ? provided : new SecureRandom(); + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java index 2a1f98e..adb2558 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java @@ -5,13 +5,18 @@ import java.security.SecureRandom; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.math.ec.ECAlgorithms; import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECMultiplier; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.FixedPointCombMultiplier; /** * EC-DSA as described in X9.62 @@ -46,18 +51,19 @@ public class ECDSASigner boolean forSigning, CipherParameters param) { + SecureRandom providedRandom = null; + if (forSigning) { if (param instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)param; + ParametersWithRandom rParam = (ParametersWithRandom)param; - this.random = rParam.getRandom(); this.key = (ECPrivateKeyParameters)rParam.getParameters(); + providedRandom = rParam.getRandom(); } else { - this.random = new SecureRandom(); this.key = (ECPrivateKeyParameters)param; } } @@ -65,6 +71,8 @@ public class ECDSASigner { this.key = (ECPublicKeyParameters)param; } + + this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom); } // 5.3 pg 28 @@ -78,50 +86,44 @@ public class ECDSASigner public BigInteger[] generateSignature( byte[] message) { - BigInteger n = key.getParameters().getN(); + ECDomainParameters ec = key.getParameters(); + BigInteger n = ec.getN(); BigInteger e = calculateE(n, message); - BigInteger r = null; - BigInteger s = null; + BigInteger d = ((ECPrivateKeyParameters)key).getD(); if (kCalculator.isDeterministic()) { - kCalculator.init(n, ((ECPrivateKeyParameters)key).getD(), message); + kCalculator.init(n, d, message); } else { kCalculator.init(n, random); } + BigInteger r, s; + + ECMultiplier basePointMultiplier = createBasePointMultiplier(); + // 5.3.2 do // generate s { - BigInteger k = null; - + BigInteger k; do // generate r { k = kCalculator.nextK(); - ECPoint p = key.getParameters().getG().multiply(k).normalize(); + ECPoint p = basePointMultiplier.multiply(ec.getG(), k).normalize(); // 5.3.3 - BigInteger x = p.getAffineXCoord().toBigInteger(); - - r = x.mod(n); + r = p.getAffineXCoord().toBigInteger().mod(n); } while (r.equals(ZERO)); - BigInteger d = ((ECPrivateKeyParameters)key).getD(); - s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n); } while (s.equals(ZERO)); - BigInteger[] res = new BigInteger[2]; - - res[0] = r; - res[1] = s; - - return res; + return new BigInteger[]{ r, s }; } // 5.4 pg 29 @@ -135,7 +137,8 @@ public class ECDSASigner BigInteger r, BigInteger s) { - BigInteger n = key.getParameters().getN(); + ECDomainParameters ec = key.getParameters(); + BigInteger n = ec.getN(); BigInteger e = calculateE(n, message); // r in the range [1,n-1] @@ -155,10 +158,10 @@ public class ECDSASigner BigInteger u1 = e.multiply(c).mod(n); BigInteger u2 = r.multiply(c).mod(n); - ECPoint G = key.getParameters().getG(); + ECPoint G = ec.getG(); ECPoint Q = ((ECPublicKeyParameters)key).getQ(); - ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2).normalize(); + ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2); // components must be bogus. if (point.isInfinity()) @@ -166,12 +169,48 @@ public class ECDSASigner return false; } - BigInteger v = point.getAffineXCoord().toBigInteger().mod(n); + /* + * If possible, avoid normalizing the point (to save a modular inversion in the curve field). + * + * There are ~cofactor elements of the curve field that reduce (modulo the group order) to 'r'. + * If the cofactor is known and small, we generate those possible field values and project each + * of them to the same "denominator" (depending on the particular projective coordinates in use) + * as the calculated point.X. If any of the projected values matches point.X, then we have: + * (point.X / Denominator mod p) mod n == r + * as required, and verification succeeds. + * + * Based on an original idea by Gregory Maxwell (https://github.com/gmaxwell), as implemented in + * the libsecp256k1 project (https://github.com/bitcoin/secp256k1). + */ + ECCurve curve = point.getCurve(); + if (curve != null) + { + BigInteger cofactor = curve.getCofactor(); + if (cofactor != null && cofactor.compareTo(EIGHT) <= 0) + { + ECFieldElement D = getDenominator(curve.getCoordinateSystem(), point); + if (D != null && !D.isZero()) + { + ECFieldElement X = point.getXCoord(); + while (curve.isValidFieldElement(r)) + { + ECFieldElement R = curve.fromBigInteger(r).multiply(D); + if (R.equals(X)) + { + return true; + } + r = r.add(n); + } + return false; + } + } + } + BigInteger v = point.normalize().getAffineXCoord().toBigInteger().mod(n); return v.equals(r); } - private BigInteger calculateE(BigInteger n, byte[] message) + protected BigInteger calculateE(BigInteger n, byte[] message) { int log2n = n.bitLength(); int messageBitLength = message.length * 8; @@ -183,4 +222,31 @@ public class ECDSASigner } return e; } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } + + protected ECFieldElement getDenominator(int coordinateSystem, ECPoint p) + { + switch (coordinateSystem) + { + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + case ECCurve.COORD_SKEWED: + return p.getZCoord(0); + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: + return p.getZCoord(0).square(); + default: + return null; + } + } + + protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided) + { + return !needed ? null : (provided != null) ? provided : new SecureRandom(); + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java index 18dd84e..a8ef959 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java @@ -50,6 +50,8 @@ public class RSADigestSigner oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256); oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384); oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512); + oidMap.put("SHA-512/224", NISTObjectIdentifiers.id_sha512_224); + oidMap.put("SHA-512/256", NISTObjectIdentifiers.id_sha512_256); // BEGIN android-removed // oidMap.put("MD2", PKCSObjectIdentifiers.md2); @@ -222,6 +224,8 @@ public class RSADigestSigner } else { + Arrays.constantTimeAreEqual(expected, expected); // keep time "steady". + return false; } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java index bbd8cda..6a69308 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java @@ -3,7 +3,7 @@ package org.bouncycastle.crypto.signers; import java.math.BigInteger; import java.security.SecureRandom; -class RandomDSAKCalculator +public class RandomDSAKCalculator implements DSAKCalculator { private static final BigInteger ZERO = BigInteger.valueOf(0); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java index f0da0bf..2ded8ef 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java @@ -1,5 +1,8 @@ package org.bouncycastle.crypto.util; +/** + * @deprecated use org.bouncycastle.util.pack + */ public abstract class Pack { public static int bigEndianToInt(byte[] bs, int off) @@ -114,6 +117,15 @@ public abstract class Pack } } + public static void littleEndianToInt(byte[] bs, int bOff, int[] ns, int nOff, int count) + { + for (int i = 0; i < count; ++i) + { + ns[nOff + i] = littleEndianToInt(bs, bOff); + bOff += 4; + } + } + public static byte[] intToLittleEndian(int n) { byte[] bs = new byte[4]; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java index d997db7..0175aa1 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java @@ -9,7 +9,6 @@ import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; // BEGIN android-removed // import org.bouncycastle.asn1.oiw.ElGamalParameter; // END android-removed @@ -25,12 +24,14 @@ import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.crypto.ec.CustomNamedCurves; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPrivateKeyParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECNamedDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; // BEGIN android-removed // import org.bouncycastle.crypto.params.ElGamalParameters; @@ -104,8 +105,8 @@ public class PrivateKeyFactory // BEGIN android-removed // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm)) // { - // ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters()); - // ASN1Integer = (ASN1Integer)keyInfo.parsePrivateKey(); + // ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters()); + // ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); // // return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters( // params.getP(), params.getG())); @@ -130,24 +131,30 @@ public class PrivateKeyFactory X962Parameters params = new X962Parameters((ASN1Primitive)algId.getParameters()); X9ECParameters x9; + ECDomainParameters dParams; + if (params.isNamedCurve()) { - ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); - x9 = ECNamedCurveTable.getByOID(oid); + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters(); + + x9 = CustomNamedCurves.getByOID(oid); + if (x9 == null) + { + x9 = ECNamedCurveTable.getByOID(oid); + } + dParams = new ECNamedDomainParameters( + oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); } else { x9 = X9ECParameters.getInstance(params.getParameters()); + dParams = new ECDomainParameters( + x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); } ECPrivateKey ec = ECPrivateKey.getInstance(keyInfo.parsePrivateKey()); BigInteger d = ec.getKey(); - // TODO We lose any named parameters here - - ECDomainParameters dParams = new ECDomainParameters( - x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); - return new ECPrivateKeyParameters(d, dParams); } else diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java index 7ade197..042c68e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java @@ -10,7 +10,6 @@ import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DEROctetString; // BEGIN android-removed // import org.bouncycastle.asn1.oiw.ElGamalParameter; @@ -23,14 +22,15 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DSAParameter; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; -import org.bouncycastle.asn1.x9.DHDomainParameters; import org.bouncycastle.asn1.x9.DHPublicKey; -import org.bouncycastle.asn1.x9.DHValidationParms; +import org.bouncycastle.asn1.x9.DomainParameters; import org.bouncycastle.asn1.x9.ECNamedCurveTable; +import org.bouncycastle.asn1.x9.ValidationParams; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ECPoint; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.crypto.ec.CustomNamedCurves; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.DHParameters; import org.bouncycastle.crypto.params.DHPublicKeyParameters; @@ -38,6 +38,7 @@ import org.bouncycastle.crypto.params.DHValidationParameters; import org.bouncycastle.crypto.params.DSAParameters; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECNamedDomainParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; // BEGIN android-removed // import org.bouncycastle.crypto.params.ElGamalParameters; @@ -97,26 +98,26 @@ public class PublicKeyFactory { DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.parsePublicKey()); - BigInteger y = dhPublicKey.getY().getValue(); + BigInteger y = dhPublicKey.getY(); - DHDomainParameters dhParams = DHDomainParameters.getInstance(algId.getParameters()); + DomainParameters dhParams = DomainParameters.getInstance(algId.getParameters()); - BigInteger p = dhParams.getP().getValue(); - BigInteger g = dhParams.getG().getValue(); - BigInteger q = dhParams.getQ().getValue(); + BigInteger p = dhParams.getP(); + BigInteger g = dhParams.getG(); + BigInteger q = dhParams.getQ(); BigInteger j = null; if (dhParams.getJ() != null) { - j = dhParams.getJ().getValue(); + j = dhParams.getJ(); } DHValidationParameters validation = null; - DHValidationParms dhValidationParms = dhParams.getValidationParms(); + ValidationParams dhValidationParms = dhParams.getValidationParams(); if (dhValidationParms != null) { - byte[] seed = dhValidationParms.getSeed().getBytes(); - BigInteger pgenCounter = dhValidationParms.getPgenCounter().getValue(); + byte[] seed = dhValidationParms.getSeed(); + BigInteger pgenCounter = dhValidationParms.getPgenCounter(); // TODO Check pgenCounter size? @@ -139,7 +140,7 @@ public class PublicKeyFactory // BEGIN android-removed // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm)) // { - // ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters()); + // ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters()); // ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey(); // // return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters( @@ -166,24 +167,30 @@ public class PublicKeyFactory X962Parameters params = X962Parameters.getInstance(algId.getParameters()); X9ECParameters x9; + ECDomainParameters dParams; + if (params.isNamedCurve()) { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters(); - x9 = ECNamedCurveTable.getByOID(oid); + + x9 = CustomNamedCurves.getByOID(oid); + if (x9 == null) + { + x9 = ECNamedCurveTable.getByOID(oid); + } + dParams = new ECNamedDomainParameters( + oid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); } else { x9 = X9ECParameters.getInstance(params.getParameters()); + dParams = new ECDomainParameters( + x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); } ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes()); X9ECPoint derQ = new X9ECPoint(x9.getCurve(), key); - // TODO We lose any named parameters here - - ECDomainParameters dParams = new ECDomainParameters( - x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); - return new ECPublicKeyParameters(derQ.getPoint(), dParams); } else diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PBKDFKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PBKDFKey.java new file mode 100644 index 0000000..ae3d2eb --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PBKDFKey.java @@ -0,0 +1,11 @@ +package org.bouncycastle.jcajce; + +import javax.crypto.SecretKey; + +/** + * Base interface for keys associated with various password based key derivation functions (PBKDF). + */ +public interface PBKDFKey + extends SecretKey +{ +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java new file mode 100644 index 0000000..db63ecd --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12Key.java @@ -0,0 +1,82 @@ +package org.bouncycastle.jcajce; + +import org.bouncycastle.crypto.PBEParametersGenerator; + +/** + * A password based key for use with PKCS#12. + */ +public class PKCS12Key + implements PBKDFKey +{ + private final char[] password; + private final boolean useWrongZeroLengthConversion; + /** + * Basic constructor for a password based key - secret key generation parameters will be passed separately.. + * + * @param password password to use. + */ + public PKCS12Key(char[] password) + { + this(password, false); + } + + /** + * Unfortunately there seems to be some confusion about how to handle zero length + * passwords. + * + * @param password password to use. + * @param useWrongZeroLengthConversion use the incorrect encoding approach (add pad bytes) + */ + public PKCS12Key(char[] password, boolean useWrongZeroLengthConversion) + { + this.password = new char[password.length]; + this.useWrongZeroLengthConversion = useWrongZeroLengthConversion; + + System.arraycopy(password, 0, this.password, 0, password.length); + } + + /** + * Return a reference to the char[] array holding the password. + * + * @return a reference to the password array. + */ + public char[] getPassword() + { + return password; + } + + /** + * Return the password based key derivation function this key is for, + * + * @return the string "PKCS12" + */ + public String getAlgorithm() + { + return "PKCS12"; + } + + /** + * Return the format encoding. + * + * @return the string "PKCS12", representing the char[] to byte[] conversion. + */ + public String getFormat() + { + return "PKCS12"; + } + + /** + * Return the password converted to bytes. + * + * @return the password converted to a byte array. + */ + public byte[] getEncoded() + { + if (useWrongZeroLengthConversion && password.length == 0) + { + return new byte[2]; + } + + return PBEParametersGenerator.PKCS12PasswordToBytes(password); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12KeyWithParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12KeyWithParameters.java new file mode 100644 index 0000000..bd05596 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12KeyWithParameters.java @@ -0,0 +1,69 @@ +package org.bouncycastle.jcajce; + +import javax.crypto.interfaces.PBEKey; + +import org.bouncycastle.util.Arrays; + +/** + * A password based key for use with PKCS#12 with full PBE parameters. + */ +public class PKCS12KeyWithParameters + extends PKCS12Key + implements PBEKey +{ + private final byte[] salt; + private final int iterationCount; + + /** + * Basic constructor for a password based key with generation parameters. + * + * @param password password to use. + * @param salt salt for generation algorithm + * @param iterationCount iteration count for generation algorithm. + */ + public PKCS12KeyWithParameters(char[] password, byte[] salt, int iterationCount) + { + super(password); + + this.salt = Arrays.clone(salt); + this.iterationCount = iterationCount; + } + + + /** + * Basic constructor for a password based key with generation parameters, specifying the wrong conversion for + * zero length passwords. + * + * @param password password to use. + * @param salt salt for generation algorithm + * @param iterationCount iteration count for generation algorithm. + * @param useWrongZeroLengthConversion use the incorrect encoding approach (add pad bytes) + */ + public PKCS12KeyWithParameters(char[] password, boolean useWrongZeroLengthConversion, byte[] salt, int iterationCount) + { + super(password, useWrongZeroLengthConversion); + + this.salt = Arrays.clone(salt); + this.iterationCount = iterationCount; + } + + /** + * Return the salt to use in the key derivation function. + * + * @return the salt to use in the KDF. + */ + public byte[] getSalt() + { + return salt; + } + + /** + * Return the iteration count to use in the key derivation function. + * + * @return the iteration count to use in the KDF. + */ + public int getIterationCount() + { + return iterationCount; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12StoreParameter.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12StoreParameter.java new file mode 100644 index 0000000..b53eca5 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKCS12StoreParameter.java @@ -0,0 +1,62 @@ +package org.bouncycastle.jcajce; + +import java.io.OutputStream; +import java.security.KeyStore; +import java.security.KeyStore.LoadStoreParameter; +import java.security.KeyStore.ProtectionParameter; + +/** + * LoadStoreParameter to allow for additional config with PKCS12 files. + *

    + * Note: if you want a straight DER encoding of a PKCS#12 file you should use this. + *

    + */ +public class PKCS12StoreParameter + implements LoadStoreParameter +{ + private final OutputStream out; + private final ProtectionParameter protectionParameter; + private final boolean forDEREncoding; + + public PKCS12StoreParameter(OutputStream out, char[] password) + { + this(out, password, false); + } + + public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter) + { + this(out, protectionParameter, false); + } + + public PKCS12StoreParameter(OutputStream out, char[] password, boolean forDEREncoding) + { + this(out, new KeyStore.PasswordProtection(password), forDEREncoding); + } + + public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter, boolean forDEREncoding) + { + this.out = out; + this.protectionParameter = protectionParameter; + this.forDEREncoding = forDEREncoding; + } + + public OutputStream getOutputStream() + { + return out; + } + + public ProtectionParameter getProtectionParameter() + { + return protectionParameter; + } + + /** + * Return whether the KeyStore used with this parameter should be DER encoded on saving. + * + * @return true for straight DER encoding, false otherwise, + */ + public boolean isForDEREncoding() + { + return forDEREncoding; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStore.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStore.java new file mode 100644 index 0000000..1592055 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStore.java @@ -0,0 +1,27 @@ +package org.bouncycastle.jcajce; + +import java.security.cert.CRL; +import java.util.Collection; + +import org.bouncycastle.util.Selector; +import org.bouncycastle.util.Store; +import org.bouncycastle.util.StoreException; + +/** + * Generic interface for a PKIX based CRL store. + * + * @param the CRL type. + */ +public interface PKIXCRLStore + extends Store +{ + /** + * Return the matches associated with the passed in selector. + * + * @param selector the selector defining the match criteria. + * @return a collection of matches with the selector, an empty selector if there are none. + * @throws StoreException in the event of an issue doing a match. + */ + Collection getMatches(Selector selector) + throws StoreException; +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java new file mode 100644 index 0000000..e7dbcce --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java @@ -0,0 +1,347 @@ +package org.bouncycastle.jcajce; + +import java.math.BigInteger; +import java.security.cert.CRL; +import java.security.cert.CRLSelector; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLSelector; +import java.security.cert.X509Certificate; +import java.util.Collection; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Selector; + +/** + * This class is a Selector implementation for X.509 certificate revocation + * lists. + * + * @see org.bouncycastle.util.Selector + */ +public class PKIXCRLStoreSelector + implements Selector +{ + /** + * Builder for a PKIXCRLStoreSelector. + */ + public static class Builder + { + private final CRLSelector baseSelector; + + private boolean deltaCRLIndicator = false; + private boolean completeCRLEnabled = false; + private BigInteger maxBaseCRLNumber = null; + private byte[] issuingDistributionPoint = null; + private boolean issuingDistributionPointEnabled = false; + + /** + * Constructor initializing a builder with a CertSelector. + * + * @param crlSelector the CertSelector to copy the match details from. + */ + public Builder(CRLSelector crlSelector) + { + this.baseSelector = (CRLSelector)crlSelector.clone(); + } + + + /** + * If set to true only complete CRLs are returned. + *

    + * {@link #setCompleteCRLEnabled(boolean)} and + * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other. + * + * @param completeCRLEnabled true if only complete CRLs + * should be returned. + */ + public Builder setCompleteCRLEnabled(boolean completeCRLEnabled) + { + this.completeCRLEnabled = completeCRLEnabled; + + return this; + } + + /** + * If this is set to true the CRL reported contains the delta + * CRL indicator CRL extension. + *

    + * {@link #setCompleteCRLEnabled(boolean)} and + * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other. + * + * @param deltaCRLIndicator true if the delta CRL indicator + * extension must be in the CRL. + */ + public Builder setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator) + { + this.deltaCRLIndicator = deltaCRLIndicator; + + return this; + } + + /** + * Sets the maximum base CRL number. Setting to null disables + * this cheack. + *

    + * This is only meaningful for delta CRLs. Complete CRLs must have a CRL + * number which is greater or equal than the base number of the + * corresponding CRL. + * + * @param maxBaseCRLNumber The maximum base CRL number to set. + */ + public void setMaxBaseCRLNumber(BigInteger maxBaseCRLNumber) + { + this.maxBaseCRLNumber = maxBaseCRLNumber; + } + + /** + * Enables or disables the issuing distribution point check. + * + * @param issuingDistributionPointEnabled true to enable the + * issuing distribution point check. + */ + public void setIssuingDistributionPointEnabled( + boolean issuingDistributionPointEnabled) + { + this.issuingDistributionPointEnabled = issuingDistributionPointEnabled; + } + + /** + * Sets the issuing distribution point. + *

    + * The issuing distribution point extension is a CRL extension which + * identifies the scope and the distribution point of a CRL. The scope + * contains among others information about revocation reasons contained in + * the CRL. Delta CRLs and complete CRLs must have matching issuing + * distribution points. + *

    + * The byte array is cloned to protect against subsequent modifications. + *

    + * You must also enable or disable this criteria with + * {@link #setIssuingDistributionPointEnabled(boolean)}. + * + * @param issuingDistributionPoint The issuing distribution point to set. + * This is the DER encoded OCTET STRING extension value. + * @see #getIssuingDistributionPoint() + */ + public void setIssuingDistributionPoint(byte[] issuingDistributionPoint) + { + this.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint); + } + + /** + * Build a selector. + * + * @return a new PKIXCRLStoreSelector + */ + public PKIXCRLStoreSelector build() + { + return new PKIXCRLStoreSelector(this); + } + } + + private final CRLSelector baseSelector; + private final boolean deltaCRLIndicator; + private final boolean completeCRLEnabled; + private final BigInteger maxBaseCRLNumber; + private final byte[] issuingDistributionPoint; + private final boolean issuingDistributionPointEnabled; + + private PKIXCRLStoreSelector(Builder baseBuilder) + { + this.baseSelector = baseBuilder.baseSelector; + this.deltaCRLIndicator = baseBuilder.deltaCRLIndicator; + this.completeCRLEnabled = baseBuilder.completeCRLEnabled; + this.maxBaseCRLNumber = baseBuilder.maxBaseCRLNumber; + this.issuingDistributionPoint = baseBuilder.issuingDistributionPoint; + this.issuingDistributionPointEnabled = baseBuilder.issuingDistributionPointEnabled; + } + + + /** + * Returns if the issuing distribution point criteria should be applied. + * Defaults to false. + *

    + * You may also set the issuing distribution point criteria if not a missing + * issuing distribution point should be assumed. + * + * @return Returns if the issuing distribution point check is enabled. + */ + public boolean isIssuingDistributionPointEnabled() + { + return issuingDistributionPointEnabled; + } + + + + public boolean match(CRL obj) + { + if (!(obj instanceof X509CRL)) + { + return baseSelector.match(obj); + } + + X509CRL crl = (X509CRL)obj; + ASN1Integer dci = null; + try + { + byte[] bytes = crl + .getExtensionValue(Extension.deltaCRLIndicator.getId()); + if (bytes != null) + { + dci = ASN1Integer.getInstance(ASN1OctetString.getInstance(bytes).getOctets()); + } + } + catch (Exception e) + { + return false; + } + if (isDeltaCRLIndicatorEnabled()) + { + if (dci == null) + { + return false; + } + } + if (isCompleteCRLEnabled()) + { + if (dci != null) + { + return false; + } + } + if (dci != null) + { + + if (maxBaseCRLNumber != null) + { + if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1) + { + return false; + } + } + } + if (issuingDistributionPointEnabled) + { + byte[] idp = crl + .getExtensionValue(Extension.issuingDistributionPoint + .getId()); + if (issuingDistributionPoint == null) + { + if (idp != null) + { + return false; + } + } + else + { + if (!Arrays.areEqual(idp, issuingDistributionPoint)) + { + return false; + } + } + + } + return baseSelector.match(obj); + } + + /** + * Returns if this selector must match CRLs with the delta CRL indicator + * extension set. Defaults to false. + * + * @return Returns true if only CRLs with the delta CRL + * indicator extension are selected. + */ + public boolean isDeltaCRLIndicatorEnabled() + { + return deltaCRLIndicator; + } + + public Object clone() + { + return this; + } + + /** + * If true only complete CRLs are returned. Defaults to + * false. + * + * @return true if only complete CRLs are returned. + */ + public boolean isCompleteCRLEnabled() + { + return completeCRLEnabled; + } + + /** + * Get the maximum base CRL number. Defaults to null. + * + * @return Returns the maximum base CRL number. + */ + public BigInteger getMaxBaseCRLNumber() + { + return maxBaseCRLNumber; + } + + + /** + * Returns the issuing distribution point. Defaults to null, + * which is a missing issuing distribution point extension. + *

    + * The internal byte array is cloned before it is returned. + *

    + * The criteria must be enable with Builder.setIssuingDistributionPointEnabled(boolean)}. + * + * @return Returns the issuing distribution point. + */ + public byte[] getIssuingDistributionPoint() + { + return Arrays.clone(issuingDistributionPoint); + } + + public X509Certificate getCertificateChecking() + { + if (baseSelector instanceof X509CRLSelector) + { + return ((X509CRLSelector)baseSelector).getCertificateChecking(); + } + + return null; + } + + public static Collection getCRLs(final PKIXCRLStoreSelector selector, CertStore certStore) + throws CertStoreException + { + return certStore.getCRLs(new SelectorClone(selector)); + } + + private static class SelectorClone + extends X509CRLSelector + { + private final PKIXCRLStoreSelector selector; + + SelectorClone(PKIXCRLStoreSelector selector) + { + this.selector = selector; + + if (selector.baseSelector instanceof X509CRLSelector) + { + X509CRLSelector baseSelector = (X509CRLSelector)selector.baseSelector; + + this.setCertificateChecking(baseSelector.getCertificateChecking()); + this.setDateAndTime(baseSelector.getDateAndTime()); + this.setIssuers(baseSelector.getIssuers()); + this.setMinCRLNumber(baseSelector.getMinCRL()); + this.setMaxCRLNumber(baseSelector.getMaxCRL()); + } + } + + public boolean match(CRL crl) + { + return (selector == null) ? (crl != null) : selector.match(crl); + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCertStore.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCertStore.java new file mode 100644 index 0000000..853e2d1 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCertStore.java @@ -0,0 +1,27 @@ +package org.bouncycastle.jcajce; + +import java.security.cert.Certificate; +import java.util.Collection; + +import org.bouncycastle.util.Selector; +import org.bouncycastle.util.Store; +import org.bouncycastle.util.StoreException; + +/** + * Generic interface for a PKIX based certificate store. + * + * @param the certificate type. + */ +public interface PKIXCertStore + extends Store +{ + /** + * Return the matches associated with the passed in selector. + * + * @param selector the selector defining the match criteria. + * @return a collection of matches with the selector, an empty selector if there are none. + * @throws StoreException in the event of an issue doing a match. + */ + Collection getMatches(Selector selector) + throws StoreException; +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCertStoreSelector.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCertStoreSelector.java new file mode 100644 index 0000000..faf25d1 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXCertStoreSelector.java @@ -0,0 +1,119 @@ +package org.bouncycastle.jcajce; + +import java.io.IOException; +import java.security.cert.CertSelector; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.Certificate; +import java.security.cert.X509CertSelector; +import java.util.Collection; + +import org.bouncycastle.util.Selector; + +/** + * This class is a Selector implementation for certificates. + * + * @see org.bouncycastle.util.Selector + */ +public class PKIXCertStoreSelector + implements Selector +{ + /** + * Builder for a PKIXCertStoreSelector. + */ + public static class Builder + { + private final CertSelector baseSelector; + + /** + * Constructor initializing a builder with a CertSelector. + * + * @param certSelector the CertSelector to copy the match details from. + */ + public Builder(CertSelector certSelector) + { + this.baseSelector = (CertSelector)certSelector.clone(); + } + + /** + * Build a selector. + * + * @return a new PKIXCertStoreSelector + */ + public PKIXCertStoreSelector build() + { + return new PKIXCertStoreSelector(baseSelector); + } + } + + private final CertSelector baseSelector; + + private PKIXCertStoreSelector(CertSelector baseSelector) + { + this.baseSelector = baseSelector; + } + + public boolean match(Certificate cert) + { + return baseSelector.match(cert); + } + + public Object clone() + { + return new PKIXCertStoreSelector(baseSelector); + } + + public static Collection getCertificates(final PKIXCertStoreSelector selector, CertStore certStore) + throws CertStoreException + { + return certStore.getCertificates(new SelectorClone(selector)); + } + + private static class SelectorClone + extends X509CertSelector + { + private final PKIXCertStoreSelector selector; + + SelectorClone(PKIXCertStoreSelector selector) + { + this.selector = selector; + + if (selector.baseSelector instanceof X509CertSelector) + { + X509CertSelector baseSelector = (X509CertSelector)selector.baseSelector; + + this.setAuthorityKeyIdentifier(baseSelector.getAuthorityKeyIdentifier()); + this.setBasicConstraints(baseSelector.getBasicConstraints()); + this.setCertificate(baseSelector.getCertificate()); + this.setCertificateValid(baseSelector.getCertificateValid()); + this.setKeyUsage(baseSelector.getKeyUsage()); + this.setMatchAllSubjectAltNames(baseSelector.getMatchAllSubjectAltNames()); + this.setPrivateKeyValid(baseSelector.getPrivateKeyValid()); + this.setSerialNumber(baseSelector.getSerialNumber()); + this.setSubjectKeyIdentifier(baseSelector.getSubjectKeyIdentifier()); + this.setSubjectPublicKey(baseSelector.getSubjectPublicKey()); + + try + { + this.setExtendedKeyUsage(baseSelector.getExtendedKeyUsage()); + this.setIssuer(baseSelector.getIssuerAsBytes()); + this.setNameConstraints(baseSelector.getNameConstraints()); + this.setPathToNames(baseSelector.getPathToNames()); + this.setPolicy(baseSelector.getPolicy()); + this.setSubject(baseSelector.getSubjectAsBytes()); + this.setSubjectAlternativeNames(baseSelector.getSubjectAlternativeNames()); + this.setSubjectPublicKeyAlgID(baseSelector.getSubjectPublicKeyAlgID()); + } + catch (IOException e) + { + throw new IllegalStateException("base selector invalid: " + e.getMessage(), e); + } + } + } + + public boolean match(Certificate certificate) + { + return (selector == null) ? (certificate != null) : selector.match(certificate); + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedBuilderParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedBuilderParameters.java new file mode 100644 index 0000000..382a23c --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedBuilderParameters.java @@ -0,0 +1,141 @@ +package org.bouncycastle.jcajce; + +import java.security.InvalidParameterException; +import java.security.cert.CertPathParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * This class contains extended parameters for PKIX certification path builders. + * + * @see PKIXBuilderParameters + */ +public class PKIXExtendedBuilderParameters + implements CertPathParameters +{ + /** + * Builder for a PKIXExtendedBuilderParameters object. + */ + public static class Builder + { + private final PKIXExtendedParameters baseParameters; + + private int maxPathLength = 5; + private Set excludedCerts = new HashSet(); + + public Builder(PKIXBuilderParameters baseParameters) + { + this.baseParameters = new PKIXExtendedParameters.Builder(baseParameters).build(); + this.maxPathLength = baseParameters.getMaxPathLength(); + } + + public Builder(PKIXExtendedParameters baseParameters) + { + this.baseParameters = baseParameters; + } + + /** + * Adds excluded certificates which are not used for building a + * certification path. + *

    + * The given set is cloned to protect it against subsequent modifications. + * + * @param excludedCerts The excluded certificates to set. + */ + public Builder addExcludedCerts(Set excludedCerts) + { + this.excludedCerts.addAll(excludedCerts); + + return this; + } + + /** + * Sets the maximum number of intermediate non-self-issued certificates in a + * certification path. The PKIX CertPathBuilder must not + * build paths longer then this length. + *

    + * A value of 0 implies that the path can only contain a single certificate. + * A value of -1 does not limit the length. The default length is 5. + * + *

    + * + * The basic constraints extension of a CA certificate overrides this value + * if smaller. + * + * @param maxPathLength the maximum number of non-self-issued intermediate + * certificates in the certification path + * @throws InvalidParameterException if maxPathLength is set + * to a value less than -1 + * + * @see #getMaxPathLength + */ + public Builder setMaxPathLength(int maxPathLength) + { + if (maxPathLength < -1) + { + throw new InvalidParameterException("The maximum path " + + "length parameter can not be less than -1."); + } + this.maxPathLength = maxPathLength; + + return this; + } + + public PKIXExtendedBuilderParameters build() + { + return new PKIXExtendedBuilderParameters(this); + } + } + + private final PKIXExtendedParameters baseParameters; + private final Set excludedCerts; + private final int maxPathLength; + + private PKIXExtendedBuilderParameters(Builder builder) + { + this.baseParameters = builder.baseParameters; + this.excludedCerts = Collections.unmodifiableSet(builder.excludedCerts); + this.maxPathLength = builder.maxPathLength; + } + + public PKIXExtendedParameters getBaseParameters() + { + return baseParameters; + } + + /** + * Excluded certificates are not used for building a certification path. + *

    + * The returned set is immutable. + * + * @return Returns the excluded certificates. + */ + public Set getExcludedCerts() + { + return excludedCerts; + } + + /** + * Returns the value of the maximum number of intermediate non-self-issued + * certificates in the certification path. + * + * @return the maximum number of non-self-issued intermediate certificates + * in the certification path, or -1 if no limit exists. + */ + public int getMaxPathLength() + { + return maxPathLength; + } + + /** + * @return this object + */ + public Object clone() + { + return this; + } +} + diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedParameters.java new file mode 100644 index 0000000..cd24f06 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/PKIXExtendedParameters.java @@ -0,0 +1,340 @@ +package org.bouncycastle.jcajce; + +import java.security.cert.CertPathParameters; +import java.security.cert.CertSelector; +import java.security.cert.CertStore; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.bouncycastle.asn1.x509.GeneralName; + +/** + * This class extends the PKIXParameters with a validity model parameter. + */ +public class PKIXExtendedParameters + implements CertPathParameters +{ + /** + * This is the default PKIX validity model. Actually there are two variants + * of this: The PKIX model and the modified PKIX model. The PKIX model + * verifies that all involved certificates must have been valid at the + * current time. The modified PKIX model verifies that all involved + * certificates were valid at the signing time. Both are indirectly choosen + * with the {@link PKIXParameters#setDate(Date)} method, so this + * methods sets the Date when all certificates must have been + * valid. + */ + public static final int PKIX_VALIDITY_MODEL = 0; + + /** + * This model uses the following validity model. Each certificate must have + * been valid at the moment where is was used. That means the end + * certificate must have been valid at the time the signature was done. The + * CA certificate which signed the end certificate must have been valid, + * when the end certificate was signed. The CA (or Root CA) certificate must + * have been valid, when the CA certificate was signed and so on. So the + * {@link PKIXParameters#setDate(Date)} method sets the time, when + * the end certificate must have been valid.

    It is used e.g. + * in the German signature law. + */ + public static final int CHAIN_VALIDITY_MODEL = 1; + + /** + * Builder for a PKIXExtendedParameters object. + */ + public static class Builder + { + private final PKIXParameters baseParameters; + private final Date date; + + private PKIXCertStoreSelector targetConstraints; + private List extraCertStores = new ArrayList(); + private Map namedCertificateStoreMap = new HashMap(); + private List extraCRLStores = new ArrayList(); + private Map namedCRLStoreMap = new HashMap(); + private boolean revocationEnabled; + private int validityModel = PKIX_VALIDITY_MODEL; + private boolean useDeltas = false; + private Set trustAnchors; + + public Builder(PKIXParameters baseParameters) + { + this.baseParameters = (PKIXParameters)baseParameters.clone(); + CertSelector constraints = baseParameters.getTargetCertConstraints(); + if (constraints != null) + { + this.targetConstraints = new PKIXCertStoreSelector.Builder(constraints).build(); + } + Date checkDate = baseParameters.getDate(); + this.date = (checkDate == null) ? new Date() : checkDate; + this.revocationEnabled = baseParameters.isRevocationEnabled(); + this.trustAnchors = baseParameters.getTrustAnchors(); + } + + public Builder(PKIXExtendedParameters baseParameters) + { + this.baseParameters = baseParameters.baseParameters; + this.date = baseParameters.date; + this.targetConstraints = baseParameters.targetConstraints; + this.extraCertStores = new ArrayList(baseParameters.extraCertStores); + this.namedCertificateStoreMap = new HashMap(baseParameters.namedCertificateStoreMap); + this.extraCRLStores = new ArrayList(baseParameters.extraCRLStores); + this.namedCRLStoreMap = new HashMap(baseParameters.namedCRLStoreMap); + this.useDeltas = baseParameters.useDeltas; + this.validityModel = baseParameters.validityModel; + this.revocationEnabled = baseParameters.isRevocationEnabled(); + this.trustAnchors = baseParameters.getTrustAnchors(); + } + + public Builder addCertificateStore(PKIXCertStore store) + { + extraCertStores.add(store); + + return this; + } + + public Builder addNamedCertificateStore(GeneralName issuerAltName, PKIXCertStore store) + { + namedCertificateStoreMap.put(issuerAltName, store); + + return this; + } + + public Builder addCRLStore(PKIXCRLStore store) + { + extraCRLStores.add(store); + + return this; + } + + public Builder addNamedCRLStore(GeneralName issuerAltName, PKIXCRLStore store) + { + namedCRLStoreMap.put(issuerAltName, store); + + return this; + } + + public Builder setTargetConstraints(PKIXCertStoreSelector selector) + { + targetConstraints = selector; + + return this; + } + + /** + * Sets if delta CRLs should be used for checking the revocation status. + * + * @param useDeltas true if delta CRLs should be used. + */ + public Builder setUseDeltasEnabled(boolean useDeltas) + { + this.useDeltas = useDeltas; + + return this; + } + + /** + * @param validityModel The validity model to set. + * @see #CHAIN_VALIDITY_MODEL + * @see #PKIX_VALIDITY_MODEL + */ + public Builder setValidityModel(int validityModel) + { + this.validityModel = validityModel; + + return this; + } + + /** + * Set the trustAnchor to be used with these parameters. + * + * @param trustAnchor the trust anchor end-entity and CRLs must be based on. + * @return the current builder. + */ + public Builder setTrustAnchor(TrustAnchor trustAnchor) + { + this.trustAnchors = Collections.singleton(trustAnchor); + + return this; + } + + /** + * Set the set of trustAnchors to be used with these parameters. + * + * @param trustAnchors a set of trustAnchors, one of which a particular end-entity and it's associated CRLs must be based on. + * @return the current builder. + */ + public Builder setTrustAnchors(Set trustAnchors) + { + this.trustAnchors = trustAnchors; + + return this; + } + + /** + * Flag whether or not revocation checking is to be enabled. + * + * @param revocationEnabled true if revocation checking to be enabled, false otherwise. + */ + public void setRevocationEnabled(boolean revocationEnabled) + { + this.revocationEnabled = revocationEnabled; + } + + public PKIXExtendedParameters build() + { + return new PKIXExtendedParameters(this); + } + } + + private final PKIXParameters baseParameters; + private final PKIXCertStoreSelector targetConstraints; + private final Date date; + private final List extraCertStores; + private final Map namedCertificateStoreMap; + private final List extraCRLStores; + private final Map namedCRLStoreMap; + private final boolean revocationEnabled; + private final boolean useDeltas; + private final int validityModel; + private final Set trustAnchors; + + private PKIXExtendedParameters(Builder builder) + { + this.baseParameters = builder.baseParameters; + this.date = builder.date; + this.extraCertStores = Collections.unmodifiableList(builder.extraCertStores); + this.namedCertificateStoreMap = Collections.unmodifiableMap(new HashMap(builder.namedCertificateStoreMap)); + this.extraCRLStores = Collections.unmodifiableList(builder.extraCRLStores); + this.namedCRLStoreMap = Collections.unmodifiableMap(new HashMap(builder.namedCRLStoreMap)); + this.targetConstraints = builder.targetConstraints; + this.revocationEnabled = builder.revocationEnabled; + this.useDeltas = builder.useDeltas; + this.validityModel = builder.validityModel; + this.trustAnchors = Collections.unmodifiableSet(builder.trustAnchors); + } + + public List getCertificateStores() + { + return extraCertStores; + } + + + public Map getNamedCertificateStoreMap() + { + return namedCertificateStoreMap; + } + + public List getCRLStores() + { + return extraCRLStores; + } + + public Map getNamedCRLStoreMap() + { + return namedCRLStoreMap; + } + + public Date getDate() + { + return new Date(date.getTime()); + } + + + + + /** + * Defaults to false. + * + * @return Returns if delta CRLs should be used. + */ + public boolean isUseDeltasEnabled() + { + return useDeltas; + } + + + + /** + * @return Returns the validity model. + * @see #CHAIN_VALIDITY_MODEL + * @see #PKIX_VALIDITY_MODEL + */ + public int getValidityModel() + { + return validityModel; + } + + public Object clone() + { + return this; + } + + /** + * Returns the required constraints on the target certificate. + * The constraints are returned as an instance of + * Selector. If null, no constraints are + * defined. + * + * @return a Selector specifying the constraints on the + * target certificate or attribute certificate (or null) + * @see PKIXCertStoreSelector + */ + public PKIXCertStoreSelector getTargetConstraints() + { + return targetConstraints; + } + + public Set getTrustAnchors() + { + return trustAnchors; + } + + public Set getInitialPolicies() + { + return baseParameters.getInitialPolicies(); + } + + public String getSigProvider() + { + return baseParameters.getSigProvider(); + } + + public boolean isExplicitPolicyRequired() + { + return baseParameters.isExplicitPolicyRequired(); + } + + public boolean isAnyPolicyInhibited() + { + return baseParameters.isAnyPolicyInhibited(); + } + + public boolean isPolicyMappingInhibited() + { + return baseParameters.isPolicyMappingInhibited(); + } + + public List getCertPathCheckers() + { + return baseParameters.getCertPathCheckers(); + } + + public List getCertStores() + { + return baseParameters.getCertStores(); + } + + public boolean isRevocationEnabled() + { + return revocationEnabled; + } + +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java index bfedc81..889d957 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java @@ -1,14 +1,10 @@ package org.bouncycastle.jcajce.provider.asymmetric; -// BEGIN android-added import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.jcajce.provider.asymmetric.dh.KeyFactorySpi; -// END android-added import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; -// BEGIN android-added -import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; -// END android-added public class DH { @@ -28,13 +24,13 @@ public class DH provider.addAlgorithm("KeyAgreement.DH", PREFIX + "KeyAgreementSpi"); provider.addAlgorithm("Alg.Alias.KeyAgreement.DIFFIEHELLMAN", "DH"); + // BEGIN android-removed + // provider.addAlgorithm("KeyAgreement", PKCSObjectIdentifiers.id_alg_ESDH, PREFIX + "KeyAgreementSpi$DHwithRFC2631KDF"); + // provider.addAlgorithm("KeyAgreement", PKCSObjectIdentifiers.id_alg_SSDH, PREFIX + "KeyAgreementSpi$DHwithRFC2631KDF"); + // END android-removed provider.addAlgorithm("KeyFactory.DH", PREFIX + "KeyFactorySpi"); provider.addAlgorithm("Alg.Alias.KeyFactory.DIFFIEHELLMAN", "DH"); - // BEGIN android-added - AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi(); - registerOid(provider, PKCSObjectIdentifiers.dhKeyAgreement, "DH", keyFact); - // END android-added provider.addAlgorithm("AlgorithmParameters.DH", PREFIX + "AlgorithmParametersSpi"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.DIFFIEHELLMAN", "DH"); @@ -42,13 +38,26 @@ public class DH provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.DIFFIEHELLMAN", "DH"); provider.addAlgorithm("AlgorithmParameterGenerator.DH", PREFIX + "AlgorithmParameterGeneratorSpi"); - + // BEGIN android-removed + // provider.addAlgorithm("Cipher.IES", PREFIX + "IESCipher$IES"); + // provider.addAlgorithm("Cipher.IESwithAES", PREFIX + "IESCipher$IESwithAES"); + // provider.addAlgorithm("Cipher.IESWITHAES", PREFIX + "IESCipher$IESwithAES"); + // provider.addAlgorithm("Cipher.IESWITHDESEDE", PREFIX + "IESCipher$IESwithDESede"); + // // provider.addAlgorithm("Cipher.DHIES", PREFIX + "IESCipher$IES"); // provider.addAlgorithm("Cipher.DHIESwithAES", PREFIX + "IESCipher$IESwithAES"); // provider.addAlgorithm("Cipher.DHIESWITHAES", PREFIX + "IESCipher$IESwithAES"); // provider.addAlgorithm("Cipher.DHIESWITHDESEDE", PREFIX + "IESCipher$IESwithDESede"); + // + // provider.addAlgorithm("Cipher.OLDDHIES", PREFIX + "IESCipher$OldIES"); + // provider.addAlgorithm("Cipher.OLDDHIESwithAES", PREFIX + "IESCipher$OldIESwithAES"); + // provider.addAlgorithm("Cipher.OLDDHIESWITHAES", PREFIX + "IESCipher$OldIESwithAES"); + // provider.addAlgorithm("Cipher.OLDDHIESWITHDESEDE", PREFIX + "IESCipher$OldIESwithDESede"); // END android-removed + + registerOid(provider, PKCSObjectIdentifiers.dhKeyAgreement, "DH", new KeyFactorySpi()); + registerOid(provider, X9ObjectIdentifiers.dhpublicnumber, "DH", new KeyFactorySpi()); } } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java index 2bede7e..7c402f3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java @@ -63,10 +63,12 @@ public class DSA provider.addAlgorithm("Alg.Alias.Signature.DSAWITHSHA1", "SHA1withDSA"); provider.addAlgorithm("Alg.Alias.Signature.SHA1WithDSA", "SHA1withDSA"); provider.addAlgorithm("Alg.Alias.Signature.DSAWithSHA1", "SHA1withDSA"); - - provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA1withDSA"); // END android-changed + // BEGIN android-removed + // provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10040.4.3", "DSA"); + // END android-removed + AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi(); for (int i = 0; i != DSAUtil.dsaOids.length; i++) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java index 43e5861..99a27bf 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java @@ -1,13 +1,18 @@ package org.bouncycastle.jcajce.provider.asymmetric; // BEGIN android-removed +// import org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; // import org.bouncycastle.asn1.eac.EACObjectIdentifiers; +// import org.bouncycastle.asn1.sec.SECObjectIdentifiers; // import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; // END android-removed import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; +// BEGIN android-removed +// import org.bouncycastle.util.Properties; +// END android-removed public class EC { @@ -22,26 +27,121 @@ public class EC public void configure(ConfigurableProvider provider) { + // BEGIN android-removed + // provider.addAlgorithm("AlgorithmParameters.EC", PREFIX + "AlgorithmParametersSpi"); + // END android-removed + provider.addAlgorithm("KeyAgreement.ECDH", PREFIX + "KeyAgreementSpi$DH"); // BEGIN android-removed // provider.addAlgorithm("KeyAgreement.ECDHC", PREFIX + "KeyAgreementSpi$DHC"); - // provider.addAlgorithm("KeyAgreement.ECMQV", PREFIX + "KeyAgreementSpi$MQV"); - // provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA1KDF"); - // provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA1KDF"); + // provider.addAlgorithm("KeyAgreement.ECCDH", PREFIX + "KeyAgreementSpi$DHC"); + // + // provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA1KDFAndSharedInfo"); + // provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA1KDFAndSharedInfo"); + // + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA224KDFAndSharedInfo"); + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA224KDFAndSharedInfo"); + // + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA256KDFAndSharedInfo"); + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA256KDFAndSharedInfo"); + // + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA384KDFAndSharedInfo"); + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA384KDFAndSharedInfo"); + // + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$DHwithSHA512KDFAndSharedInfo"); + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$CDHwithSHA512KDFAndSharedInfo"); + // + // provider.addAlgorithm("KeyAgreement.ECDHWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHwithSHA1KDF"); + // + // provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA1CKDF"); + // provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA256CKDF"); + // provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA384CKDF"); + // provider.addAlgorithm("KeyAgreement.ECCDHWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$DHwithSHA512CKDF"); // END android-removed registerOid(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC", new KeyFactorySpi.EC()); - // TODO Should this be an alias for ECDH? + // BEGIN android-added + // We were having this one in 1.52. As of 1.54 this one is under + // if (!Properties.isOverrideSet("org.bouncycastle.ec.disable_mqv")) + // below registerOid(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC()); + // END android-added + // BEGIN android-removed + // registerOid(provider, X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC()); // registerOid(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV()); + // + // registerOid(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme, "EC", new KeyFactorySpi.EC()); + // registerOid(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme, "EC", new KeyFactorySpi.EC()); + // + // registerOid(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme, "EC", new KeyFactorySpi.EC()); + // registerOid(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme, "EC", new KeyFactorySpi.EC()); + // + // registerOid(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme, "EC", new KeyFactorySpi.EC()); + // registerOid(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme, "EC", new KeyFactorySpi.EC()); + // + // registerOid(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme, "EC", new KeyFactorySpi.EC()); + // registerOid(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme, "EC", new KeyFactorySpi.EC()); + // // END android-removed - // BEGIN android-removed + // // Android comment: the registrations in this block are causing CTS tests to fail + // // and don't seem to be implemented by bouncycastle (so looks like an bug in + // // bouncycastle). + // // TODO(20447540): check if this occurs in upstream bouncycastle and report accordingly // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC"); - // // TODO Should this be an alias for ECDH? + // // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC"); - // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "EC"); + // END android-removed + // BEGIN android-removed + // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme, "EC"); + // + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme, "EC"); + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme, "EC"); + // + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme, "EC"); + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme, "EC"); + // + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme, "EC"); + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme, "EC"); + // + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme, "EC"); + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme, "EC"); + // + // if (!Properties.isOverrideSet("org.bouncycastle.ec.disable_mqv")) + // { + // provider.addAlgorithm("KeyAgreement.ECMQV", PREFIX + "KeyAgreementSpi$MQV"); + // + // provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA1CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA1CKDF"); + // provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA224CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA224CKDF"); + // provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA256CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA256CKDF"); + // provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA384CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA384CKDF"); + // provider.addAlgorithm("KeyAgreement.ECMQVWITHSHA512CKDF", PREFIX + "KeyAgreementSpi$MQVwithSHA512CKDF"); + // + // provider.addAlgorithm("KeyAgreement." + X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA1KDFAndSharedInfo"); + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA224KDFAndSharedInfo"); + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA256KDFAndSharedInfo"); + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA384KDFAndSharedInfo"); + // provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA512KDFAndSharedInfo"); + // + // registerOid(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC()); + // registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "EC"); + // + // registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV()); + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, "EC"); + // + // registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV()); + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, "EC"); + // + // registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV()); + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme, "EC"); + // + // registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha512kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV()); + // registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha512kdf_scheme, "EC"); + // + // provider.addAlgorithm("KeyFactory.ECMQV", PREFIX + "KeyFactorySpi$ECMQV"); + // provider.addAlgorithm("KeyPairGenerator.ECMQV", PREFIX + "KeyPairGeneratorSpi$ECMQV"); + // } // END android-removed provider.addAlgorithm("KeyFactory.EC", PREFIX + "KeyFactorySpi$EC"); @@ -49,43 +149,65 @@ public class EC // provider.addAlgorithm("KeyFactory.ECDSA", PREFIX + "KeyFactorySpi$ECDSA"); // provider.addAlgorithm("KeyFactory.ECDH", PREFIX + "KeyFactorySpi$ECDH"); // provider.addAlgorithm("KeyFactory.ECDHC", PREFIX + "KeyFactorySpi$ECDHC"); - // provider.addAlgorithm("KeyFactory.ECMQV", PREFIX + "KeyFactorySpi$ECMQV"); // END android-removed provider.addAlgorithm("KeyPairGenerator.EC", PREFIX + "KeyPairGeneratorSpi$EC"); // BEGIN android-removed // provider.addAlgorithm("KeyPairGenerator.ECDSA", PREFIX + "KeyPairGeneratorSpi$ECDSA"); // provider.addAlgorithm("KeyPairGenerator.ECDH", PREFIX + "KeyPairGeneratorSpi$ECDH"); + // provider.addAlgorithm("KeyPairGenerator.ECDHWITHSHA1KDF", PREFIX + "KeyPairGeneratorSpi$ECDH"); // provider.addAlgorithm("KeyPairGenerator.ECDHC", PREFIX + "KeyPairGeneratorSpi$ECDHC"); // provider.addAlgorithm("KeyPairGenerator.ECIES", PREFIX + "KeyPairGeneratorSpi$ECDH"); - // provider.addAlgorithm("KeyPairGenerator.ECMQV", PREFIX + "KeyPairGeneratorSpi$ECMQV"); // // provider.addAlgorithm("Cipher.ECIES", PREFIX + "IESCipher$ECIES"); // provider.addAlgorithm("Cipher.ECIESwithAES", PREFIX + "IESCipher$ECIESwithAES"); // provider.addAlgorithm("Cipher.ECIESWITHAES", PREFIX + "IESCipher$ECIESwithAES"); // provider.addAlgorithm("Cipher.ECIESwithDESEDE", PREFIX + "IESCipher$ECIESwithDESede"); // provider.addAlgorithm("Cipher.ECIESWITHDESEDE", PREFIX + "IESCipher$ECIESwithDESede"); + // provider.addAlgorithm("Cipher.ECIESwithAES-CBC", PREFIX + "IESCipher$ECIESwithAESCBC"); + // provider.addAlgorithm("Cipher.ECIESWITHAES-CBC", PREFIX + "IESCipher$ECIESwithAESCBC"); + // provider.addAlgorithm("Cipher.ECIESwithDESEDE-CBC", PREFIX + "IESCipher$ECIESwithDESedeCBC"); + // provider.addAlgorithm("Cipher.ECIESWITHDESEDE-CBC", PREFIX + "IESCipher$ECIESwithDESedeCBC"); + // + // provider.addAlgorithm("Cipher.OldECIES", PREFIX + "IESCipher$OldECIES"); + // provider.addAlgorithm("Cipher.OldECIESwithAES", PREFIX + "IESCipher$OldECIESwithAES"); + // provider.addAlgorithm("Cipher.OldECIESWITHAES", PREFIX + "IESCipher$OldECIESwithAES"); + // provider.addAlgorithm("Cipher.OldECIESwithDESEDE", PREFIX + "IESCipher$OldECIESwithDESede"); + // provider.addAlgorithm("Cipher.OldECIESWITHDESEDE", PREFIX + "IESCipher$OldECIESwithDESede"); + // provider.addAlgorithm("Cipher.OldECIESwithAES-CBC", PREFIX + "IESCipher$OldECIESwithAESCBC"); + // provider.addAlgorithm("Cipher.OldECIESWITHAES-CBC", PREFIX + "IESCipher$OldECIESwithAESCBC"); + // provider.addAlgorithm("Cipher.OldECIESwithDESEDE-CBC", PREFIX + "IESCipher$OldECIESwithDESedeCBC"); + // provider.addAlgorithm("Cipher.OldECIESWITHDESEDE-CBC", PREFIX + "IESCipher$OldECIESwithDESedeCBC"); // END android-removed - provider.addAlgorithm("Signature.ECDSA", PREFIX + "SignatureSpi$ecDSA"); + // BEGIN android-changed + provider.addAlgorithm("Signature.SHA1withECDSA", PREFIX + "SignatureSpi$ecDSA"); provider.addAlgorithm("Signature.NONEwithECDSA", PREFIX + "SignatureSpi$ecDSAnone"); - provider.addAlgorithm("Alg.Alias.Signature.SHA1withECDSA", "ECDSA"); - provider.addAlgorithm("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA"); - provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHECDSA", "ECDSA"); - provider.addAlgorithm("Alg.Alias.Signature.ECDSAWITHSHA1", "ECDSA"); - provider.addAlgorithm("Alg.Alias.Signature.SHA1WithECDSA", "ECDSA"); - provider.addAlgorithm("Alg.Alias.Signature.ECDSAWithSHA1", "ECDSA"); - provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA"); + provider.addAlgorithm("Alg.Alias.Signature.ECDSA", "SHA1withECDSA"); + provider.addAlgorithm("Alg.Alias.Signature.ECDSAwithSHA1", "SHA1withECDSA"); + provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHECDSA", "SHA1withECDSA"); + provider.addAlgorithm("Alg.Alias.Signature.ECDSAWITHSHA1", "SHA1withECDSA"); + provider.addAlgorithm("Alg.Alias.Signature.SHA1WithECDSA", "SHA1withECDSA"); + provider.addAlgorithm("Alg.Alias.Signature.ECDSAWithSHA1", "SHA1withECDSA"); + provider.addAlgorithm("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA"); + // END android-changed // BEGIN android-removed // provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA"); // - // provider.addAlgorithm("Signature.DETECDSA", PREFIX + "SignatureSpi$ecDetDSA"); - // provider.addAlgorithm("Signature.SHA1WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA"); - // provider.addAlgorithm("Signature.SHA224WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA224"); - // provider.addAlgorithm("Signature.SHA256WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA256"); - // provider.addAlgorithm("Signature.SHA384WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA384"); - // provider.addAlgorithm("Signature.SHA512WITHDETECDSA", PREFIX + "SignatureSpi$ecDetDSA512"); + // provider.addAlgorithm("Signature.ECDDSA", PREFIX + "SignatureSpi$ecDetDSA"); + // provider.addAlgorithm("Signature.SHA1WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA"); + // provider.addAlgorithm("Signature.SHA224WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA224"); + // provider.addAlgorithm("Signature.SHA256WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA256"); + // provider.addAlgorithm("Signature.SHA384WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA384"); + // provider.addAlgorithm("Signature.SHA512WITHECDDSA", PREFIX + "SignatureSpi$ecDetDSA512"); + // + // provider.addAlgorithm("Alg.Alias.Signature.DETECDSA", "ECDDSA"); + // provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDETECDSA", "SHA1WITHECDDSA"); + // provider.addAlgorithm("Alg.Alias.Signature.SHA224WITHDETECDSA", "SHA224WITHECDDSA"); + // provider.addAlgorithm("Alg.Alias.Signature.SHA256WITHDETECDSA", "SHA256WITHECDDSA"); + // provider.addAlgorithm("Alg.Alias.Signature.SHA384WITHDETECDSA", "SHA384WITHECDDSA"); + // provider.addAlgorithm("Alg.Alias.Signature.SHA512WITHDETECDSA", "SHA512WITHECDDSA"); // END android-removed addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224); @@ -106,6 +228,13 @@ public class EC // addSignatureAlgorithm(provider, "SHA256", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256); // addSignatureAlgorithm(provider, "SHA384", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA384", EACObjectIdentifiers.id_TA_ECDSA_SHA_384); // addSignatureAlgorithm(provider, "SHA512", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA512", EACObjectIdentifiers.id_TA_ECDSA_SHA_512); + // + // addSignatureAlgorithm(provider, "SHA1", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", BSIObjectIdentifiers.ecdsa_plain_SHA1); + // addSignatureAlgorithm(provider, "SHA224", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", BSIObjectIdentifiers.ecdsa_plain_SHA224); + // addSignatureAlgorithm(provider, "SHA256", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", BSIObjectIdentifiers.ecdsa_plain_SHA256); + // addSignatureAlgorithm(provider, "SHA384", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA384", BSIObjectIdentifiers.ecdsa_plain_SHA384); + // addSignatureAlgorithm(provider, "SHA512", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA512", BSIObjectIdentifiers.ecdsa_plain_SHA512); + // addSignatureAlgorithm(provider, "RIPEMD160", "PLAIN-ECDSA", PREFIX + "SignatureSpi$ecPlainDSARP160", BSIObjectIdentifiers.ecdsa_plain_RIPEMD160); // END android-removed } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java index 901e27d..5098c33 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java @@ -26,9 +26,9 @@ public class RSA public void configure(ConfigurableProvider provider) { provider.addAlgorithm("AlgorithmParameters.OAEP", PREFIX + "AlgorithmParametersSpi$OAEP"); + provider.addAlgorithm("AlgorithmParameters.PSS", PREFIX + "AlgorithmParametersSpi$PSS"); + // BEGIN android-removed - // provider.addAlgorithm("AlgorithmParameters.PSS", PREFIX + "AlgorithmParametersSpi$PSS"); - // // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSAPSS", "PSS"); // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RSASSA-PSS", "PSS"); // @@ -53,12 +53,12 @@ public class RSA // END android-changed // BEGIN android-removed // provider.addAlgorithm("Cipher.RSA/PKCS1", PREFIX + "CipherSpi$PKCS1v1_5Padding"); - // provider.addAlgorithm("Cipher.1.2.840.113549.1.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding"); - // provider.addAlgorithm("Cipher.2.5.8.1.1", PREFIX + "CipherSpi$PKCS1v1_5Padding"); + // provider.addAlgorithm("Cipher", PKCSObjectIdentifiers.rsaEncryption, PREFIX + "CipherSpi$PKCS1v1_5Padding"); + // provider.addAlgorithm("Cipher", X509ObjectIdentifiers.id_ea_rsa, PREFIX + "CipherSpi$PKCS1v1_5Padding"); // provider.addAlgorithm("Cipher.RSA/1", PREFIX + "CipherSpi$PKCS1v1_5Padding_PrivateOnly"); // provider.addAlgorithm("Cipher.RSA/2", PREFIX + "CipherSpi$PKCS1v1_5Padding_PublicOnly"); // provider.addAlgorithm("Cipher.RSA/OAEP", PREFIX + "CipherSpi$OAEPPadding"); - // provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.id_RSAES_OAEP, PREFIX + "CipherSpi$OAEPPadding"); + // provider.addAlgorithm("Cipher", PKCSObjectIdentifiers.id_RSAES_OAEP, PREFIX + "CipherSpi$OAEPPadding"); // provider.addAlgorithm("Cipher.RSA/ISO9796-1", PREFIX + "CipherSpi$ISO9796d1Padding"); // END android-removed @@ -86,16 +86,10 @@ public class RSA // registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "OAEP"); // registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "PSS"); // - // // provider.addAlgorithm("Signature.RSASSA-PSS", PREFIX + "PSSSignatureSpi$PSSwithRSA"); // provider.addAlgorithm("Signature." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA"); // provider.addAlgorithm("Signature.OID." + PKCSObjectIdentifiers.id_RSASSA_PSS, PREFIX + "PSSSignatureSpi$PSSwithRSA"); // - // provider.addAlgorithm("Signature.SHA224withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA224withRSA"); - // provider.addAlgorithm("Signature.SHA256withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA256withRSA"); - // provider.addAlgorithm("Signature.SHA384withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA384withRSA"); - // provider.addAlgorithm("Signature.SHA512withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA512withRSA"); - // // provider.addAlgorithm("Signature.RSA", PREFIX + "DigestSignatureSpi$noneRSA"); // provider.addAlgorithm("Signature.RAWRSASSA-PSS", PREFIX + "PSSSignatureSpi$nonePSS"); // @@ -107,15 +101,12 @@ public class RSA // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAANDMGF1", "RAWRSASSA-PSS"); // provider.addAlgorithm("Alg.Alias.Signature.RSAPSS", "RSASSA-PSS"); // - // - // provider.addAlgorithm("Alg.Alias.Signature.SHA224withRSAandMGF1", "SHA224withRSA/PSS"); - // provider.addAlgorithm("Alg.Alias.Signature.SHA256withRSAandMGF1", "SHA256withRSA/PSS"); - // provider.addAlgorithm("Alg.Alias.Signature.SHA384withRSAandMGF1", "SHA384withRSA/PSS"); - // provider.addAlgorithm("Alg.Alias.Signature.SHA512withRSAandMGF1", "SHA512withRSA/PSS"); - // provider.addAlgorithm("Alg.Alias.Signature.SHA224WITHRSAANDMGF1", "SHA224withRSA/PSS"); - // provider.addAlgorithm("Alg.Alias.Signature.SHA256WITHRSAANDMGF1", "SHA256withRSA/PSS"); - // provider.addAlgorithm("Alg.Alias.Signature.SHA384WITHRSAANDMGF1", "SHA384withRSA/PSS"); - // provider.addAlgorithm("Alg.Alias.Signature.SHA512WITHRSAANDMGF1", "SHA512withRSA/PSS"); + // addPSSSignature(provider, "SHA224", PREFIX + "PSSSignatureSpi$SHA224withRSA"); + // addPSSSignature(provider, "SHA256", PREFIX + "PSSSignatureSpi$SHA256withRSA"); + // addPSSSignature(provider, "SHA384", PREFIX + "PSSSignatureSpi$SHA384withRSA"); + // addPSSSignature(provider, "SHA512", PREFIX + "PSSSignatureSpi$SHA512withRSA"); + // addPSSSignature(provider, "SHA512(224)", PREFIX + "PSSSignatureSpi$SHA512_224withRSA"); + // addPSSSignature(provider, "SHA512(256)", PREFIX + "PSSSignatureSpi$SHA512_256withRSA"); // // if (provider.hasAlgorithm("MessageDigest", "MD2")) // { @@ -132,8 +123,7 @@ public class RSA { addDigestSignature(provider, "MD5", PREFIX + "DigestSignatureSpi$MD5", PKCSObjectIdentifiers.md5WithRSAEncryption); // BEGIN android-removed - // provider.addAlgorithm("Signature.MD5withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$MD5WithRSAEncryption"); - // provider.addAlgorithm("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2"); + // addISO9796Signature(provider, "MD5", PREFIX + "ISOSignatureSpi$MD5WithRSAEncryption"); // END android-removed } @@ -142,19 +132,20 @@ public class RSA // BEGIN android-removed // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1withRSA/PSS", "PSS"); // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA1WITHRSAANDMGF1", "PSS"); - // provider.addAlgorithm("Signature.SHA1withRSA/PSS", PREFIX + "PSSSignatureSpi$SHA1withRSA"); - // provider.addAlgorithm("Alg.Alias.Signature.SHA1withRSAandMGF1", "SHA1withRSA/PSS"); - // provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHRSAANDMGF1", "SHA1withRSA/PSS"); + // + // addPSSSignature(provider, "SHA1", PREFIX + "PSSSignatureSpi$SHA1withRSA"); // END android-removed - addDigestSignature(provider, "SHA1", PREFIX + "DigestSignatureSpi$SHA1", PKCSObjectIdentifiers.sha1WithRSAEncryption); - // BEGIN android-removed - // provider.addAlgorithm("Alg.Alias.Signature.SHA1WithRSA/ISO9796-2", "SHA1withRSA/ISO9796-2"); - // provider.addAlgorithm("Signature.SHA1withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$SHA1WithRSAEncryption"); + // addISO9796Signature(provider, "SHA1", PREFIX + "ISOSignatureSpi$SHA1WithRSAEncryption"); // END android-removed + provider.addAlgorithm("Alg.Alias.Signature." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA"); provider.addAlgorithm("Alg.Alias.Signature.OID." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA"); + + // BEGIN android-removed + // addX931Signature(provider, "SHA1", PREFIX + "X931SignatureSpi$SHA1WithRSAEncryption"); + // END android-removed } addDigestSignature(provider, "SHA224", PREFIX + "DigestSignatureSpi$SHA224", PKCSObjectIdentifiers.sha224WithRSAEncryption); @@ -163,26 +154,57 @@ public class RSA addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption); // BEGIN android-removed + // addDigestSignature(provider, "SHA512(224)", PREFIX + "DigestSignatureSpi$SHA512_224", null); + // addDigestSignature(provider, "SHA512(256)", PREFIX + "DigestSignatureSpi$SHA512_256", null); + + // addISO9796Signature(provider, "SHA224", PREFIX + "ISOSignatureSpi$SHA224WithRSAEncryption"); + // addISO9796Signature(provider, "SHA256", PREFIX + "ISOSignatureSpi$SHA256WithRSAEncryption"); + // addISO9796Signature(provider, "SHA384", PREFIX + "ISOSignatureSpi$SHA384WithRSAEncryption"); + // addISO9796Signature(provider, "SHA512", PREFIX + "ISOSignatureSpi$SHA512WithRSAEncryption"); + // addISO9796Signature(provider, "SHA512(224)", PREFIX + "ISOSignatureSpi$SHA512_224WithRSAEncryption"); + // addISO9796Signature(provider, "SHA512(256)", PREFIX + "ISOSignatureSpi$SHA512_256WithRSAEncryption"); + // + // addX931Signature(provider, "SHA224", PREFIX + "X931SignatureSpi$SHA224WithRSAEncryption"); + // addX931Signature(provider, "SHA256", PREFIX + "X931SignatureSpi$SHA256WithRSAEncryption"); + // addX931Signature(provider, "SHA384", PREFIX + "X931SignatureSpi$SHA384WithRSAEncryption"); + // addX931Signature(provider, "SHA512", PREFIX + "X931SignatureSpi$SHA512WithRSAEncryption"); + // addX931Signature(provider, "SHA512(224)", PREFIX + "X931SignatureSpi$SHA512_224WithRSAEncryption"); + // addX931Signature(provider, "SHA512(256)", PREFIX + "X931SignatureSpi$SHA512_256WithRSAEncryption"); + // // if (provider.hasAlgorithm("MessageDigest", "RIPEMD128")) // { // addDigestSignature(provider, "RIPEMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128); // addDigestSignature(provider, "RMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", null); + // provider.addAlgorithm("Alg.Alias.Signature.RIPEMD128withRSA/X9.31", "RIPEMD128WITHRSA/X9.31"); + // provider.addAlgorithm("Alg.Alias.Signature.RIPEMD128WithRSA/X9.31", "RIPEMD128WITHRSA/X9.31"); + // provider.addAlgorithm("Signature.RIPEMD128WITHRSA/X9.31", PREFIX + "X931SignatureSpi$RIPEMD128WithRSAEncryption"); // } - // + // // if (provider.hasAlgorithm("MessageDigest", "RIPEMD160")) // { // addDigestSignature(provider, "RIPEMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160); // addDigestSignature(provider, "RMD160", PREFIX + "DigestSignatureSpi$RIPEMD160", null); // provider.addAlgorithm("Alg.Alias.Signature.RIPEMD160WithRSA/ISO9796-2", "RIPEMD160withRSA/ISO9796-2"); // provider.addAlgorithm("Signature.RIPEMD160withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$RIPEMD160WithRSAEncryption"); + // provider.addAlgorithm("Alg.Alias.Signature.RIPEMD160withRSA/X9.31", "RIPEMD160WITHRSA/X9.31"); + // provider.addAlgorithm("Alg.Alias.Signature.RIPEMD160WithRSA/X9.31", "RIPEMD160WITHRSA/X9.31"); + // provider.addAlgorithm("Signature.RIPEMD160WITHRSA/X9.31", PREFIX + "X931SignatureSpi$RIPEMD160WithRSAEncryption"); // } - // + // // if (provider.hasAlgorithm("MessageDigest", "RIPEMD256")) // { // addDigestSignature(provider, "RIPEMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256); // addDigestSignature(provider, "RMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", null); // } - // END android-removed + // + // if (provider.hasAlgorithm("MessageDigest", "WHIRLPOOL")) + // { + // provider.addAlgorithm("Alg.Alias.Signature.WhirlpoolWithRSA/X9.31", "WHIRLPOOLWITHRSA/X9.31"); + // provider.addAlgorithm("Alg.Alias.Signature.WHIRLPOOLwithRSA/X9.31", "WHIRLPOOLWITHRSA/X9.31"); + // provider.addAlgorithm("Alg.Alias.Signature.WHIRLPOOLWithRSA/X9.31", "WHIRLPOOLWITHRSA/X9.31"); + // provider.addAlgorithm("Signature.WHIRLPOOLWITHRSA/X9.31", PREFIX + "X931SignatureSpi$WhirlpoolWithRSAEncryption"); + // } + // END android-removed } private void addDigestSignature( @@ -213,5 +235,37 @@ public class RSA provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, mainName); } } + + private void addISO9796Signature( + ConfigurableProvider provider, + String digest, + String className) + { + provider.addAlgorithm("Alg.Alias.Signature." + digest + "withRSA/ISO9796-2", digest + "WITHRSA/ISO9796-2"); + provider.addAlgorithm("Alg.Alias.Signature." + digest + "WithRSA/ISO9796-2", digest + "WITHRSA/ISO9796-2"); + provider.addAlgorithm("Signature." + digest + "WITHRSA/ISO9796-2", className); + } + + private void addPSSSignature( + ConfigurableProvider provider, + String digest, + String className) + { + provider.addAlgorithm("Alg.Alias.Signature." + digest + "withRSA/PSS", digest + "WITHRSAANDMGF1"); + provider.addAlgorithm("Alg.Alias.Signature." + digest + "WithRSA/PSS", digest + "WITHRSAANDMGF1"); + provider.addAlgorithm("Alg.Alias.Signature." + digest + "withRSAandMGF1", digest + "WITHRSAANDMGF1"); + provider.addAlgorithm("Alg.Alias.Signature." + digest + "WithRSAAndMGF1", digest + "WITHRSAANDMGF1"); + provider.addAlgorithm("Signature." + digest + "WITHRSAANDMGF1", className); + } + + private void addX931Signature( + ConfigurableProvider provider, + String digest, + String className) + { + provider.addAlgorithm("Alg.Alias.Signature." + digest + "withRSA/X9.31", digest + "WITHRSA/X9.31"); + provider.addAlgorithm("Alg.Alias.Signature." + digest + "WithRSA/X9.31", digest + "WITHRSA/X9.31"); + provider.addAlgorithm("Signature." + digest + "WITHRSA/X9.31", className); + } } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java index 8bdcc55..e4c8172 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java @@ -10,10 +10,10 @@ import javax.crypto.spec.DHParameterSpec; import org.bouncycastle.crypto.generators.DHParametersGenerator; import org.bouncycastle.crypto.params.DHParameters; -import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAlgorithmParameterGeneratorSpi; public class AlgorithmParameterGeneratorSpi - extends java.security.AlgorithmParameterGeneratorSpi + extends BaseAlgorithmParameterGeneratorSpi { protected SecureRandom random; protected int strength = 1024; @@ -63,7 +63,7 @@ public class AlgorithmParameterGeneratorSpi try { - params = AlgorithmParameters.getInstance("DH", BouncyCastleProvider.PROVIDER_NAME); + params = createParametersInstance("DH"); params.init(new DHParameterSpec(p.getP(), p.getG(), l)); } catch (Exception e) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java index c771123..608171b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java @@ -73,7 +73,7 @@ public class AlgorithmParametersSpi Class paramSpec) throws InvalidParameterSpecException { - if (paramSpec == DHParameterSpec.class) + if (paramSpec == DHParameterSpec.class || paramSpec == AlgorithmParameterSpec.class) { return currentSpec; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java index d5516dc..6fb54b6 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java @@ -20,6 +20,7 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x9.DHDomainParameters; +import org.bouncycastle.asn1.x9.DomainParameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.DHPrivateKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; @@ -82,9 +83,9 @@ public class BCDHPrivateKey } else if (id.equals(X9ObjectIdentifiers.dhpublicnumber)) { - DHDomainParameters params = DHDomainParameters.getInstance(seq); + DomainParameters params = DomainParameters.getInstance(seq); - this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue()); + this.dhSpec = new DHParameterSpec(params.getP(), params.getG()); } else { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java index 0697f75..ef74309 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java @@ -17,6 +17,7 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.DHDomainParameters; +import org.bouncycastle.asn1.x9.DomainParameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.DHPublicKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; @@ -96,9 +97,9 @@ public class BCDHPublicKey } else if (id.equals(X9ObjectIdentifiers.dhpublicnumber)) { - DHDomainParameters params = DHDomainParameters.getInstance(seq); + DomainParameters params = DomainParameters.getInstance(seq); - this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue()); + this.dhSpec = new DHParameterSpec(params.getP(), params.getG()); } else { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java index f2b5314..3de8ffe 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java @@ -4,9 +4,9 @@ import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; +import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; -import java.util.Hashtable; import javax.crypto.SecretKey; import javax.crypto.ShortBufferException; @@ -15,9 +15,13 @@ import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.spec.SecretKeySpec; -import org.bouncycastle.crypto.params.DESParameters; -import org.bouncycastle.util.Integers; -import org.bouncycastle.util.Strings; +import org.bouncycastle.crypto.DerivationFunction; +// BEGIN android-removed +// import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator; +// END android-removed +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi; +import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec; /** * Diffie-Hellman key agreement. There's actually a better way of doing this @@ -25,29 +29,25 @@ import org.bouncycastle.util.Strings; * details. */ public class KeyAgreementSpi - extends javax.crypto.KeyAgreementSpi + extends BaseAgreementSpi { private BigInteger x; private BigInteger p; private BigInteger g; - private BigInteger result; - private static final Hashtable algorithms = new Hashtable(); + public KeyAgreementSpi() + { + super("Diffie-Hellman", null); + } - static + public KeyAgreementSpi( + String kaAlgorithm, + DerivationFunction kdf) { - Integer i64 = Integers.valueOf(64); - Integer i192 = Integers.valueOf(192); - Integer i128 = Integers.valueOf(128); - Integer i256 = Integers.valueOf(256); - - algorithms.put("DES", i64); - algorithms.put("DESEDE", i192); - algorithms.put("BLOWFISH", i128); - algorithms.put("AES", i256); + super(kaAlgorithm, kdf); } - private byte[] bigIntToBytes( + protected byte[] bigIntToBytes( BigInteger r) { // @@ -122,7 +122,7 @@ public class KeyAgreementSpi throw new IllegalStateException("Diffie-Hellman not initialised."); } - return bigIntToBytes(result); + return super.engineGenerateSecret(); } protected int engineGenerateSecret( @@ -135,45 +135,27 @@ public class KeyAgreementSpi throw new IllegalStateException("Diffie-Hellman not initialised."); } - byte[] secret = bigIntToBytes(result); - - if (sharedSecret.length - offset < secret.length) - { - throw new ShortBufferException("DHKeyAgreement - buffer too short"); - } - - System.arraycopy(secret, 0, sharedSecret, offset, secret.length); - - return secret.length; + return super.engineGenerateSecret(sharedSecret, offset); } protected SecretKey engineGenerateSecret( - String algorithm) + String algorithm) + throws NoSuchAlgorithmException { if (x == null) { throw new IllegalStateException("Diffie-Hellman not initialised."); } - String algKey = Strings.toUpperCase(algorithm); byte[] res = bigIntToBytes(result); - if (algorithms.containsKey(algKey)) + // for JSSE compatibility + if (algorithm.equals("TlsPremasterSecret")) { - Integer length = (Integer)algorithms.get(algKey); - - byte[] key = new byte[length.intValue() / 8]; - System.arraycopy(res, 0, key, 0, key.length); - - if (algKey.startsWith("DES")) - { - DESParameters.setOddParity(key); - } - - return new SecretKeySpec(key, algorithm); + return new SecretKeySpec(trimZeroes(res), algorithm); } - return new SecretKeySpec(res, algorithm); + return super.engineGenerateSecret(algorithm); } protected void engineInit( @@ -190,14 +172,23 @@ public class KeyAgreementSpi if (params != null) { - if (!(params instanceof DHParameterSpec)) + if (params instanceof DHParameterSpec) // p, g override. + { + DHParameterSpec p = (DHParameterSpec)params; + + this.p = p.getP(); + this.g = p.getG(); + } + else if (params instanceof UserKeyingMaterialSpec) + { + this.p = privKey.getParams().getP(); + this.g = privKey.getParams().getG(); + this.ukmParameters = ((UserKeyingMaterialSpec)params).getUserKeyingMaterial(); + } + else { throw new InvalidAlgorithmParameterException("DHKeyAgreement only accepts DHParameterSpec"); } - DHParameterSpec p = (DHParameterSpec)params; - - this.p = p.getP(); - this.g = p.getG(); } else { @@ -224,4 +215,15 @@ public class KeyAgreementSpi this.g = privKey.getParams().getG(); this.x = this.result = privKey.getX(); } + + // BEGIN android-removed + // public static class DHwithRFC2631KDF + // extends KeyAgreementSpi + // { + // public DHwithRFC2631KDF() + // { + // super("DHwithRFC2631KDF", new DHKEKGenerator(new SHA1Digest())); + // } + // } + // END android-removed } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java index d850e5d..2d7c4c5 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java @@ -11,10 +11,10 @@ import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.generators.DSAParametersGenerator; import org.bouncycastle.crypto.params.DSAParameterGenerationParameters; import org.bouncycastle.crypto.params.DSAParameters; -import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAlgorithmParameterGeneratorSpi; public class AlgorithmParameterGeneratorSpi - extends java.security.AlgorithmParameterGeneratorSpi + extends BaseAlgorithmParameterGeneratorSpi { protected SecureRandom random; protected int strength = 1024; @@ -90,7 +90,7 @@ public class AlgorithmParameterGeneratorSpi try { - params = AlgorithmParameters.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME); + params = createParametersInstance("DSA"); params.init(new DSAParameterSpec(p.getP(), p.getQ(), p.getG())); } catch (Exception e) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java index 61fa33c..c6aac7c 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java @@ -33,7 +33,6 @@ public class AlgorithmParametersSpi /** * Return the X.509 ASN.1 structure DSAParameter. - *

    *

          *  DSAParameter ::= SEQUENCE {
          *                   prime INTEGER, -- p
    @@ -70,7 +69,7 @@ public class AlgorithmParametersSpi
             Class paramSpec)
             throws InvalidParameterSpecException
         {
    -        if (paramSpec == DSAParameterSpec.class)
    +        if (paramSpec == DSAParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
             {
                 return currentSpec;
             }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
    index e66330b..3a7b312 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
    @@ -18,6 +18,7 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
     import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
     import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
     import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
    +import org.bouncycastle.util.Strings;
     
     public class BCDSAPublicKey
         implements DSAPublicKey
    @@ -119,7 +120,7 @@ public class BCDSAPublicKey
         public String toString()
         {
             StringBuffer    buf = new StringBuffer();
    -        String          nl = System.getProperty("line.separator");
    +        String          nl = Strings.lineSeparator();
     
             buf.append("DSA Public Key").append(nl);
             buf.append("            y: ").append(this.getY().toString(16)).append(nl);
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
    index 5e940ec..c7e2aa9 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
    @@ -23,6 +23,9 @@ public class DSAUtil
         public static final ASN1ObjectIdentifier[] dsaOids =
         {
             X9ObjectIdentifiers.id_dsa,
    +        // BEGIN android-added
    +        X9ObjectIdentifiers.id_dsa_with_sha1,
    +        // END android-added
             OIWObjectIdentifiers.dsaWithSHA1
         };
     
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
    index c6ddf9b..d2c2c71 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
    @@ -34,9 +34,9 @@ public class KeyPairGeneratorSpi
             int strength,
             SecureRandom random)
         {
    -        if (strength < 512 || strength > 1024 || strength % 64 != 0)
    +        if (strength < 512 || strength > 4096 || ((strength < 1024) && strength % 64 != 0) || (strength >= 1024 && strength % 1024 != 0))
             {
    -            throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64");
    +            throw new InvalidParameterException("strength must be from 512 - 4096 and a multiple of 1024 above 1024");
             }
     
             this.strength = strength;
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java
    new file mode 100644
    index 0000000..6af71e8
    --- /dev/null
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java
    @@ -0,0 +1,167 @@
    +package org.bouncycastle.jcajce.provider.asymmetric.ec;
    +
    +import java.io.IOException;
    +import java.security.spec.AlgorithmParameterSpec;
    +import java.security.spec.ECGenParameterSpec;
    +import java.security.spec.ECParameterSpec;
    +import java.security.spec.InvalidParameterSpecException;
    +
    +import org.bouncycastle.asn1.ASN1ObjectIdentifier;
    +import org.bouncycastle.asn1.DERNull;
    +import org.bouncycastle.asn1.x9.ECNamedCurveTable;
    +import org.bouncycastle.asn1.x9.X962Parameters;
    +import org.bouncycastle.asn1.x9.X9ECParameters;
    +import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
    +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
    +import org.bouncycastle.jce.provider.BouncyCastleProvider;
    +import org.bouncycastle.math.ec.ECCurve;
    +
    +public class AlgorithmParametersSpi
    +    extends java.security.AlgorithmParametersSpi
    +{
    +    private ECParameterSpec ecParameterSpec;
    +    private String curveName;
    +
    +    protected boolean isASN1FormatString(String format)
    +    {
    +        return format == null || format.equals("ASN.1");
    +    }
    +
    +    @Override
    +    protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec)
    +        throws InvalidParameterSpecException
    +    {
    +        if (algorithmParameterSpec instanceof ECGenParameterSpec)
    +        {
    +            ECGenParameterSpec ecGenParameterSpec = (ECGenParameterSpec)algorithmParameterSpec;
    +            X9ECParameters params = ECUtils.getDomainParametersFromGenSpec(ecGenParameterSpec);
    +
    +            if (params == null)
    +            {
    +                throw new InvalidParameterSpecException("EC curve name not recognized: " + ecGenParameterSpec.getName());
    +            }
    +            curveName = ecGenParameterSpec.getName();
    +            ecParameterSpec = EC5Util.convertToSpec(params);
    +        }
    +        else if (algorithmParameterSpec instanceof ECParameterSpec)
    +        {
    +            curveName = null;
    +            ecParameterSpec = (ECParameterSpec)algorithmParameterSpec;
    +        }
    +        else
    +        {
    +            throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + algorithmParameterSpec.getClass().getName());
    +        }
    +    }
    +
    +    @Override
    +    protected void engineInit(byte[] bytes)
    +        throws IOException
    +    {
    +        engineInit(bytes, "ASN.1");
    +    }
    +
    +    @Override
    +    protected void engineInit(byte[] bytes, String format)
    +        throws IOException
    +    {
    +        if (isASN1FormatString(format))
    +        {
    +            X962Parameters params = X962Parameters.getInstance(bytes);
    +
    +            ECCurve curve = EC5Util.getCurve(BouncyCastleProvider.CONFIGURATION, params);
    +
    +            if (params.isNamedCurve())
    +            {
    +                curveName = ECNamedCurveTable.getName(ASN1ObjectIdentifier.getInstance(params.getParameters()));
    +            }
    +
    +            ecParameterSpec = EC5Util.convertToSpec(params, curve);
    +        }
    +        else
    +        {
    +            throw new IOException("Unknown encoded parameters format in AlgorithmParameters object: " + format);
    +        }
    +    }
    +
    +    @Override
    +    protected  T engineGetParameterSpec(Class paramSpec)
    +        throws InvalidParameterSpecException
    +    {
    +        if (ECParameterSpec.class.isAssignableFrom(paramSpec) || paramSpec == AlgorithmParameterSpec.class)
    +        {
    +            return (T)ecParameterSpec;
    +        }
    +        else if (ECGenParameterSpec.class.isAssignableFrom(paramSpec))
    +        {
    +            if (curveName != null)
    +            {
    +                ASN1ObjectIdentifier namedCurveOid = ECUtil.getNamedCurveOid(curveName);
    +
    +                if (namedCurveOid != null)
    +                {
    +                    return (T)new ECGenParameterSpec(namedCurveOid.getId());
    +                }
    +                return (T)new ECGenParameterSpec(curveName);
    +            }
    +            else
    +            {
    +                ASN1ObjectIdentifier namedCurveOid = ECUtil.getNamedCurveOid(EC5Util.convertSpec(ecParameterSpec, false));
    +
    +                if (namedCurveOid != null)
    +                {
    +                    return (T)new ECGenParameterSpec(namedCurveOid.getId());
    +                }
    +            }
    +        }
    +        throw new InvalidParameterSpecException("EC AlgorithmParameters cannot convert to " + paramSpec.getName());
    +    }
    +
    +    @Override
    +    protected byte[] engineGetEncoded()
    +        throws IOException
    +    {
    +        return engineGetEncoded("ASN.1");
    +    }
    +
    +    @Override
    +    protected byte[] engineGetEncoded(String format)
    +        throws IOException
    +    {
    +        if (isASN1FormatString(format))
    +        {
    +            X962Parameters params;
    +
    +            if (ecParameterSpec == null)     // implicitly CA
    +            {
    +                params = new X962Parameters(DERNull.INSTANCE);
    +            }
    +            else if (curveName != null)
    +            {
    +                params = new X962Parameters(ECUtil.getNamedCurveOid(curveName));
    +            }
    +            else
    +            {
    +                org.bouncycastle.jce.spec.ECParameterSpec ecSpec = EC5Util.convertSpec(ecParameterSpec, false);
    +                X9ECParameters ecP = new X9ECParameters(
    +                    ecSpec.getCurve(),
    +                    ecSpec.getG(),
    +                    ecSpec.getN(),
    +                    ecSpec.getH(),
    +                    ecSpec.getSeed());
    +
    +                params = new X962Parameters(ecP);
    +            }
    +
    +            return params.getEncoded();
    +        }
    +
    +        throw new IOException("Unknown parameters format in AlgorithmParameters object: " + format);
    +    }
    +
    +    @Override
    +    protected String engineToString()
    +    {
    +        return "EC AlgorithmParameters ";
    +    }
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
    index 45d5b08..e69942a 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
    @@ -35,6 +35,7 @@ import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
     import org.bouncycastle.jce.provider.BouncyCastleProvider;
     import org.bouncycastle.jce.spec.ECNamedCurveSpec;
     import org.bouncycastle.math.ec.ECCurve;
    +import org.bouncycastle.util.Strings;
     
     public class BCECPrivateKey
         implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
    @@ -210,38 +211,8 @@ public class BCECPrivateKey
         {
             X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters());
     
    -        if (params.isNamedCurve())
    -        {
    -            ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
    -            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
    -            EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
    -
    -            ecSpec = new ECNamedCurveSpec(
    -                    ECUtil.getCurveName(oid),
    -                    ellipticCurve,
    -                    new ECPoint(
    -                            ecP.getG().getAffineXCoord().toBigInteger(),
    -                            ecP.getG().getAffineYCoord().toBigInteger()),
    -                    ecP.getN(),
    -                    ecP.getH());
    -        }
    -        else if (params.isImplicitlyCA())
    -        {
    -            ecSpec = null;
    -        }
    -        else
    -        {
    -            X9ECParameters      ecP = X9ECParameters.getInstance(params.getParameters());
    -            EllipticCurve       ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
    -
    -            this.ecSpec = new ECParameterSpec(
    -                ellipticCurve,
    -                new ECPoint(
    -                        ecP.getG().getAffineXCoord().toBigInteger(),
    -                        ecP.getG().getAffineYCoord().toBigInteger()),
    -                ecP.getN(),
    -                ecP.getH().intValue());
    -        }
    +        ECCurve curve = EC5Util.getCurve(configuration, params);
    +        ecSpec = EC5Util.convertToSpec(params, curve);
     
             ASN1Encodable privKey = info.parsePrivateKey();
             if (privKey instanceof ASN1Integer)
    @@ -282,7 +253,8 @@ public class BCECPrivateKey
          */
         public byte[] getEncoded()
         {
    -        X962Parameters          params;
    +        X962Parameters  params;
    +        int orderBitLength;
     
             if (ecSpec instanceof ECNamedCurveSpec)
             {
    @@ -293,10 +265,12 @@ public class BCECPrivateKey
                 }
     
                 params = new X962Parameters(curveOid);
    +            orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS());
             }
             else if (ecSpec == null)
             {
                 params = new X962Parameters(DERNull.INSTANCE);
    +            orderBitLength = ECUtil.getOrderBitLength(null, this.getS());
             }
             else
             {
    @@ -310,6 +284,7 @@ public class BCECPrivateKey
                     ecSpec.getCurve().getSeed());
     
                 params = new X962Parameters(ecP);
    +            orderBitLength = ECUtil.getOrderBitLength(ecSpec.getOrder(), this.getS());
             }
             
             PrivateKeyInfo          info;
    @@ -317,11 +292,11 @@ public class BCECPrivateKey
     
             if (publicKey != null)
             {
    -            keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(this.getS(), publicKey, params);
    +            keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), publicKey, params);
             }
             else
             {
    -            keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(this.getS(), params);
    +            keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(orderBitLength, this.getS(), params);
             }
     
             try
    @@ -414,7 +389,7 @@ public class BCECPrivateKey
         public String toString()
         {
             StringBuffer    buf = new StringBuffer();
    -        String          nl = System.getProperty("line.separator");
    +        String          nl = Strings.lineSeparator();
     
             buf.append("EC Private Key").append(nl);
             buf.append("             S: ").append(this.d.toString(16)).append(nl);
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
    index 0eaae1d..c3f0dd0 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
    @@ -34,6 +34,7 @@ import org.bouncycastle.jce.interfaces.ECPointEncoder;
     import org.bouncycastle.jce.provider.BouncyCastleProvider;
     import org.bouncycastle.jce.spec.ECNamedCurveSpec;
     import org.bouncycastle.math.ec.ECCurve;
    +import org.bouncycastle.util.Strings;
     
     public class BCECPublicKey
         implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder
    @@ -82,6 +83,8 @@ public class BCECPublicKey
                 ECCurve curve = spec.getParams().getCurve();
                 EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
     
    +            // this may seem a little long-winded but it's how we pick up the custom curve.
    +            this.q = EC5Util.convertCurve(ellipticCurve).createPoint(spec.getQ().getAffineXCoord().toBigInteger(), spec.getQ().getAffineYCoord().toBigInteger());
                 this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
             }
             else
    @@ -132,7 +135,6 @@ public class BCECPublicKey
             ECDomainParameters      dp = params.getParameters();
     
             this.algorithm = algorithm;
    -        this.q = params.getQ();
     
             if (spec == null)
             {
    @@ -147,6 +149,8 @@ public class BCECPublicKey
                 this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
             }
     
    +        this.q = EC5Util.convertCurve(ecSpec.getCurve()).createPoint(params.getQ().getAffineXCoord().toBigInteger(), params.getQ().getAffineYCoord().toBigInteger());
    +
             this.configuration = configuration;
         }
     
    @@ -197,46 +201,8 @@ public class BCECPublicKey
         private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
         {
             X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithm().getParameters());
    -        ECCurve                 curve;
    -        EllipticCurve           ellipticCurve;
    -
    -        if (params.isNamedCurve())
    -        {
    -            ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
    -            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
    -
    -            curve = ecP.getCurve();
    -            ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
    -
    -            ecSpec = new ECNamedCurveSpec(
    -                    ECUtil.getCurveName(oid),
    -                    ellipticCurve,
    -                    new ECPoint(
    -                            ecP.getG().getAffineXCoord().toBigInteger(),
    -                            ecP.getG().getAffineYCoord().toBigInteger()),
    -                    ecP.getN(),
    -                    ecP.getH());
    -        }
    -        else if (params.isImplicitlyCA())
    -        {
    -            ecSpec = null;
    -            curve = configuration.getEcImplicitlyCa().getCurve();
    -        }
    -        else
    -        {
    -            X9ECParameters          ecP = X9ECParameters.getInstance(params.getParameters());
    -
    -            curve = ecP.getCurve();
    -            ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
    -
    -            this.ecSpec = new ECParameterSpec(
    -                    ellipticCurve,
    -                    new ECPoint(
    -                            ecP.getG().getAffineXCoord().toBigInteger(),
    -                            ecP.getG().getAffineYCoord().toBigInteger()),
    -                    ecP.getN(),
    -                    ecP.getH().intValue());
    -        }
    +        ECCurve curve = EC5Util.getCurve(configuration, params);
    +        ecSpec = EC5Util.convertToSpec(params, curve);
     
             DERBitString    bits = info.getPublicKeyData();
             byte[]          data = bits.getBytes();
    @@ -262,6 +228,7 @@ public class BCECPublicKey
                     }
                 }
             }
    +
             X9ECPoint derQ = new X9ECPoint(curve, key);
     
             this.q = derQ.getPoint();
    @@ -369,14 +336,7 @@ public class BCECPublicKey
         {
             if (ecSpec == null)
             {
    -            if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp)
    -            {
    -                return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord());
    -            }
    -            else
    -            {
    -                return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord());
    -            }
    +            return q.getDetachedPoint();
             }
     
             return q;
    @@ -400,7 +360,7 @@ public class BCECPublicKey
         public String toString()
         {
             StringBuffer    buf = new StringBuffer();
    -        String          nl = System.getProperty("line.separator");
    +        String          nl = Strings.lineSeparator();
     
             buf.append("EC Public Key").append(nl);
             buf.append("            X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl);
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java
    new file mode 100644
    index 0000000..dc92e0e
    --- /dev/null
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java
    @@ -0,0 +1,45 @@
    +package org.bouncycastle.jcajce.provider.asymmetric.ec;
    +
    +import java.security.spec.ECGenParameterSpec;
    +
    +import org.bouncycastle.asn1.ASN1ObjectIdentifier;
    +import org.bouncycastle.asn1.x9.X9ECParameters;
    +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
    +
    +class ECUtils
    +{
    +    static X9ECParameters getDomainParametersFromGenSpec(ECGenParameterSpec genSpec)
    +    {
    +        return getDomainParametersFromName(genSpec.getName());
    +    }
    +
    +    static X9ECParameters getDomainParametersFromName(String curveName)
    +    {
    +        X9ECParameters domainParameters;
    +        try
    +        {
    +            if (curveName.charAt(0) >= '0' && curveName.charAt(0) <= '2')
    +            {
    +                ASN1ObjectIdentifier oidID = new ASN1ObjectIdentifier(curveName);
    +                domainParameters = ECUtil.getNamedCurveByOid(oidID);
    +            }
    +            else
    +            {
    +                if (curveName.indexOf(' ') > 0)
    +                {
    +                    curveName = curveName.substring(curveName.indexOf(' ') + 1);
    +                    domainParameters = ECUtil.getNamedCurveByName(curveName);
    +                }
    +                else
    +                {
    +                    domainParameters = ECUtil.getNamedCurveByName(curveName);
    +                }
    +            }
    +        }
    +        catch (IllegalArgumentException ex)
    +        {
    +            domainParameters = ECUtil.getNamedCurveByName(curveName);
    +        }
    +        return domainParameters;
    +    }
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
    index ea36dfd..18fb306 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
    @@ -4,20 +4,11 @@ import java.math.BigInteger;
     import java.security.InvalidAlgorithmParameterException;
     import java.security.InvalidKeyException;
     import java.security.Key;
    -import java.security.NoSuchAlgorithmException;
     import java.security.PrivateKey;
     import java.security.PublicKey;
     import java.security.SecureRandom;
     import java.security.spec.AlgorithmParameterSpec;
    -import java.util.Hashtable;
     
    -import javax.crypto.SecretKey;
    -import javax.crypto.ShortBufferException;
    -import javax.crypto.spec.SecretKeySpec;
    -
    -import org.bouncycastle.asn1.ASN1ObjectIdentifier;
    -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
    -import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
     import org.bouncycastle.asn1.x9.X9IntegerConverter;
     import org.bouncycastle.crypto.BasicAgreement;
     import org.bouncycastle.crypto.CipherParameters;
    @@ -26,10 +17,16 @@ import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
     // BEGIN android-removed
     // import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement;
     // import org.bouncycastle.crypto.agreement.ECMQVBasicAgreement;
    -// import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
    -// import org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator;
    +// import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator;
     // END android-removed
     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;
    +// BEGIN android-removed
    +// import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
    +// END android-removed
     import org.bouncycastle.crypto.params.ECDomainParameters;
     import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
     import org.bouncycastle.crypto.params.ECPublicKeyParameters;
    @@ -37,14 +34,18 @@ import org.bouncycastle.crypto.params.ECPublicKeyParameters;
     // import org.bouncycastle.crypto.params.MQVPrivateParameters;
     // import org.bouncycastle.crypto.params.MQVPublicParameters;
     // END android-removed
    +import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
     import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
    +// BEGIN android-removed
    +// import org.bouncycastle.jcajce.spec.MQVParameterSpec;
    +// END android-removed
    +import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
     import org.bouncycastle.jce.interfaces.ECPrivateKey;
     import org.bouncycastle.jce.interfaces.ECPublicKey;
     // BEGIN android-removed
     // import org.bouncycastle.jce.interfaces.MQVPrivateKey;
     // import org.bouncycastle.jce.interfaces.MQVPublicKey;
     // END android-removed
    -import org.bouncycastle.util.Integers;
     
     /**
      * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
    @@ -53,50 +54,34 @@ import org.bouncycastle.util.Integers;
      * Also, MQV key agreement per SEC-1
      */
     public class KeyAgreementSpi
    -    extends javax.crypto.KeyAgreementSpi
    +    extends BaseAgreementSpi
     {
         private static final X9IntegerConverter converter = new X9IntegerConverter();
    -    private static final Hashtable algorithms = new Hashtable();
    -
    -    static
    -    {
    -        Integer i128 = Integers.valueOf(128);
    -        Integer i192 = Integers.valueOf(192);
    -        Integer i256 = Integers.valueOf(256);
    -
    -        algorithms.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
    -        algorithms.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
    -        algorithms.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), i256);
    -        algorithms.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), i128);
    -        algorithms.put(NISTObjectIdentifiers.id_aes192_wrap.getId(), i192);
    -        algorithms.put(NISTObjectIdentifiers.id_aes256_wrap.getId(), i256);
    -        algorithms.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
    -    }
     
         private String                 kaAlgorithm;
    -    private BigInteger             result;
    +
         private ECDomainParameters     parameters;
         private BasicAgreement         agreement;
    +
         // BEGIN android-removed
    -    // private DerivationFunction     kdf;
    +    // private MQVParameterSpec       mqvParameters;
         // END android-removed
     
    -    private byte[] bigIntToBytes(
    -        BigInteger    r)
    -    {
    -        return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getAffineXCoord()));
    -    }
    -
         protected KeyAgreementSpi(
             String kaAlgorithm,
             BasicAgreement agreement,
             DerivationFunction kdf)
         {
    +        super(kaAlgorithm, kdf);
    +
             this.kaAlgorithm = kaAlgorithm;
             this.agreement = agreement;
    -        // BEGIN android-removed
    -        // this.kdf = kdf;
    -        // END android-removed
    +    }
    +
    +    protected byte[] bigIntToBytes(
    +        BigInteger    r)
    +    {
    +        return converter.integerToBytes(r, converter.getByteLength(parameters.getCurve()));
         }
     
         protected Key engineDoPhase(
    @@ -120,19 +105,25 @@ public class KeyAgreementSpi
             // {
             //     if (!(key instanceof MQVPublicKey))
             //     {
    -        //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
    -        //             + getSimpleName(MQVPublicKey.class) + " for doPhase");
    -        //     }
    +        //         ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
    +        //             ECUtil.generatePublicKeyParameter((PublicKey)key);
    +        //         ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
    +        //             ECUtil.generatePublicKeyParameter(mqvParameters.getOtherPartyEphemeralKey());
             //
    -        //     MQVPublicKey mqvPubKey = (MQVPublicKey)key;
    -        //     ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
    -        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
    -        //     ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
    -        //         ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
    +        //         pubKey = new MQVPublicParameters(staticKey, ephemKey);
    +        //     }
    +        //     else
    +        //     {
    +        //         MQVPublicKey mqvPubKey = (MQVPublicKey)key;
    +        //         ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
    +        //             ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
    +        //         ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
    +        //             ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
             //
    -        //     pubKey = new MQVPublicParameters(staticKey, ephemKey);
    +        //         pubKey = new MQVPublicParameters(staticKey, ephemKey);
             //
    -        //     // TODO Validate that all the keys are using the same parameters?
    +        //         // TODO Validate that all the keys are using the same parameters?
    +        //     }
             // }
             // else
             // END android-removed
    @@ -153,82 +144,20 @@ public class KeyAgreementSpi
             return null;
         }
     
    -    protected byte[] engineGenerateSecret()
    -        throws IllegalStateException
    -    {
    -        // BEGIN android-removed
    -        // if (kdf != null)
    -        // {
    -        //     throw new UnsupportedOperationException(
    -        //         "KDF can only be used when algorithm is known");
    -        // }
    -        // END android-removed
    -
    -        return bigIntToBytes(result);
    -    }
    -
    -    protected int engineGenerateSecret(
    -        byte[]  sharedSecret,
    -        int     offset) 
    -        throws IllegalStateException, ShortBufferException
    -    {
    -        byte[] secret = engineGenerateSecret();
    -
    -        if (sharedSecret.length - offset < secret.length)
    -        {
    -            throw new ShortBufferException(kaAlgorithm + " key agreement: need " + secret.length + " bytes");
    -        }
    -
    -        System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
    -        
    -        return secret.length;
    -    }
    -
    -    protected SecretKey engineGenerateSecret(
    -        String algorithm)
    -        throws NoSuchAlgorithmException
    -    {
    -        byte[] secret = bigIntToBytes(result);
    -
    -        // BEGIN android-removed
    -        // if (kdf != null)
    -        // {
    -        //     if (!algorithms.containsKey(algorithm))
    -        //     {
    -        //         throw new NoSuchAlgorithmException("unknown algorithm encountered: " + algorithm);
    -        //     }
    -        //     
    -        //     int    keySize = ((Integer)algorithms.get(algorithm)).intValue();
    -        //
    -        //     DHKDFParameters params = new DHKDFParameters(new ASN1ObjectIdentifier(algorithm), keySize, secret);
    -        //
    -        //     byte[] keyBytes = new byte[keySize / 8];
    -        //     kdf.init(params);
    -        //     kdf.generateBytes(keyBytes, 0, keyBytes.length);
    -        //     secret = keyBytes;
    -        // }
    -        // else
    -        // END android-removed
    -        {
    -            // TODO Should we be ensuring the key is the right length?
    -        }
    -
    -        return new SecretKeySpec(secret, algorithm);
    -    }
    -
         protected void engineInit(
             Key                     key,
             AlgorithmParameterSpec  params,
             SecureRandom            random) 
             throws InvalidKeyException, InvalidAlgorithmParameterException
         {
    -        // BEGIN android-added
    -        if (params != null)
    +        // BEGIN android-changed
    +        if (params != null && !(params instanceof UserKeyingMaterialSpec))
    +        // END android-changed
             {
                 throw new InvalidAlgorithmParameterException("No algorithm parameters supported");
             }
    -        // END android-added
    -        initFromKey(key);
    +
    +        initFromKey(key, params);
         }
     
         protected void engineInit(
    @@ -236,32 +165,57 @@ public class KeyAgreementSpi
             SecureRandom    random) 
             throws InvalidKeyException
         {
    -        initFromKey(key);
    +        initFromKey(key, null);
         }
     
    -    private void initFromKey(Key key)
    +    private void initFromKey(Key key, AlgorithmParameterSpec parameterSpec)
             throws InvalidKeyException
         {
             // BEGIN android-removed
             // if (agreement instanceof ECMQVBasicAgreement)
             // {
    -        //     if (!(key instanceof MQVPrivateKey))
    +        //     mqvParameters = null;
    +        //     if (!(key instanceof MQVPrivateKey) && !(parameterSpec instanceof MQVParameterSpec))
             //     {
             //         throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
    -        //             + getSimpleName(MQVPrivateKey.class) + " for initialisation");
    +        //             + getSimpleName(MQVParameterSpec.class) + " for initialisation");
             //     }
             //
    -        //     MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
    -        //     ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
    -        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
    -        //     ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
    -        //         ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
    +        //     ECPrivateKeyParameters staticPrivKey;
    +        //     ECPrivateKeyParameters ephemPrivKey;
    +        //     ECPublicKeyParameters ephemPubKey;
    +        //     if (key instanceof MQVPrivateKey)
    +        //     {
    +        //         MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
    +        //         staticPrivKey = (ECPrivateKeyParameters)
    +        //             ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
    +        //         ephemPrivKey = (ECPrivateKeyParameters)
    +        //             ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
             //
    -        //     ECPublicKeyParameters ephemPubKey = null;
    -        //     if (mqvPrivKey.getEphemeralPublicKey() != null)
    +        //         ephemPubKey = null;
    +        //         if (mqvPrivKey.getEphemeralPublicKey() != null)
    +        //         {
    +        //             ephemPubKey = (ECPublicKeyParameters)
    +        //                 ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
    +        //         }
    +        //     }
    +        //     else
             //     {
    -        //         ephemPubKey = (ECPublicKeyParameters)
    -        //             ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
    +        //         MQVParameterSpec mqvParameterSpec = (MQVParameterSpec)parameterSpec;
    +        //
    +        //         staticPrivKey = (ECPrivateKeyParameters)
    +        //             ECUtil.generatePrivateKeyParameter((PrivateKey)key);
    +        //         ephemPrivKey = (ECPrivateKeyParameters)
    +        //             ECUtil.generatePrivateKeyParameter(mqvParameterSpec.getEphemeralPrivateKey());
    +        //
    +        //         ephemPubKey = null;
    +        //         if (mqvParameterSpec.getEphemeralPublicKey() != null)
    +        //         {
    +        //             ephemPubKey = (ECPublicKeyParameters)
    +        //                 ECUtil.generatePublicKeyParameter(mqvParameterSpec.getEphemeralPublicKey());
    +        //         }
    +        //         mqvParameters = mqvParameterSpec;
    +        //         ukmParameters = mqvParameterSpec.getUserKeyingMaterial();
             //     }
             //
             //     MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
    @@ -282,7 +236,7 @@ public class KeyAgreementSpi
     
                 ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
                 this.parameters = privKey.getParameters();
    -
    +            ukmParameters = (parameterSpec instanceof UserKeyingMaterialSpec) ? ((UserKeyingMaterialSpec)parameterSpec).getUserKeyingMaterial() : null;
                 agreement.init(privKey);
             }
         }
    @@ -327,17 +281,223 @@ public class KeyAgreementSpi
         // {
         //     public DHwithSHA1KDF()
         //     {
    -    //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
    +    //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest()));
         //     }
         // }
         //
    -    // public static class MQVwithSHA1KDF
    +    // public static class DHwithSHA1KDFAndSharedInfo
         //     extends KeyAgreementSpi
         // {
    -    //     public MQVwithSHA1KDF()
    +    //     public DHwithSHA1KDFAndSharedInfo()
         //     {
    -    //         super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
    +    //         super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class CDHwithSHA1KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public CDHwithSHA1KDFAndSharedInfo()
    +    //     {
    +    //         super("ECCDHwithSHA1KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class DHwithSHA224KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public DHwithSHA224KDFAndSharedInfo()
    +    //     {
    +    //         super("ECDHwithSHA224KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA224Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class CDHwithSHA224KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public CDHwithSHA224KDFAndSharedInfo()
    +    //     {
    +    //         super("ECCDHwithSHA224KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA224Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class DHwithSHA256KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public DHwithSHA256KDFAndSharedInfo()
    +    //     {
    +    //         super("ECDHwithSHA256KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class CDHwithSHA256KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public CDHwithSHA256KDFAndSharedInfo()
    +    //     {
    +    //         super("ECCDHwithSHA256KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class DHwithSHA384KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public DHwithSHA384KDFAndSharedInfo()
    +    //     {
    +    //         super("ECDHwithSHA384KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class CDHwithSHA384KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public CDHwithSHA384KDFAndSharedInfo()
    +    //     {
    +    //         super("ECCDHwithSHA384KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class DHwithSHA512KDFAndSharedInfo
    +    //      extends KeyAgreementSpi
    +    //  {
    +    //      public DHwithSHA512KDFAndSharedInfo()
    +    //      {
    +    //          super("ECDHwithSHA512KDF", new ECDHBasicAgreement(), new KDF2BytesGenerator(new SHA512Digest()));
    +    //      }
    +    //  }
    +    //
    +    //  public static class CDHwithSHA512KDFAndSharedInfo
    +    //      extends KeyAgreementSpi
    +    //  {
    +    //      public CDHwithSHA512KDFAndSharedInfo()
    +    //      {
    +    //          super("ECCDHwithSHA512KDF", new ECDHCBasicAgreement(), new KDF2BytesGenerator(new SHA512Digest()));
    +    //      }
    +    //  }
    +    //
    +    // public static class MQVwithSHA1KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA1KDFAndSharedInfo()
    +    //     {
    +    //         super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA1Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class MQVwithSHA224KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA224KDFAndSharedInfo()
    +    //     {
    +    //         super("ECMQVwithSHA224KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA224Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class MQVwithSHA256KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA256KDFAndSharedInfo()
    +    //     {
    +    //         super("ECMQVwithSHA256KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA256Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class MQVwithSHA384KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA384KDFAndSharedInfo()
    +    //     {
    +    //         super("ECMQVwithSHA384KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA384Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class MQVwithSHA512KDFAndSharedInfo
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA512KDFAndSharedInfo()
    +    //     {
    +    //         super("ECMQVwithSHA512KDF", new ECMQVBasicAgreement(), new KDF2BytesGenerator(new SHA512Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class DHwithSHA1CKDF
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public DHwithSHA1CKDF()
    +    //     {
    +    //         super("ECDHwithSHA1CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA1Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class DHwithSHA256CKDF
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public DHwithSHA256CKDF()
    +    //     {
    +    //         super("ECDHwithSHA256CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA256Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class DHwithSHA384CKDF
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public DHwithSHA384CKDF()
    +    //     {
    +    //         super("ECDHwithSHA384CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA384Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class DHwithSHA512CKDF
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public DHwithSHA512CKDF()
    +    //     {
    +    //         super("ECDHwithSHA512CKDF", new ECDHCBasicAgreement(), new ConcatenationKDFGenerator(new SHA512Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class MQVwithSHA1CKDF
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA1CKDF()
    +    //     {
    +    //         super("ECMQVwithSHA1CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA1Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class MQVwithSHA224CKDF
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA224CKDF()
    +    //     {
    +    //         super("ECMQVwithSHA224CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA224Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class MQVwithSHA256CKDF
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA256CKDF()
    +    //     {
    +    //         super("ECMQVwithSHA256CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA256Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class MQVwithSHA384CKDF
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA384CKDF()
    +    //     {
    +    //         super("ECMQVwithSHA384CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA384Digest()));
    +    //     }
    +    // }
    +    //
    +    // public static class MQVwithSHA512CKDF
    +    //     extends KeyAgreementSpi
    +    // {
    +    //     public MQVwithSHA512CKDF()
    +    //     {
    +    //         super("ECMQVwithSHA512CKDF", new ECMQVBasicAgreement(), new ConcatenationKDFGenerator(new SHA512Digest()));
         //     }
         // }
    -    // END android-removed
     }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
    index 42bb895..9a9c46b 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
    @@ -42,7 +42,9 @@ public abstract class KeyPairGeneratorSpi
             ECKeyGenerationParameters   param;
             ECKeyPairGenerator          engine = new ECKeyPairGenerator();
             Object                      ecParams = null;
    -        int                         strength = 239;
    +        // BEGIN android-changed
    +        int                         strength = 256;
    +        // BEGIN android-changed
             int                         certainty = 50;
             SecureRandom                random = new SecureRandom();
             boolean                     initialised = false;
    @@ -91,22 +93,20 @@ public abstract class KeyPairGeneratorSpi
                 // BEGIN android-added
                 }
                 // END android-added
    +
                 ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(Integers.valueOf(strength));
    +            if (ecParams == null)
    +            {
    +                throw new InvalidParameterException("unknown key size.");
    +            }
     
    -            if (ecParams != null)
    +            try
                 {
    -                try
    -                {
    -                    initialize(ecParams, random);
    -                }
    -                catch (InvalidAlgorithmParameterException e)
    -                {
    -                    throw new InvalidParameterException("key size not configurable.");
    -                }
    +                initialize(ecParams, random);
                 }
    -            else
    +            catch (InvalidAlgorithmParameterException e)
                 {
    -                throw new InvalidParameterException("unknown key size.");
    +                throw new InvalidParameterException("key size not configurable.");
                 }
             }
     
    @@ -120,97 +120,42 @@ public abstract class KeyPairGeneratorSpi
                     random = this.random;
                 }
                 // END android-added
    -            if (params instanceof ECParameterSpec)
    +            if (params == null)
                 {
    -                ECParameterSpec p = (ECParameterSpec)params;
    -                this.ecParams = params;
    -
    -                param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
    +                ECParameterSpec implicitCA = configuration.getEcImplicitlyCa();
    +                if (implicitCA == null)
    +                {
    +                    throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
    +                }
     
    -                engine.init(param);
    -                initialised = true;
    +                this.ecParams = null;
    +                this.param = createKeyGenParamsBC(implicitCA, random);
                 }
    -            else if (params instanceof java.security.spec.ECParameterSpec)
    +            else if (params instanceof ECParameterSpec)
                 {
    -                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)params;
                     this.ecParams = params;
    -
    -                ECCurve curve = EC5Util.convertCurve(p.getCurve());
    -                ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
    -
    -                param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
    -
    -                engine.init(param);
    -                initialised = true;
    +                this.param = createKeyGenParamsBC((ECParameterSpec)params, random);
                 }
    -            else if (params instanceof ECGenParameterSpec || params instanceof ECNamedCurveGenParameterSpec)
    +            else if (params instanceof java.security.spec.ECParameterSpec)
                 {
    -                String curveName;
    -
    -                if (params instanceof ECGenParameterSpec)
    -                {
    -                    curveName = ((ECGenParameterSpec)params).getName();
    -                }
    -                else
    -                {
    -                    curveName = ((ECNamedCurveGenParameterSpec)params).getName();
    -                }
    -
    -                X9ECParameters  ecP = ECNamedCurveTable.getByName(curveName);
    -                if (ecP == null)
    -                {
    -                    // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
    -                    try
    -                    {
    -                        ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName);
    -                        ecP = ECNamedCurveTable.getByOID(oid);
    -                        if (ecP == null)
    -                        {
    -                            throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
    -                        }
    -                    }
    -                    catch (IllegalArgumentException ex)
    -                    {
    -                        throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
    -                    }
    -                }
    -
    -                this.ecParams = new ECNamedCurveSpec(
    -                            curveName,
    -                            ecP.getCurve(),
    -                            ecP.getG(),
    -                            ecP.getN(),
    -                            ecP.getH(),
    -                            null); // ecP.getSeed());   Work-around JDK bug -- it won't look up named curves properly if seed is present
    -
    -                java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
    -
    -                ECCurve curve = EC5Util.convertCurve(p.getCurve());
    -                ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
    -
    -                param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random);
    -
    -                engine.init(param);
    -                initialised = true;
    +                this.ecParams = params;
    +                this.param = createKeyGenParamsJCE((java.security.spec.ECParameterSpec)params, random);
                 }
    -            else if (params == null && configuration.getEcImplicitlyCa() != null)
    +            else if (params instanceof ECGenParameterSpec)
                 {
    -                ECParameterSpec p = configuration.getEcImplicitlyCa();
    -                this.ecParams = params;
    -
    -                param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
    -
    -                engine.init(param);
    -                initialised = true;
    +                initializeNamedCurve(((ECGenParameterSpec)params).getName(), random);
                 }
    -            else if (params == null && configuration.getEcImplicitlyCa() == null)
    +            else if (params instanceof ECNamedCurveGenParameterSpec)
                 {
    -                throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
    +                initializeNamedCurve(((ECNamedCurveGenParameterSpec)params).getName(), random);
                 }
                 else
                 {
                     throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec");
                 }
    +
    +            engine.init(param);
    +            initialised = true;
             }
     
             public KeyPair generateKeyPair()
    @@ -246,6 +191,58 @@ public abstract class KeyPairGeneratorSpi
                     return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
                 }
             }
    +
    +        protected ECKeyGenerationParameters createKeyGenParamsBC(ECParameterSpec p, SecureRandom r)
    +        {
    +            return new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), r);
    +        }
    +
    +        protected ECKeyGenerationParameters createKeyGenParamsJCE(java.security.spec.ECParameterSpec p, SecureRandom r)
    +        {
    +            ECCurve curve = EC5Util.convertCurve(p.getCurve());
    +            ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false);
    +            BigInteger n = p.getOrder();
    +            BigInteger h = BigInteger.valueOf(p.getCofactor());
    +            ECDomainParameters dp = new ECDomainParameters(curve, g, n, h);
    +            return new ECKeyGenerationParameters(dp, r);
    +        }
    +
    +        protected ECNamedCurveSpec createNamedCurveSpec(String curveName)
    +            throws InvalidAlgorithmParameterException
    +        {
    +            // NOTE: Don't bother with custom curves here as the curve will be converted to JCE type shortly
    +
    +            X9ECParameters p = ECUtils.getDomainParametersFromName(curveName);
    +            if (p == null)
    +            {
    +                try
    +                {
    +                    // Check whether it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
    +                    p = ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(curveName));
    +                    if (p == null)
    +                    {
    +                        throw new InvalidAlgorithmParameterException("unknown curve OID: " + curveName);
    +                    }
    +                }
    +                catch (IllegalArgumentException ex)
    +                {
    +                    throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName);
    +                }
    +            }
    +
    +            // Work-around for JDK bug -- it won't look up named curves properly if seed is present
    +            byte[] seed = null; //p.getSeed();
    +
    +            return new ECNamedCurveSpec(curveName, p.getCurve(), p.getG(), p.getN(), p.getH(), seed);
    +        }
    +
    +        protected void initializeNamedCurve(String curveName, SecureRandom random)
    +            throws InvalidAlgorithmParameterException
    +        {
    +            ECNamedCurveSpec namedCurve = createNamedCurveSpec(curveName);
    +            this.ecParams = namedCurve;
    +            this.param = createKeyGenParamsJCE(namedCurve, random);
    +        }
         }
     
         public static class ECDSA
    @@ -283,4 +280,4 @@ public abstract class KeyPairGeneratorSpi
                 super("ECMQV", BouncyCastleProvider.CONFIGURATION);
             }
         }
    -}
    \ No newline at end of file
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
    index 3757229..26811d1 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
    @@ -249,7 +249,7 @@ public class SignatureSpi
         // {
         //     public ecCVCDSA()
         //     {
    -    //         super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
    +    //         super(new SHA1Digest(), new ECDSASigner(), new PlainDSAEncoder());
         //     }
         // }
         //
    @@ -258,7 +258,7 @@ public class SignatureSpi
         // {
         //     public ecCVCDSA224()
         //     {
    -    //         super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
    +    //         super(new SHA224Digest(), new ECDSASigner(), new PlainDSAEncoder());
         //     }
         // }
         //
    @@ -267,7 +267,7 @@ public class SignatureSpi
         // {
         //     public ecCVCDSA256()
         //     {
    -    //         super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
    +    //         super(new SHA256Digest(), new ECDSASigner(), new PlainDSAEncoder());
         //     }
         // }
         //
    @@ -276,7 +276,7 @@ public class SignatureSpi
         // {
         //     public ecCVCDSA384()
         //     {
    -    //         super(new SHA384Digest(), new ECDSASigner(), new CVCDSAEncoder());
    +    //         super(new SHA384Digest(), new ECDSASigner(), new PlainDSAEncoder());
         //     }
         // }
         //
    @@ -285,7 +285,16 @@ public class SignatureSpi
         // {
         //     public ecCVCDSA512()
         //     {
    -    //         super(new SHA512Digest(), new ECDSASigner(), new CVCDSAEncoder());
    +    //         super(new SHA512Digest(), new ECDSASigner(), new PlainDSAEncoder());
    +    //     }
    +    // }
    +    //
    +    // static public class ecPlainDSARP160
    +    //     extends SignatureSpi
    +    // {
    +    //     public ecPlainDSARP160()
    +    //     {
    +    //         super(new RIPEMD160Digest(), new ECDSASigner(), new PlainDSAEncoder());
         //     }
         // }
         // END android-removed
    @@ -320,66 +329,68 @@ public class SignatureSpi
             }
         }
     
    -    private static class CVCDSAEncoder
    -        implements DSAEncoder
    -    {
    -        public byte[] encode(
    -            BigInteger r,
    -            BigInteger s)
    -            throws IOException
    -        {
    -            byte[] first = makeUnsigned(r);
    -            byte[] second = makeUnsigned(s);
    -            byte[] res;
    -
    -            if (first.length > second.length)
    -            {
    -                res = new byte[first.length * 2];
    -            }
    -            else
    -            {
    -                res = new byte[second.length * 2];
    -            }
    -
    -            System.arraycopy(first, 0, res, res.length / 2 - first.length, first.length);
    -            System.arraycopy(second, 0, res, res.length - second.length, second.length);
    -
    -            return res;
    -        }
    -
    -
    -        private byte[] makeUnsigned(BigInteger val)
    -        {
    -            byte[] res = val.toByteArray();
    -
    -            if (res[0] == 0)
    -            {
    -                byte[] tmp = new byte[res.length - 1];
    -
    -                System.arraycopy(res, 1, tmp, 0, tmp.length);
    -
    -                return tmp;
    -            }
    -
    -            return res;
    -        }
    -
    -        public BigInteger[] decode(
    -            byte[] encoding)
    -            throws IOException
    -        {
    -            BigInteger[] sig = new BigInteger[2];
    -
    -            byte[] first = new byte[encoding.length / 2];
    -            byte[] second = new byte[encoding.length / 2];
    -
    -            System.arraycopy(encoding, 0, first, 0, first.length);
    -            System.arraycopy(encoding, first.length, second, 0, second.length);
    -
    -            sig[0] = new BigInteger(1, first);
    -            sig[1] = new BigInteger(1, second);
    -
    -            return sig;
    -        }
    -    }
    +    // BEGIN android-removed
    +    // private static class PlainDSAEncoder
    +    //     implements DSAEncoder
    +    // {
    +    //     public byte[] encode(
    +    //         BigInteger r,
    +    //         BigInteger s)
    +    //         throws IOException
    +    //     {
    +    //         byte[] first = makeUnsigned(r);
    +    //         byte[] second = makeUnsigned(s);
    +    //         byte[] res;
    +    //
    +    //         if (first.length > second.length)
    +    //         {
    +    //             res = new byte[first.length * 2];
    +    //         }
    +    //         else
    +    //         {
    +    //             res = new byte[second.length * 2];
    +    //         }
    +    //
    +    //         System.arraycopy(first, 0, res, res.length / 2 - first.length, first.length);
    +    //         System.arraycopy(second, 0, res, res.length - second.length, second.length);
    +    //
    +    //         return res;
    +    //     }
    +    //
    +    //
    +    //     private byte[] makeUnsigned(BigInteger val)
    +    //     {
    +    //         byte[] res = val.toByteArray();
    +    //
    +    //         if (res[0] == 0)
    +    //         {
    +    //             byte[] tmp = new byte[res.length - 1];
    +    //
    +    //             System.arraycopy(res, 1, tmp, 0, tmp.length);
    +    //
    +    //             return tmp;
    +    //         }
    +    //
    +    //         return res;
    +    //     }
    +    //
    +    //     public BigInteger[] decode(
    +    //         byte[] encoding)
    +    //         throws IOException
    +    //     {
    +    //         BigInteger[] sig = new BigInteger[2];
    +    //
    +    //         byte[] first = new byte[encoding.length / 2];
    +    //         byte[] second = new byte[encoding.length / 2];
    +    //
    +    //         System.arraycopy(encoding, 0, first, 0, first.length);
    +    //         System.arraycopy(encoding, first.length, second, 0, second.length);
    +    //
    +    //         sig[0] = new BigInteger(1, first);
    +    //         sig[1] = new BigInteger(1, second);
    +    //
    +    //         return sig;
    +    //     }
    +    // }
    +    // END android-removed
     }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
    index baee6d5..de5a9aa 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
    @@ -90,7 +90,7 @@ public abstract class AlgorithmParametersSpi
                 Class paramSpec)
                 throws InvalidParameterSpecException
             {
    -            if (paramSpec == OAEPParameterSpec.class && currentSpec != null)
    +            if (paramSpec == OAEPParameterSpec.class || paramSpec == AlgorithmParameterSpec.class)
                 {
                     return currentSpec;
                 }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
    index 9b70d74..d81d197 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
    @@ -12,6 +12,7 @@ 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;
    +import org.bouncycastle.util.Strings;
     
     /**
      * A provider representation for a RSA private key, with CRT factors included.
    @@ -224,7 +225,7 @@ public class BCRSAPrivateCrtKey
         public String toString()
         {
             StringBuffer    buf = new StringBuffer();
    -        String          nl = System.getProperty("line.separator");
    +        String          nl = Strings.lineSeparator();
     
             buf.append("RSA Private CRT Key").append(nl);
             buf.append("            modulus: ").append(this.getModulus().toString(16)).append(nl);
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
    index 0aa81b4..b82c5f8 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
    @@ -55,6 +55,12 @@ public class BCRSAPrivateKey
             this.privateExponent = key.getPrivateExponent();
         }
     
    +    BCRSAPrivateKey(org.bouncycastle.asn1.pkcs.RSAPrivateKey key)
    +    {
    +        this.modulus = key.getModulus();
    +        this.privateExponent = key.getPrivateExponent();
    +    }
    +
         public BigInteger getModulus()
         {
             return modulus;
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
    index a2114fa..669cf2b 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
    @@ -1,5 +1,6 @@
     package org.bouncycastle.jcajce.provider.asymmetric.rsa;
     
    +import java.io.EOFException;
     import java.io.IOException;
     import java.io.ObjectInputStream;
     import java.io.ObjectOutputStream;
    @@ -14,6 +15,7 @@ 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;
    +import org.bouncycastle.util.Strings;
     
     public class BCRSAPublicKey
         implements RSAPublicKey
    @@ -133,7 +135,7 @@ public class BCRSAPublicKey
         public String toString()
         {
             StringBuffer    buf = new StringBuffer();
    -        String          nl = System.getProperty("line.separator");
    +        String          nl = Strings.lineSeparator();
     
             buf.append("RSA Public Key").append(nl);
             buf.append("            modulus: ").append(this.getModulus().toString(16)).append(nl);
    @@ -152,7 +154,7 @@ public class BCRSAPublicKey
             {
                 algorithmIdentifier = AlgorithmIdentifier.getInstance(in.readObject());
             }
    -        catch (OptionalDataException e)
    +        catch (Exception e)
             {
                 algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER;
             }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
    index ae40cbe..81e5013 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
    @@ -35,12 +35,15 @@ 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.jcajce.util.BCJcaJceHelper;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
     import org.bouncycastle.util.Strings;
     
     public class CipherSpi
         extends BaseCipherSpi
     {
    +    private final JcaJceHelper helper = new BCJcaJceHelper();
    +
         private AsymmetricBlockCipher cipher;
         private AlgorithmParameterSpec paramSpec;
         private AlgorithmParameters engineParams;
    @@ -145,7 +148,7 @@ public class CipherSpi
                 {
                     try
                     {
    -                    engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
    +                    engineParams = helper.createAlgorithmParameters("OAEP");
                         engineParams.init(paramSpec);
                     }
                     catch (Exception e)
    @@ -311,7 +314,7 @@ public class CipherSpi
             }
             else
             {
    -            throw new IllegalArgumentException("unknown parameter type.");
    +            throw new InvalidAlgorithmParameterException("unknown parameter type: " + params.getClass().getName());
             }
     
             if (!(cipher instanceof RSABlindedEngine))
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
    index 13f7c93..9616a99 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
    @@ -25,6 +25,9 @@ import org.bouncycastle.asn1.x509.DigestInfo;
     import org.bouncycastle.crypto.AsymmetricBlockCipher;
     import org.bouncycastle.crypto.CipherParameters;
     import org.bouncycastle.crypto.Digest;
    +// BEGIN android-added
    +import org.bouncycastle.crypto.digests.AndroidDigestFactory;
    +// END android-added
     // BEGIN android-removed
     // import org.bouncycastle.crypto.digests.MD2Digest;
     // import org.bouncycastle.crypto.digests.MD4Digest;
    @@ -38,12 +41,11 @@ import org.bouncycastle.crypto.Digest;
     // import org.bouncycastle.crypto.digests.SHA256Digest;
     // import org.bouncycastle.crypto.digests.SHA384Digest;
     // import org.bouncycastle.crypto.digests.SHA512Digest;
    +// import org.bouncycastle.crypto.digests.SHA512tDigest;
     // 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;
    +import org.bouncycastle.util.Arrays;
     
     public class DigestSignatureSpi
         extends SignatureSpi
    @@ -178,13 +180,7 @@ public class DigestSignatureSpi
     
             if (sig.length == expected.length)
             {
    -            for (int i = 0; i < sig.length; i++)
    -            {
    -                if (sig[i] != expected[i])
    -                {
    -                    return false;
    -                }
    -            }
    +            return Arrays.constantTimeAreEqual(sig, expected);
             }
             else if (sig.length == expected.length - 2)  // NULL left out
             {
    @@ -194,28 +190,26 @@ public class DigestSignatureSpi
                 expected[1] -= 2;      // adjust lengths
                 expected[3] -= 2;
     
    +            int nonEqual = 0;
    +
                 for (int i = 0; i < hash.length; i++)
                 {
    -                if (sig[sigOffset + i] != expected[expectedOffset + i])  // check hash
    -                {
    -                    return false;
    -                }
    +                nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
                 }
     
                 for (int i = 0; i < sigOffset; i++)
                 {
    -                if (sig[i] != expected[i])  // check header less NULL
    -                {
    -                    return false;
    -                }
    +                nonEqual |= (sig[i] ^ expected[i]);  // check header less NULL
                 }
    +
    +            return nonEqual == 0;
             }
             else
             {
    +            Arrays.constantTimeAreEqual(expected, expected);  // keep time "steady".
    +
                 return false;
             }
    -
    -        return true;
         }
     
         protected void engineSetParameter(
    @@ -319,6 +313,24 @@ public class DigestSignatureSpi
         }
     
         // BEGIN android-removed
    +    // static public class SHA512_224
    +    //     extends DigestSignatureSpi
    +    // {
    +    //     public SHA512_224()
    +    //     {
    +    //         super(NISTObjectIdentifiers.id_sha512_224, new SHA512tDigest(224), new PKCS1Encoding(new RSABlindedEngine()));
    +    //     }
    +    // }
    +
    +    // static public class SHA512_256
    +    //     extends DigestSignatureSpi
    +    // {
    +    //     public SHA512_256()
    +    //     {
    +    //         super(NISTObjectIdentifiers.id_sha512_256, new SHA512tDigest(256), new PKCS1Encoding(new RSABlindedEngine()));
    +    //     }
    +    // }
    +
         // static public class MD2
         //     extends DigestSignatureSpi
         // {
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
    index d8eb539..80690f7 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
    @@ -137,7 +137,16 @@ public class KeyFactorySpi
     
             if (RSAUtil.isRsaOid(algOid))
             {
    -            return new BCRSAPrivateCrtKey(keyInfo);
    +            RSAPrivateKey rsaPrivKey = RSAPrivateKey.getInstance(keyInfo.parsePrivateKey());
    +
    +            if (rsaPrivKey.getCoefficient().intValue() == 0)
    +            {
    +                return new BCRSAPrivateKey(rsaPrivKey);
    +            }
    +            else
    +            {
    +                return new BCRSAPrivateCrtKey(keyInfo);
    +            }
             }
             else
             {
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
    index c61e7cb..adb130e 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
    @@ -23,7 +23,7 @@ public class KeyPairGeneratorSpi
         }
     
         final static BigInteger defaultPublicExponent = BigInteger.valueOf(0x10001);
    -    final static int defaultTests = 12;
    +    final static int defaultTests = 112;
     
         RSAKeyGenerationParameters param;
         RSAKeyPairGenerator engine;
    @@ -43,7 +43,10 @@ public class KeyPairGeneratorSpi
             SecureRandom random)
         {
             param = new RSAKeyGenerationParameters(defaultPublicExponent,
    -            random, strength, defaultTests);
    +            // BEGIN android-changed
    +            // Was: random, strength, defaultTests);
    +            (random != null) ? random : new SecureRandom(), strength, defaultTests);
    +            // END android-changed
     
             engine.init(param);
         }
    @@ -61,7 +64,10 @@ public class KeyPairGeneratorSpi
     
             param = new RSAKeyGenerationParameters(
                 rsaParams.getPublicExponent(),
    -            random, rsaParams.getKeysize(), defaultTests);
    +            // BEGIN android-changed
    +            // Was: random, rsaParams.getKeysize(), defaultTests);
    +            (random != null) ? random : new SecureRandom(), rsaParams.getKeysize(), defaultTests);
    +            // END android-changed
     
             engine.init(param);
         }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
    new file mode 100644
    index 0000000..16e7348
    --- /dev/null
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
    @@ -0,0 +1,323 @@
    +package org.bouncycastle.jcajce.provider.asymmetric.util;
    +
    +import java.math.BigInteger;
    +import java.security.NoSuchAlgorithmException;
    +import java.util.HashMap;
    +import java.util.Hashtable;
    +import java.util.Map;
    +
    +import javax.crypto.KeyAgreementSpi;
    +import javax.crypto.SecretKey;
    +import javax.crypto.ShortBufferException;
    +import javax.crypto.spec.SecretKeySpec;
    +
    +import org.bouncycastle.asn1.ASN1ObjectIdentifier;
    +// BEGIN android-removed
    +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
    +// import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
    +// END android-removed
    +import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
    +import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
    +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
    +import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
    +import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
    +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
    +import org.bouncycastle.crypto.DerivationFunction;
    +// BEGIN android-removed
    +// import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
    +// import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator;
    +// END android-removed
    +import org.bouncycastle.crypto.params.DESParameters;
    +import org.bouncycastle.crypto.params.KDFParameters;
    +import org.bouncycastle.util.Integers;
    +import org.bouncycastle.util.Strings;
    +
    +public abstract class BaseAgreementSpi
    +    extends KeyAgreementSpi
    +{
    +    private static final Map defaultOids = new HashMap();
    +    private static final Map keySizes = new HashMap();
    +    private static final Map nameTable = new HashMap();
    +
    +    private static final Hashtable oids = new Hashtable();
    +    private static final Hashtable des = new Hashtable();
    +
    +    static
    +    {
    +        Integer i64 = Integers.valueOf(64);
    +        Integer i128 = Integers.valueOf(128);
    +        Integer i192 = Integers.valueOf(192);
    +        Integer i256 = Integers.valueOf(256);
    +
    +        keySizes.put("DES", i64);
    +        keySizes.put("DESEDE", i192);
    +        keySizes.put("BLOWFISH", i128);
    +        keySizes.put("AES", i256);
    +
    +        keySizes.put(NISTObjectIdentifiers.id_aes128_ECB.getId(), i128);
    +        keySizes.put(NISTObjectIdentifiers.id_aes192_ECB.getId(), i192);
    +        keySizes.put(NISTObjectIdentifiers.id_aes256_ECB.getId(), i256);
    +        keySizes.put(NISTObjectIdentifiers.id_aes128_CBC.getId(), i128);
    +        keySizes.put(NISTObjectIdentifiers.id_aes192_CBC.getId(), i192);
    +        keySizes.put(NISTObjectIdentifiers.id_aes256_CBC.getId(), i256);
    +        keySizes.put(NISTObjectIdentifiers.id_aes128_CFB.getId(), i128);
    +        keySizes.put(NISTObjectIdentifiers.id_aes192_CFB.getId(), i192);
    +        keySizes.put(NISTObjectIdentifiers.id_aes256_CFB.getId(), i256);
    +        keySizes.put(NISTObjectIdentifiers.id_aes128_OFB.getId(), i128);
    +        keySizes.put(NISTObjectIdentifiers.id_aes192_OFB.getId(), i192);
    +        keySizes.put(NISTObjectIdentifiers.id_aes256_OFB.getId(), i256);
    +        keySizes.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), i128);
    +        keySizes.put(NISTObjectIdentifiers.id_aes192_wrap.getId(), i192);
    +        keySizes.put(NISTObjectIdentifiers.id_aes256_wrap.getId(), i256);
    +        keySizes.put(NISTObjectIdentifiers.id_aes128_CCM.getId(), i128);
    +        keySizes.put(NISTObjectIdentifiers.id_aes192_CCM.getId(), i192);
    +        keySizes.put(NISTObjectIdentifiers.id_aes256_CCM.getId(), i256);
    +        keySizes.put(NISTObjectIdentifiers.id_aes128_GCM.getId(), i128);
    +        keySizes.put(NISTObjectIdentifiers.id_aes192_GCM.getId(), i192);
    +        keySizes.put(NISTObjectIdentifiers.id_aes256_GCM.getId(), i256);
    +        keySizes.put(NTTObjectIdentifiers.id_camellia128_wrap.getId(), i128);
    +        keySizes.put(NTTObjectIdentifiers.id_camellia192_wrap.getId(), i192);
    +        keySizes.put(NTTObjectIdentifiers.id_camellia256_wrap.getId(), i256);
    +        keySizes.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap.getId(), i128);
    +
    +        keySizes.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), i192);
    +        keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), i192);
    +        keySizes.put(OIWObjectIdentifiers.desCBC.getId(), i64);
    +
    +        keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA1.getId(), Integers.valueOf(160));
    +        keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA256.getId(), i256);
    +        keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA384.getId(), Integers.valueOf(384));
    +        keySizes.put(PKCSObjectIdentifiers.id_hmacWithSHA512.getId(), Integers.valueOf(512));
    +
    +        defaultOids.put("DESEDE", PKCSObjectIdentifiers.des_EDE3_CBC);
    +        defaultOids.put("AES", NISTObjectIdentifiers.id_aes256_CBC);
    +        defaultOids.put("CAMELLIA", NTTObjectIdentifiers.id_camellia256_cbc);
    +        defaultOids.put("SEED", KISAObjectIdentifiers.id_seedCBC);
    +        defaultOids.put("DES", OIWObjectIdentifiers.desCBC);
    +
    +        nameTable.put(MiscObjectIdentifiers.cast5CBC.getId(), "CAST5");
    +        nameTable.put(MiscObjectIdentifiers.as_sys_sec_alg_ideaCBC.getId(), "IDEA");
    +        nameTable.put(MiscObjectIdentifiers.cryptlib_algorithm_blowfish_ECB.getId(), "Blowfish");
    +        nameTable.put(MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CBC.getId(), "Blowfish");
    +        nameTable.put(MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CFB.getId(), "Blowfish");
    +        nameTable.put(MiscObjectIdentifiers.cryptlib_algorithm_blowfish_OFB.getId(), "Blowfish");
    +        nameTable.put(OIWObjectIdentifiers.desECB.getId(), "DES");
    +        nameTable.put(OIWObjectIdentifiers.desCBC.getId(), "DES");
    +        nameTable.put(OIWObjectIdentifiers.desCFB.getId(), "DES");
    +        nameTable.put(OIWObjectIdentifiers.desOFB.getId(), "DES");
    +        nameTable.put(OIWObjectIdentifiers.desEDE.getId(), "DESede");
    +        nameTable.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), "DESede");
    +        nameTable.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), "DESede");
    +        nameTable.put(PKCSObjectIdentifiers.id_alg_CMSRC2wrap.getId(), "RC2");
    +        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA1.getId(), "HmacSHA1");
    +        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA224.getId(), "HmacSHA224");
    +        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA256.getId(), "HmacSHA256");
    +        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA384.getId(), "HmacSHA384");
    +        nameTable.put(PKCSObjectIdentifiers.id_hmacWithSHA512.getId(), "HmacSHA512");
    +        nameTable.put(NTTObjectIdentifiers.id_camellia128_cbc.getId(), "Camellia");
    +        nameTable.put(NTTObjectIdentifiers.id_camellia192_cbc.getId(), "Camellia");
    +        nameTable.put(NTTObjectIdentifiers.id_camellia256_cbc.getId(), "Camellia");
    +        nameTable.put(NTTObjectIdentifiers.id_camellia128_wrap.getId(), "Camellia");
    +        nameTable.put(NTTObjectIdentifiers.id_camellia192_wrap.getId(), "Camellia");
    +        nameTable.put(NTTObjectIdentifiers.id_camellia256_wrap.getId(), "Camellia");
    +        nameTable.put(KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap.getId(), "SEED");
    +        nameTable.put(KISAObjectIdentifiers.id_seedCBC.getId(), "SEED");
    +        nameTable.put(KISAObjectIdentifiers.id_seedMAC.getId(), "SEED");
    +        // BEGIN android-removed
    +        // nameTable.put(CryptoProObjectIdentifiers.gostR28147_gcfb.getId(), "GOST28147");
    +        // END android-removed
    +
    +        nameTable.put(NISTObjectIdentifiers.id_aes128_wrap.getId(), "AES");
    +        nameTable.put(NISTObjectIdentifiers.id_aes128_CCM.getId(), "AES");
    +        nameTable.put(NISTObjectIdentifiers.id_aes128_CCM.getId(), "AES");
    +
    +        oids.put("DESEDE", PKCSObjectIdentifiers.des_EDE3_CBC);
    +        oids.put("AES", NISTObjectIdentifiers.id_aes256_CBC);
    +        oids.put("DES", OIWObjectIdentifiers.desCBC);
    +
    +        des.put("DES", "DES");
    +        des.put("DESEDE", "DES");
    +        des.put(OIWObjectIdentifiers.desCBC.getId(), "DES");
    +        des.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), "DES");
    +        des.put(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId(), "DES");
    +    }
    +
    +    private final String kaAlgorithm;
    +    private final DerivationFunction kdf;
    +
    +    protected BigInteger result;
    +    protected byte[]     ukmParameters;
    +
    +    public BaseAgreementSpi(String kaAlgorithm, DerivationFunction kdf)
    +    {
    +        this.kaAlgorithm = kaAlgorithm;
    +        this.kdf = kdf;
    +    }
    +
    +    protected static String getAlgorithm(String algDetails)
    +    {
    +        if (algDetails.indexOf('[') > 0)
    +        {
    +            return algDetails.substring(0, algDetails.indexOf('['));
    +        }
    +
    +        if (algDetails.startsWith(NISTObjectIdentifiers.aes.getId()))
    +        {
    +            return "AES";
    +        }
    +        // BEGIN android-removed
    +        // if (algDetails.startsWith(GNUObjectIdentifiers.Serpent.getId()))
    +        // {
    +        //     return "Serpent";
    +        // }
    +        // END android-removed
    +
    +        String name = (String)nameTable.get(Strings.toUpperCase(algDetails));
    +
    +        if (name != null)
    +        {
    +            return name;
    +        }
    +
    +        return algDetails;
    +    }
    +
    +    protected static int getKeySize(String algDetails)
    +    {
    +        if (algDetails.indexOf('[') > 0)
    +        {
    +            return (Integer.parseInt(algDetails.substring(algDetails.indexOf('[') + 1, algDetails.indexOf(']'))) + 7) / 8;
    +        }
    +
    +        String algKey = Strings.toUpperCase(algDetails);
    +        if (!keySizes.containsKey(algKey))
    +        {
    +            return -1;
    +        }
    +
    +        return ((Integer)keySizes.get(algKey)).intValue();
    +    }
    +
    +    protected static byte[] trimZeroes(byte[] secret)
    +    {
    +        if (secret[0] != 0)
    +        {
    +            return secret;
    +        }
    +        else
    +        {
    +            int ind = 0;
    +            while (ind < secret.length && secret[ind] == 0)
    +            {
    +                ind++;
    +            }
    +
    +            byte[] rv = new byte[secret.length - ind];
    +
    +            System.arraycopy(secret, ind, rv, 0, rv.length);
    +
    +            return rv;
    +        }
    +    }
    +
    +    protected byte[] engineGenerateSecret()
    +        throws IllegalStateException
    +    {
    +        if (kdf != null)
    +        {
    +            throw new UnsupportedOperationException(
    +                "KDF can only be used when algorithm is known");
    +        }
    +
    +        return bigIntToBytes(result);
    +    }
    +
    +    protected int engineGenerateSecret(
    +        byte[]  sharedSecret,
    +        int     offset)
    +        throws IllegalStateException, ShortBufferException
    +    {
    +        byte[] secret = engineGenerateSecret();
    +
    +        if (sharedSecret.length - offset < secret.length)
    +        {
    +            throw new ShortBufferException(kaAlgorithm + " key agreement: need " + secret.length + " bytes");
    +        }
    +
    +        System.arraycopy(secret, 0, sharedSecret, offset, secret.length);
    +
    +        return secret.length;
    +    }
    +
    +    protected SecretKey engineGenerateSecret(
    +        String algorithm)
    +        throws NoSuchAlgorithmException
    +    {
    +        byte[] secret = bigIntToBytes(result);
    +        String algKey = Strings.toUpperCase(algorithm);
    +        String oidAlgorithm = algorithm;
    +
    +        if (oids.containsKey(algKey))
    +        {
    +            oidAlgorithm = ((ASN1ObjectIdentifier)oids.get(algKey)).getId();
    +        }
    +
    +        int    keySize = getKeySize(oidAlgorithm);
    +        if (kdf != null)
    +        {
    +            if (keySize < 0)
    +            {
    +                throw new NoSuchAlgorithmException("unknown algorithm encountered: " + oidAlgorithm);
    +            }
    +            byte[] keyBytes = new byte[keySize / 8];
    +
    +            // BEGIN android-removed
    +            // if (kdf instanceof DHKEKGenerator)
    +            // {
    +            //     ASN1ObjectIdentifier oid;
    +            //     try
    +            //     {
    +            //         oid = new ASN1ObjectIdentifier(oidAlgorithm);
    +            //     }
    +            //     catch (IllegalArgumentException e)
    +            //     {
    +            //         throw new NoSuchAlgorithmException("no OID for algorithm: " + oidAlgorithm);
    +            //     }
    +            //     DHKDFParameters params = new DHKDFParameters(oid, keySize, secret, ukmParameters);
    +
    +            //     kdf.init(params);
    +            // }
    +            // else
    +            // END android-removed
    +            {
    +                KDFParameters params = new KDFParameters(secret, ukmParameters);
    +
    +                kdf.init(params);
    +            }
    +
    +            kdf.generateBytes(keyBytes, 0, keyBytes.length);
    +
    +            secret = keyBytes;
    +        }
    +        else
    +        {
    +            if (keySize > 0)
    +            {
    +                byte[] keyBytes = new byte[keySize / 8];
    +
    +                System.arraycopy(secret, 0, keyBytes, 0, keyBytes.length);
    +
    +                secret = keyBytes;
    +            }
    +        }
    +
    +        if (des.containsKey(oidAlgorithm))
    +        {
    +            DESParameters.setOddParity(secret);
    +        }
    +
    +        return new SecretKeySpec(secret, getAlgorithm(algorithm));
    +    }
    +
    +    protected abstract byte[] bigIntToBytes(BigInteger result);
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAlgorithmParameterGeneratorSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAlgorithmParameterGeneratorSpi.java
    new file mode 100644
    index 0000000..d9fb3fb
    --- /dev/null
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAlgorithmParameterGeneratorSpi.java
    @@ -0,0 +1,25 @@
    +package org.bouncycastle.jcajce.provider.asymmetric.util;
    +
    +import java.security.AlgorithmParameterGeneratorSpi;
    +import java.security.AlgorithmParameters;
    +import java.security.NoSuchAlgorithmException;
    +import java.security.NoSuchProviderException;
    +
    +import org.bouncycastle.jcajce.util.BCJcaJceHelper;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
    +
    +public abstract class BaseAlgorithmParameterGeneratorSpi
    +    extends AlgorithmParameterGeneratorSpi
    +{
    +    private final JcaJceHelper helper = new BCJcaJceHelper();
    +
    +    public BaseAlgorithmParameterGeneratorSpi()
    +    {
    +    }
    +
    +    protected final AlgorithmParameters createParametersInstance(String algorithm)
    +        throws NoSuchAlgorithmException, NoSuchProviderException
    +    {
    +        return helper.createAlgorithmParameters(algorithm);
    +    }
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
    index fabad43..5842b9e 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
    @@ -27,6 +27,8 @@ import javax.crypto.spec.SecretKeySpec;
     import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
     import org.bouncycastle.crypto.InvalidCipherTextException;
     import org.bouncycastle.crypto.Wrapper;
    +import org.bouncycastle.jcajce.util.BCJcaJceHelper;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
     import org.bouncycastle.jce.provider.BouncyCastleProvider;
     
     public abstract class BaseCipherSpi
    @@ -45,6 +47,7 @@ public abstract class BaseCipherSpi
                                             // END android-removed
                                         };
     
    +    private final JcaJceHelper helper = new BCJcaJceHelper();
     
         protected AlgorithmParameters     engineParams = null;
     
    @@ -84,6 +87,12 @@ public abstract class BaseCipherSpi
             return null;
         }
     
    +    protected final AlgorithmParameters createParametersInstance(String algorithm)
    +        throws NoSuchAlgorithmException, NoSuchProviderException
    +    {
    +        return helper.createAlgorithmParameters(algorithm);
    +    }
    +
         protected void engineSetMode(
             String  mode)
             throws NoSuchAlgorithmException
    @@ -190,7 +199,7 @@ public abstract class BaseCipherSpi
             {
                 try
                 {
    -                KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
    +                KeyFactory kf = helper.createKeyFactory(wrappedKeyAlgorithm);
     
                     if (wrappedKeyType == Cipher.PUBLIC_KEY)
                     {
    @@ -201,17 +210,17 @@ public abstract class BaseCipherSpi
                         return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded));
                     }
                 }
    -            catch (NoSuchProviderException e)
    +            catch (NoSuchAlgorithmException e)
                 {
                     throw new InvalidKeyException("Unknown key type " + e.getMessage());
                 }
    -            catch (NoSuchAlgorithmException e)
    +            catch (InvalidKeySpecException e)
                 {
                     throw new InvalidKeyException("Unknown key type " + e.getMessage());
                 }
    -            catch (InvalidKeySpecException e2)
    +            catch (NoSuchProviderException e)
                 {
    -                throw new InvalidKeyException("Unknown key type " + e2.getMessage());
    +                throw new InvalidKeyException("Unknown key type " + e.getMessage());
                 }
     
                 throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
    index 490bf4e..cb34f44 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
    @@ -1,6 +1,5 @@
     package org.bouncycastle.jcajce.provider.asymmetric.util;
     
    -import java.io.IOException;
     import java.security.Key;
     import java.security.PrivateKey;
     import java.security.PublicKey;
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
    index 5eea1b9..0f25888 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java
    @@ -7,41 +7,149 @@ import java.security.spec.ECFieldFp;
     import java.security.spec.ECParameterSpec;
     import java.security.spec.ECPoint;
     import java.security.spec.EllipticCurve;
    +import java.util.Enumeration;
    +import java.util.HashMap;
    +import java.util.Map;
     
    +import org.bouncycastle.asn1.ASN1ObjectIdentifier;
    +import org.bouncycastle.asn1.x9.ECNamedCurveTable;
    +import org.bouncycastle.asn1.x9.X962Parameters;
    +import org.bouncycastle.asn1.x9.X9ECParameters;
    +import org.bouncycastle.crypto.ec.CustomNamedCurves;
    +import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
     import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
     import org.bouncycastle.jce.spec.ECNamedCurveSpec;
    +import org.bouncycastle.math.ec.ECAlgorithms;
     import org.bouncycastle.math.ec.ECCurve;
    +import org.bouncycastle.math.field.FiniteField;
    +import org.bouncycastle.math.field.Polynomial;
    +import org.bouncycastle.math.field.PolynomialExtensionField;
    +import org.bouncycastle.util.Arrays;
     
     public class EC5Util
     {
    -    public static EllipticCurve convertCurve(
    -        ECCurve curve, 
    -        byte[]  seed)
    +    private static Map customCurves = new HashMap();
    +
    +    static
         {
    -        // TODO: the Sun EC implementation doesn't currently handle the seed properly
    -        // so at the moment it's set to null. Should probably look at making this configurable
    -        if (curve instanceof ECCurve.Fp)
    +        Enumeration e = CustomNamedCurves.getNames();
    +        while (e.hasMoreElements())
    +        {
    +            String name = (String)e.nextElement();
    +
    +            X9ECParameters curveParams = ECNamedCurveTable.getByName(name);
    +            if (curveParams != null)  // there may not be a regular curve, may just be a custom curve.
    +            {
    +                customCurves.put(curveParams.getCurve(), CustomNamedCurves.getByName(name).getCurve());
    +            }
    +        }
    +    }
    +
    +    public static ECCurve getCurve(
    +        ProviderConfiguration configuration,
    +        X962Parameters params)
    +    {
    +        ECCurve curve;
    +
    +        if (params.isNamedCurve())
    +        {
    +            ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
    +            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
    +
    +            curve = ecP.getCurve();
    +        }
    +        else if (params.isImplicitlyCA())
    +        {
    +            curve = configuration.getEcImplicitlyCa().getCurve();
    +        }
    +        else
    +        {
    +            X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
    +
    +            curve = ecP.getCurve();
    +        }
    +
    +        return curve;
    +    }
    +
    +    public static ECParameterSpec convertToSpec(
    +        X962Parameters params, ECCurve curve)
    +    {
    +        ECParameterSpec ecSpec;
    +        EllipticCurve ellipticCurve;
    +
    +        if (params.isNamedCurve())
    +        {
    +            ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
    +            X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
    +
    +            ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
    +
    +            ecSpec = new ECNamedCurveSpec(
    +                ECUtil.getCurveName(oid),
    +                ellipticCurve,
    +                new ECPoint(
    +                    ecP.getG().getAffineXCoord().toBigInteger(),
    +                    ecP.getG().getAffineYCoord().toBigInteger()),
    +                ecP.getN(),
    +                ecP.getH());
    +        }
    +        else if (params.isImplicitlyCA())
             {
    -            return new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
    +            ecSpec = null;
             }
             else
             {
    -            ECCurve.F2m curveF2m = (ECCurve.F2m)curve;
    -            int ks[];
    -            
    -            if (curveF2m.isTrinomial())
    +            X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters());
    +
    +            ellipticCurve = EC5Util.convertCurve(curve, ecP.getSeed());
    +
    +            if (ecP.getH() != null)
                 {
    -                ks = new int[] { curveF2m.getK1() };
    -                
    -                return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
    +                ecSpec = new ECParameterSpec(
    +                    ellipticCurve,
    +                    new ECPoint(
    +                        ecP.getG().getAffineXCoord().toBigInteger(),
    +                        ecP.getG().getAffineYCoord().toBigInteger()),
    +                    ecP.getN(),
    +                    ecP.getH().intValue());
                 }
                 else
                 {
    -                ks = new int[] { curveF2m.getK3(), curveF2m.getK2(), curveF2m.getK1() };
    -                
    -                return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
    -            } 
    +                ecSpec = new ECParameterSpec(
    +                    ellipticCurve,
    +                    new ECPoint(
    +                        ecP.getG().getAffineXCoord().toBigInteger(),
    +                        ecP.getG().getAffineYCoord().toBigInteger()),
    +                    ecP.getN(), 1);      // TODO: not strictly correct... need to fix the test data...
    +            }
             }
    +
    +        return ecSpec;
    +    }
    +
    +    public static ECParameterSpec convertToSpec(
    +        X9ECParameters domainParameters)
    +    {
    +        return new ECParameterSpec(
    +            convertCurve(domainParameters.getCurve(), null),  // JDK 1.5 has trouble with this if it's not null...
    +            new ECPoint(
    +                domainParameters.getG().getAffineXCoord().toBigInteger(),
    +                domainParameters.getG().getAffineYCoord().toBigInteger()),
    +            domainParameters.getN(),
    +            domainParameters.getH().intValue());
    +    }
    +
    +    public static EllipticCurve convertCurve(
    +        ECCurve curve, 
    +        byte[]  seed)
    +    {
    +        ECField field = convertField(curve.getField());
    +        BigInteger a = curve.getA().toBigInteger(), b = curve.getB().toBigInteger();
    +
    +        // TODO: the Sun EC implementation doesn't currently handle the seed properly
    +        // so at the moment it's set to null. Should probably look at making this configurable
    +        return new EllipticCurve(field, a, b, null);
         }
     
         public static ECCurve convertCurve(
    @@ -53,7 +161,14 @@ public class EC5Util
     
             if (field instanceof ECFieldFp)
             {
    -            return new ECCurve.Fp(((ECFieldFp)field).getP(), a, b);
    +            ECCurve.Fp curve = new ECCurve.Fp(((ECFieldFp)field).getP(), a, b);
    +
    +            if (customCurves.containsKey(curve))
    +            {
    +                return (ECCurve)customCurves.get(curve);
    +            }
    +
    +            return curve;
             }
             else
             {
    @@ -64,6 +179,21 @@ public class EC5Util
             }
         }
     
    +    public static ECField convertField(FiniteField field)
    +    {
    +        if (ECAlgorithms.isFpField(field))
    +        {
    +            return new ECFieldFp(field.getCharacteristic());
    +        }
    +        else //if (ECAlgorithms.isF2mField(curveField))
    +        {
    +            Polynomial poly = ((PolynomialExtensionField)field).getMinimalPolynomial();
    +            int[] exponents = poly.getExponentsPresent();
    +            int[] ks = Arrays.reverse(Arrays.copyOfRange(exponents, 1, exponents.length - 1));
    +            return new ECFieldF2m(poly.getDegree(), ks);
    +        }
    +    }
    +
         public static ECParameterSpec convertSpec(
             EllipticCurve ellipticCurve,
             org.bouncycastle.jce.spec.ECParameterSpec spec)
    @@ -118,6 +248,6 @@ public class EC5Util
             ECPoint point,
             boolean withCompression)
         {
    -        return curve.createPoint(point.getAffineX(), point.getAffineY(), withCompression);
    +        return curve.createPoint(point.getAffineX(), point.getAffineY());
         }
     }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
    index 442b340..561259a 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java
    @@ -1,11 +1,14 @@
     package org.bouncycastle.jcajce.provider.asymmetric.util;
     
    +import java.math.BigInteger;
     import java.security.InvalidKeyException;
     import java.security.PrivateKey;
     import java.security.PublicKey;
    +import java.util.Enumeration;
     
     import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     // BEGIN android-removed
    +// import org.bouncycastle.asn1.anssi.ANSSINamedCurves;
     // import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
     // END android-removed
     import org.bouncycastle.asn1.nist.NISTNamedCurves;
    @@ -15,8 +18,10 @@ import org.bouncycastle.asn1.sec.SECNamedCurves;
     // import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
     // END android-removed
     import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
    +import org.bouncycastle.asn1.x9.ECNamedCurveTable;
     import org.bouncycastle.asn1.x9.X962NamedCurves;
     import org.bouncycastle.asn1.x9.X9ECParameters;
    +import org.bouncycastle.crypto.ec.CustomNamedCurves;
     import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
     import org.bouncycastle.crypto.params.ECDomainParameters;
     import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
    @@ -217,11 +222,60 @@ public class ECUtil
             throw new InvalidKeyException("can't identify EC private key.");
         }
     
    +    public static int getOrderBitLength(BigInteger order, BigInteger privateValue)
    +    {
    +        if (order == null)     // implicitly CA
    +        {
    +            ECParameterSpec implicitCA = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
    +
    +            if (implicitCA == null)
    +            {
    +                return privateValue.bitLength();   // a guess but better than an exception!
    +            }
    +
    +            return implicitCA.getN().bitLength();
    +        }
    +        else
    +        {
    +            return order.bitLength();
    +        }
    +    }
    +
         public static ASN1ObjectIdentifier getNamedCurveOid(
    -        String name)
    +        String curveName)
    +    {
    +        String name;
    +
    +        if (curveName.indexOf(' ') > 0)
    +        {
    +            name = curveName.substring(curveName.indexOf(' ') + 1);
    +        }
    +        else
    +        {
    +            name = curveName;
    +        }
    +
    +        try
    +        {
    +            if (name.charAt(0) >= '0' && name.charAt(0) <= '2')
    +            {
    +                return new ASN1ObjectIdentifier(name);
    +            }
    +            else
    +            {
    +                return lookupOidByName(name);
    +            }
    +        }
    +        catch (IllegalArgumentException ex)
    +        {
    +            return lookupOidByName(name);
    +        }
    +    }
    +
    +    private static ASN1ObjectIdentifier lookupOidByName(String name)
         {
             ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name);
    -        
    +
             if (oid == null)
             {
                 oid = SECNamedCurves.getOID(name);
    @@ -238,20 +292,49 @@ public class ECUtil
                 // {
                 //     oid = ECGOST3410NamedCurves.getOID(name);
                 // }
    +            // if (oid == null)
    +            // {
    +            //     oid = ANSSINamedCurves.getOID(name);
    +            // }
                 // END android-removed
             }
     
             return oid;
         }
    -    
    +
    +    public static ASN1ObjectIdentifier getNamedCurveOid(
    +        ECParameterSpec ecParameterSpec)
    +    {
    +        for (Enumeration names = ECNamedCurveTable.getNames(); names.hasMoreElements();)
    +        {
    +            String name = (String)names.nextElement();
    +
    +            X9ECParameters params = ECNamedCurveTable.getByName(name);
    +
    +            if (params.getN().equals(ecParameterSpec.getN())
    +                && params.getH().equals(ecParameterSpec.getH())
    +                && params.getCurve().equals(ecParameterSpec.getCurve())
    +                && params.getG().equals(ecParameterSpec.getG()))
    +            {
    +                return org.bouncycastle.asn1.x9.ECNamedCurveTable.getOID(name);
    +            }
    +        }
    +
    +        return null;
    +    }
    +
         public static X9ECParameters getNamedCurveByOid(
             ASN1ObjectIdentifier oid)
         {
    -        X9ECParameters params = X962NamedCurves.getByOID(oid);
    -        
    +        X9ECParameters params = CustomNamedCurves.getByOID(oid);
    +
             if (params == null)
             {
    -            params = SECNamedCurves.getByOID(oid);
    +            params = X962NamedCurves.getByOID(oid);
    +            if (params == null)
    +            {
    +                params = SECNamedCurves.getByOID(oid);
    +            }
                 if (params == null)
                 {
                     params = NISTNamedCurves.getByOID(oid);
    @@ -267,6 +350,33 @@ public class ECUtil
             return params;
         }
     
    +    public static X9ECParameters getNamedCurveByName(
    +        String curveName)
    +    {
    +        X9ECParameters params = CustomNamedCurves.getByName(curveName);
    +
    +        if (params == null)
    +        {
    +            params = X962NamedCurves.getByName(curveName);
    +            if (params == null)
    +            {
    +                params = SECNamedCurves.getByName(curveName);
    +            }
    +            if (params == null)
    +            {
    +                params = NISTNamedCurves.getByName(curveName);
    +            }
    +            // BEGIN android-removed
    +            // if (params == null)
    +            // {
    +            //     params = TeleTrusTNamedCurves.getByName(curveName);
    +            // }
    +            // END android-removed
    +        }
    +
    +        return params;
    +    }
    +
         public static String getCurveName(
             ASN1ObjectIdentifier oid)
         {
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
    index 532554d..3e328da 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
    @@ -12,7 +12,6 @@ import org.bouncycastle.asn1.ASN1Encodable;
     import org.bouncycastle.asn1.ASN1InputStream;
     import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     import org.bouncycastle.asn1.ASN1OutputStream;
    -import org.bouncycastle.asn1.DERObjectIdentifier;
     import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
     
     public class PKCS12BagAttributeCarrierImpl
    @@ -90,7 +89,7 @@ public class PKCS12BagAttributeCarrierImpl
     
                 while (e.hasMoreElements())
                 {
    -                DERObjectIdentifier    oid = (DERObjectIdentifier)e.nextElement();
    +                ASN1ObjectIdentifier    oid = (ASN1ObjectIdentifier)e.nextElement();
     
                     aOut.writeObject(oid);
                     aOut.writeObject((ASN1Encodable)pkcs12Attributes.get(oid));
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
    index 03a1fe8..2203ce7 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
    @@ -24,6 +24,8 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
     import org.bouncycastle.asn1.pkcs.SignedData;
     import org.bouncycastle.asn1.x509.Certificate;
     import org.bouncycastle.asn1.x509.CertificateList;
    +import org.bouncycastle.jcajce.util.BCJcaJceHelper;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
     
     /**
      * class for dealing with X509 certificates.
    @@ -35,6 +37,8 @@ import org.bouncycastle.asn1.x509.CertificateList;
     public class CertificateFactory
         extends CertificateFactorySpi
     {
    +    private final JcaJceHelper bcHelper = new BCJcaJceHelper();
    +
         private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE");
         private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
     
    @@ -64,7 +68,7 @@ public class CertificateFactory
                 }
             }
     
    -        return new X509CertificateObject(
    +        return new X509CertificateObject(bcHelper,
                                 Certificate.getInstance(seq));
         }
     
    @@ -79,7 +83,7 @@ public class CertificateFactory
     
                     if (obj instanceof ASN1Sequence)
                     {
    -                   return new X509CertificateObject(
    +                   return new X509CertificateObject(bcHelper,
                                         Certificate.getInstance(obj));
                     }
                 }
    @@ -96,7 +100,7 @@ public class CertificateFactory
     
             if (seq != null)
             {
    -            return new X509CertificateObject(
    +            return new X509CertificateObject(bcHelper,
                                 Certificate.getInstance(seq));
             }
     
    @@ -106,7 +110,7 @@ public class CertificateFactory
         protected CRL createCRL(CertificateList c)
         throws CRLException
         {
    -        return new X509CRLObject(c);
    +        return new X509CRLObject(bcHelper, c);
         }
         
         private CRL readPEMCRL(
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
    index 8699c3c..8116f29 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
    @@ -6,7 +6,7 @@ import java.io.InputStream;
     import org.bouncycastle.asn1.ASN1Sequence;
     import org.bouncycastle.util.encoders.Base64;
     
    -public class PEMUtil
    +class PEMUtil
     {
         private final String _header1;
         private final String _header2;
    @@ -33,11 +33,6 @@ public class PEMUtil
             {
                 while (((c = in.read()) != '\r') && c != '\n' && (c >= 0))
                 {
    -                if (c == '\r')
    -                {
    -                    continue;
    -                }
    -
                     l.append((char)c);
                 }
             }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
    index 9b14731..8bb4c3a 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
    @@ -34,7 +34,8 @@ import org.bouncycastle.asn1.DERSet;
     import org.bouncycastle.asn1.pkcs.ContentInfo;
     import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
     import org.bouncycastle.asn1.pkcs.SignedData;
    -import org.bouncycastle.jce.provider.BouncyCastleProvider;
    +import org.bouncycastle.jcajce.util.BCJcaJceHelper;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
     import org.bouncycastle.util.io.pem.PemObject;
     // BEGIN android-removed
     // import org.bouncycastle.util.io.pem.PemWriter;
    @@ -47,6 +48,8 @@ import org.bouncycastle.util.io.pem.PemObject;
     public  class PKIXCertPath
         extends CertPath
     {
    +    private final JcaJceHelper helper = new BCJcaJceHelper();
    +
         static final List certPathEncodings;
     
         static
    @@ -184,7 +187,7 @@ public  class PKIXCertPath
                     }
                     Enumeration e = ((ASN1Sequence)derObject).getObjects();
                     certificates = new ArrayList();
    -                CertificateFactory certFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
    +                CertificateFactory certFactory = helper.createCertificateFactory("X.509");
                     while (e.hasMoreElements())
                     {
                         ASN1Encodable element = (ASN1Encodable)e.nextElement();
    @@ -197,7 +200,7 @@ public  class PKIXCertPath
                 {
                     inStream = new BufferedInputStream(inStream);
                     certificates = new ArrayList();
    -                CertificateFactory certFactory= CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
    +                CertificateFactory certFactory= helper.createCertificateFactory("X.509");
                     Certificate cert;
                     while ((cert = certFactory.generateCertificate(inStream)) != null)
                     {
    @@ -217,7 +220,7 @@ public  class PKIXCertPath
             {
                 throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString());
             }
    -        
    +
             this.certificates = sortCerts(certificates);
         }
         
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
    index 32e595c..5a94c63 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java
    @@ -23,7 +23,7 @@ import org.bouncycastle.asn1.x509.Extensions;
     import org.bouncycastle.asn1.x509.GeneralName;
     import org.bouncycastle.asn1.x509.GeneralNames;
     import org.bouncycastle.asn1.x509.TBSCertList;
    -import org.bouncycastle.asn1.x509.X509Extension;
    +import org.bouncycastle.util.Strings;
     
     /**
      * The following extensions are listed in RFC 2459 as relevant to CRL Entries
    @@ -31,7 +31,7 @@ import org.bouncycastle.asn1.x509.X509Extension;
      * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
      * (critical)
      */
    -public class X509CRLEntryObject extends X509CRLEntry
    +class X509CRLEntryObject extends X509CRLEntry
     {
         private TBSCertList.CRLEntry c;
     
    @@ -189,7 +189,7 @@ public class X509CRLEntryObject extends X509CRLEntry
                 }
                 catch (Exception e)
                 {
    -                throw new RuntimeException("error encoding " + e.toString());
    +                throw new IllegalStateException("Exception encoding: " + e.toString());
                 }
             }
     
    @@ -259,7 +259,7 @@ public class X509CRLEntryObject extends X509CRLEntry
         public String toString()
         {
             StringBuffer buf = new StringBuffer();
    -        String nl = System.getProperty("line.separator");
    +        String nl = Strings.lineSeparator();
     
             buf.append("      userCertificate: ").append(this.getSerialNumber()).append(nl);
             buf.append("       revocationDate: ").append(this.getRevocationDate()).append(nl);
    @@ -285,11 +285,11 @@ public class X509CRLEntryObject extends X509CRLEntry
                             buf.append("                       critical(").append(ext.isCritical()).append(") ");
                             try
                             {
    -                            if (oid.equals(X509Extension.reasonCode))
    +                            if (oid.equals(Extension.reasonCode))
                                 {
                                     buf.append(CRLReason.getInstance(ASN1Enumerated.getInstance(dIn.readObject()))).append(nl);
                                 }
    -                            else if (oid.equals(X509Extension.certificateIssuer))
    +                            else if (oid.equals(Extension.certificateIssuer))
                                 {
                                     buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
                                 }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
    index c7d0402..dc8930b 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java
    @@ -6,6 +6,7 @@ import java.security.InvalidKeyException;
     import java.security.NoSuchAlgorithmException;
     import java.security.NoSuchProviderException;
     import java.security.Principal;
    +import java.security.Provider;
     import java.security.PublicKey;
     import java.security.Signature;
     import java.security.SignatureException;
    @@ -40,9 +41,9 @@ import org.bouncycastle.asn1.x509.Extensions;
     import org.bouncycastle.asn1.x509.GeneralNames;
     import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
     import org.bouncycastle.asn1.x509.TBSCertList;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
     import org.bouncycastle.jce.X509Principal;
    -import org.bouncycastle.jce.provider.BouncyCastleProvider;
    -import org.bouncycastle.jce.provider.RFC3280CertPathUtilities;
    +import org.bouncycastle.util.Strings;
     import org.bouncycastle.util.encoders.Hex;
     
     /**
    @@ -54,9 +55,10 @@ import org.bouncycastle.util.encoders.Hex;
      * Delta CRL Indicator (critical)
      * Issuing Distribution Point (critical)
      */
    -public class X509CRLObject
    +class X509CRLObject
         extends X509CRL
     {
    +    private JcaJceHelper bcHelper;
         private CertificateList c;
         private String sigAlgName;
         private byte[] sigAlgParams;
    @@ -81,9 +83,11 @@ public class X509CRLObject
         }
     
         protected X509CRLObject(
    +        JcaJceHelper bcHelper,
             CertificateList c)
             throws CRLException
         {
    +        this.bcHelper = bcHelper;
             this.c = c;
             
             try
    @@ -120,8 +124,8 @@ public class X509CRLObject
                 return false;
             }
     
    -        extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
    -        extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
    +        extns.remove(Extension.issuingDistributionPoint.getId());
    +        extns.remove(Extension.deltaCRLIndicator.getId());
     
             return !extns.isEmpty();
         }
    @@ -203,21 +207,45 @@ public class X509CRLObject
         }
     
         public void verify(PublicKey key)
    -        throws CRLException,  NoSuchAlgorithmException,
    -            InvalidKeyException, NoSuchProviderException, SignatureException
    +        throws CRLException, NoSuchAlgorithmException,
    +        InvalidKeyException, NoSuchProviderException, SignatureException
         {
    -        verify(key, BouncyCastleProvider.PROVIDER_NAME);
    +        Signature sig;
    +
    +        try
    +        {
    +            sig = bcHelper.createSignature(getSigAlgName());
    +        }
    +        catch (Exception e)
    +        {
    +            sig = Signature.getInstance(getSigAlgName());
    +        }
    +
    +        doVerify(key, sig);
         }
     
         public void verify(PublicKey key, String sigProvider)
             throws CRLException, NoSuchAlgorithmException,
    -            InvalidKeyException, NoSuchProviderException, SignatureException
    +        InvalidKeyException, NoSuchProviderException, SignatureException
         {
    -        if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
    +        Signature sig;
    +
    +        if (sigProvider != null)
             {
    -            throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
    +            sig = Signature.getInstance(getSigAlgName(), sigProvider);
    +        }
    +        else
    +        {
    +            sig = Signature.getInstance(getSigAlgName());
             }
     
    +        doVerify(key, sig);
    +    }
    +
    +    public void verify(PublicKey key, Provider sigProvider)
    +        throws CRLException, NoSuchAlgorithmException,
    +        InvalidKeyException, SignatureException
    +    {
             Signature sig;
     
             if (sigProvider != null)
    @@ -229,6 +257,18 @@ public class X509CRLObject
                 sig = Signature.getInstance(getSigAlgName());
             }
     
    +        doVerify(key, sig);
    +    }
    +
    +    private void doVerify(PublicKey key, Signature sig)
    +        throws CRLException, NoSuchAlgorithmException,
    +        InvalidKeyException, SignatureException
    +    {
    +        if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
    +        {
    +            throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
    +        }
    +
             sig.initVerify(key);
             sig.update(this.getTBSCertList());
     
    @@ -355,7 +395,7 @@ public class X509CRLObject
     
         public byte[] getSignature()
         {
    -        return c.getSignature().getBytes();
    +        return c.getSignature().getOctets();
         }
     
         public String getSigAlgName()
    @@ -390,7 +430,7 @@ public class X509CRLObject
         public String toString()
         {
             StringBuffer buf = new StringBuffer();
    -        String nl = System.getProperty("line.separator");
    +        String nl = Strings.lineSeparator();
     
             buf.append("              Version: ").append(this.getVersion()).append(
                 nl);
    @@ -521,7 +561,7 @@ public class X509CRLObject
         {
             if (!cert.getType().equals("X.509"))
             {
    -            throw new RuntimeException("X.509 CRL used with non X.509 Cert");
    +            throw new IllegalArgumentException("X.509 CRL used with non X.509 Cert");
             }
     
             Enumeration certs = c.getRevokedCertificateEnumeration();
    @@ -562,7 +602,7 @@ public class X509CRLObject
                             }
                             catch (CertificateEncodingException e)
                             {
    -                            throw new RuntimeException("Cannot process certificate");
    +                            throw new IllegalArgumentException("Cannot process certificate: " + e.getMessage());
                             }
                         }
     
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
    index 6604b4a..51213d4 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java
    @@ -11,10 +11,8 @@ import java.security.NoSuchProviderException;
     import java.security.Principal;
     import java.security.Provider;
     import java.security.PublicKey;
    -import java.security.Security;
     import java.security.Signature;
     import java.security.SignatureException;
    -import java.security.cert.Certificate;
     import java.security.cert.CertificateEncodingException;
     import java.security.cert.CertificateException;
     import java.security.cert.CertificateExpiredException;
    @@ -32,6 +30,7 @@ import java.util.Set;
     
     import javax.security.auth.x500.X500Principal;
     
    +import org.bouncycastle.asn1.ASN1BitString;
     import org.bouncycastle.asn1.ASN1Encodable;
     import org.bouncycastle.asn1.ASN1Encoding;
     import org.bouncycastle.asn1.ASN1InputStream;
    @@ -61,18 +60,19 @@ import org.bouncycastle.asn1.x509.KeyUsage;
     import org.bouncycastle.asn1.x509.X509Name;
     // END android-added
     import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
     import org.bouncycastle.jce.X509Principal;
     import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
     import org.bouncycastle.jce.provider.BouncyCastleProvider;
    -import org.bouncycastle.jce.provider.RFC3280CertPathUtilities;
    -import org.bouncycastle.util.Arrays;
     import org.bouncycastle.util.Integers;
    +import org.bouncycastle.util.Strings;
     import org.bouncycastle.util.encoders.Hex;
     
     class X509CertificateObject
         extends X509Certificate
         implements PKCS12BagAttributeCarrier
     {
    +    private JcaJceHelper bcHelper;
         private org.bouncycastle.asn1.x509.Certificate    c;
         private BasicConstraints            basicConstraints;
         private boolean[]                   keyUsage;
    @@ -82,9 +82,11 @@ class X509CertificateObject
         private PKCS12BagAttributeCarrier   attrCarrier = new PKCS12BagAttributeCarrierImpl();
     
         public X509CertificateObject(
    +        JcaJceHelper bcHelper,
             org.bouncycastle.asn1.x509.Certificate    c)
             throws CertificateParsingException
         {
    +        this.bcHelper = bcHelper;
             this.c = c;
     
             try
    @@ -106,7 +108,7 @@ class X509CertificateObject
                 byte[] bytes = this.getExtensionBytes("2.5.29.15");
                 if (bytes != null)
                 {
    -                DERBitString    bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
    +                ASN1BitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
     
                     bytes = bits.getBytes();
                     int length = (bytes.length * 8) - bits.getPadBits();
    @@ -236,42 +238,16 @@ class X509CertificateObject
     
         public byte[] getSignature()
         {
    -        return c.getSignature().getBytes();
    +        return c.getSignature().getOctets();
         }
     
         /**
          * return a more "meaningful" representation for the signature algorithm used in
    -     * the certficate.
    +     * the certificate.
          */
         public String getSigAlgName()
         {
    -        Provider    prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
    -
    -        if (prov != null)
    -        {
    -            String      algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
    -
    -            if (algName != null)
    -            {
    -                return algName;
    -            }
    -        }
    -
    -        Provider[] provs = Security.getProviders();
    -
    -        //
    -        // search every provider looking for a real algorithm
    -        //
    -        for (int i = 0; i != provs.length; i++)
    -        {
    -            String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
    -            if (algName != null)
    -            {
    -                return algName;
    -            }
    -        }
    -
    -        return this.getSigAlgOID();
    +        return X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
         }
     
         /**
    @@ -525,19 +501,18 @@ class X509CertificateObject
                     while (e.hasMoreElements())
                     {
                         ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
    -                    String              oidId = oid.getId();
    -
    -                    if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE)
    -                     || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES)
    -                     || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS)
    -                     || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)
    -                     || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS)
    -                     || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT)
    -                     || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR)
    -                     || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS)
    -                     || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS)
    -                     || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME)
    -                     || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS))
    +
    +                    if (oid.equals(Extension.keyUsage)
    +                     || oid.equals(Extension.certificatePolicies)
    +                     || oid.equals(Extension.policyMappings)
    +                     || oid.equals(Extension.inhibitAnyPolicy)
    +                     || oid.equals(Extension.cRLDistributionPoints)
    +                     || oid.equals(Extension.issuingDistributionPoint)
    +                     || oid.equals(Extension.deltaCRLIndicator)
    +                     || oid.equals(Extension.policyConstraints)
    +                     || oid.equals(Extension.basicConstraints)
    +                     || oid.equals(Extension.subjectAlternativeName)
    +                     || oid.equals(Extension.nameConstraints))
                         {
                             continue;
                         }
    @@ -596,38 +571,41 @@ class X509CertificateObject
                 return true;
             }
     
    -        if (!(o instanceof Certificate))
    +        if (o instanceof X509CertificateObject)
             {
    -            return false;
    -        }
    -
    -        Certificate other = (Certificate)o;
    +            X509CertificateObject other = (X509CertificateObject)o;
     
    -        try
    -        {
    -            byte[] b1 = this.getEncoded();
    -            byte[] b2 = other.getEncoded();
    +            if (this.hashValueSet && other.hashValueSet)
    +            {
    +                if (this.hashValue != other.hashValue)
    +                {
    +                    return false;
    +                }
    +            }
     
    -            return Arrays.areEqual(b1, b2);
    -        }
    -        catch (CertificateEncodingException e)
    -        {
    -            return false;
    +            return this.c.equals(other.c);
             }
    +
    +        return super.equals(o);
         }
    -    
    +
         public synchronized int hashCode()
         {
             if (!hashValueSet)
             {
    -            hashValue = calculateHashCode();
    +            hashValue = super.hashCode();
                 hashValueSet = true;
             }
     
             return hashValue;
         }
    -    
    -    private int calculateHashCode()
    +
    +    /**
    +     * Returns the original hash code for Certificates pre-JDK 1.8.
    +     *
    +     * @return the pre-JDK 1.8 hashcode calculation.
    +     */
    +    public int originalHashCode()
         {
             try
             {
    @@ -666,7 +644,7 @@ class X509CertificateObject
         public String toString()
         {
             StringBuffer    buf = new StringBuffer();
    -        String          nl = System.getProperty("line.separator");
    +        String          nl = Strings.lineSeparator();
     
             buf.append("  [0]         Version: ").append(this.getVersion()).append(nl);
             buf.append("         SerialNumber: ").append(this.getSerialNumber()).append(nl);
    @@ -769,7 +747,7 @@ class X509CertificateObject
             
             try
             {
    -            signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
    +            signature = bcHelper.createSignature(sigName);
             }
             catch (Exception e)
             {
    @@ -786,11 +764,41 @@ class X509CertificateObject
             InvalidKeyException, NoSuchProviderException, SignatureException
         {
             String    sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
    -        Signature signature = Signature.getInstance(sigName, sigProvider);
    +        Signature signature;
    +
    +        if (sigProvider != null)
    +        {
    +            signature = Signature.getInstance(sigName, sigProvider);
    +        }
    +        else
    +        {
    +            signature = Signature.getInstance(sigName);
    +        }
             
             checkSignature(key, signature);
         }
     
    +    public final void verify(
    +        PublicKey   key,
    +        Provider sigProvider)
    +        throws CertificateException, NoSuchAlgorithmException,
    +        InvalidKeyException, SignatureException
    +    {
    +        String    sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
    +        Signature signature;
    +
    +        if (sigProvider != null)
    +        {
    +            signature = Signature.getInstance(sigName, sigProvider);
    +        }
    +        else
    +        {
    +            signature = Signature.getInstance(sigName);
    +        }
    +
    +        checkSignature(key, signature);
    +    }
    +
         private void checkSignature(
             PublicKey key, 
             Signature signature) 
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
    index 4ca9e89..61b0545 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
    @@ -5,15 +5,17 @@ import java.security.AlgorithmParameters;
     import java.security.GeneralSecurityException;
     import java.security.InvalidKeyException;
     import java.security.NoSuchAlgorithmException;
    +import java.security.Provider;
    +import java.security.Security;
     import java.security.Signature;
     import java.security.SignatureException;
     import java.security.spec.PSSParameterSpec;
     
     import org.bouncycastle.asn1.ASN1Encodable;
     import org.bouncycastle.asn1.ASN1Null;
    +import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     import org.bouncycastle.asn1.ASN1Sequence;
     import org.bouncycastle.asn1.DERNull;
    -import org.bouncycastle.asn1.DERObjectIdentifier;
     // BEGIN android-removed
     // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
     // END android-removed
    @@ -26,6 +28,7 @@ import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
     // END android-removed
     import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
    +import org.bouncycastle.jce.provider.BouncyCastleProvider;
     
     class X509SignatureUtil
     {
    @@ -80,7 +83,33 @@ class X509SignatureUtil
                 {
                     ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
                     
    -                return getDigestAlgName((DERObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
    +                return getDigestAlgName((ASN1ObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
    +            }
    +        }
    +
    +        Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
    +
    +        if (prov != null)
    +        {
    +            String      algName = prov.getProperty("Alg.Alias.Signature." + sigAlgId.getAlgorithm().getId());
    +
    +            if (algName != null)
    +            {
    +                return algName;
    +            }
    +        }
    +
    +        Provider[] provs = Security.getProviders();
    +
    +        //
    +        // search every provider looking for a real algorithm
    +        //
    +        for (int i = 0; i != provs.length; i++)
    +        {
    +            String algName = provs[i].getProperty("Alg.Alias.Signature." + sigAlgId.getAlgorithm().getId());
    +            if (algName != null)
    +            {
    +                return algName;
                 }
             }
     
    @@ -92,7 +121,7 @@ class X509SignatureUtil
          * representations rather the the algorithm identifier (if possible).
          */
         private static String getDigestAlgName(
    -        DERObjectIdentifier digestAlgOID)
    +        ASN1ObjectIdentifier digestAlgOID)
         {
             if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
             {
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
    index 05bfa1c..5fb3ffc 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
    @@ -15,7 +15,7 @@ public interface ConfigurableProvider
         static final String THREAD_LOCAL_EC_IMPLICITLY_CA = "threadLocalEcImplicitlyCa";
     
         /**
    -     * Elliptic Curve CA parameters - thread local version
    +     * Elliptic Curve CA parameters - VM wide version
          */
         static final String EC_IMPLICITLY_CA = "ecImplicitlyCa";
     
    @@ -33,6 +33,8 @@ public interface ConfigurableProvider
     
         void addAlgorithm(String key, String value);
     
    +    void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className);
    +
         boolean hasAlgorithm(String type, String name);
     
         void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter);
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/PKCS12StoreParameter.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/PKCS12StoreParameter.java
    index 36a32b1..7d0b203 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/PKCS12StoreParameter.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/PKCS12StoreParameter.java
    @@ -2,50 +2,31 @@ package org.bouncycastle.jcajce.provider.config;
     
     import java.io.OutputStream;
     import java.security.KeyStore;
    -import java.security.KeyStore.LoadStoreParameter;
     import java.security.KeyStore.ProtectionParameter;
     
    +/**
    + * @deprecated use org.bouncycastle.jcajce.PKCS12StoreParameter
    + */
     public class PKCS12StoreParameter
    -    implements LoadStoreParameter
    +    extends org.bouncycastle.jcajce.PKCS12StoreParameter
     {
    -    private final OutputStream out;
    -    private final ProtectionParameter protectionParameter;
    -    private final boolean forDEREncoding;
    -
         public PKCS12StoreParameter(OutputStream out, char[] password)
         {
    -        this(out, password, false);
    +        super(out, password, false);
         }
     
         public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter)
         {
    -        this(out, protectionParameter, false);
    +        super(out, protectionParameter, false);
         }
     
         public PKCS12StoreParameter(OutputStream out, char[] password, boolean forDEREncoding)
         {
    -        this(out, new KeyStore.PasswordProtection(password), forDEREncoding);
    +        super(out, new KeyStore.PasswordProtection(password), forDEREncoding);
         }
     
         public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter, boolean forDEREncoding)
         {
    -        this.out = out;
    -        this.protectionParameter = protectionParameter;
    -        this.forDEREncoding = forDEREncoding;
    -    }
    -
    -    public OutputStream getOutputStream()
    -    {
    -        return out;
    -    }
    -
    -    public ProtectionParameter getProtectionParameter()
    -    {
    -        return protectionParameter;
    -    }
    -
    -    public boolean isForDEREncoding()
    -    {
    -        return forDEREncoding;
    +        super(out, protectionParameter, forDEREncoding);
         }
     }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
    index c7502c7..1fdadc2 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
    @@ -195,6 +195,8 @@ public class SHA1
                 provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1", PREFIX + "$PBKDF2WithHmacSHA1UTF8");
                 provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2WithHmacSHA1AndUTF8", "PBKDF2WithHmacSHA1");
                 provider.addAlgorithm("SecretKeyFactory.PBKDF2WithHmacSHA1And8BIT", PREFIX + "$PBKDF2WithHmacSHA18BIT");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2withASCII", "PBKDF2WithHmacSHA1And8BIT");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBKDF2with8BIT", "PBKDF2WithHmacSHA1And8BIT");
             }
         }
     }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
    index ea89261..0640669 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java
    @@ -14,8 +14,10 @@ import java.security.KeyStoreSpi;
     import java.security.NoSuchAlgorithmException;
     import java.security.NoSuchProviderException;
     import java.security.PrivateKey;
    +import java.security.Provider;
     import java.security.PublicKey;
     import java.security.SecureRandom;
    +import java.security.Security;
     import java.security.UnrecoverableKeyException;
     import java.security.cert.Certificate;
     import java.security.cert.CertificateEncodingException;
    @@ -46,6 +48,8 @@ import org.bouncycastle.crypto.io.DigestOutputStream;
     import org.bouncycastle.crypto.io.MacInputStream;
     import org.bouncycastle.crypto.io.MacOutputStream;
     import org.bouncycastle.crypto.macs.HMac;
    +import org.bouncycastle.jcajce.util.BCJcaJceHelper;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
     import org.bouncycastle.jce.interfaces.BCKeyStore;
     import org.bouncycastle.jce.provider.BouncyCastleProvider;
     import org.bouncycastle.util.Arrays;
    @@ -88,6 +92,8 @@ public class BcKeyStoreSpi
     
         protected int              version;
     
    +    private final JcaJceHelper helper = new BCJcaJceHelper();
    +
         public BcKeyStoreSpi(int version)
         {
             this.version = version;
    @@ -361,7 +367,7 @@ public class BcKeyStoreSpi
     
             try
             {
    -            CertificateFactory cFact = CertificateFactory.getInstance(type, BouncyCastleProvider.PROVIDER_NAME);
    +            CertificateFactory cFact = helper.createCertificateFactory(type);
                 ByteArrayInputStream bIn = new ByteArrayInputStream(cEnc);
     
                 return cFact.generateCertificate(bIn);
    @@ -436,11 +442,11 @@ public class BcKeyStoreSpi
                 switch (keyType)
                 {
                 case KEY_PRIVATE:
    -                return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePrivate(spec);
    +                return helper.createKeyFactory(algorithm).generatePrivate(spec);
                 case KEY_PUBLIC:
    -                return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePublic(spec);
    +                return  helper.createKeyFactory(algorithm).generatePublic(spec);
                 case KEY_SECRET:
    -                return SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generateSecret(spec);
    +                return  helper.createSecretKeyFactory(algorithm).generateSecret(spec);
                 default:
                     throw new IOException("Key type " + keyType + " not recognised!");
                 }
    @@ -462,10 +468,10 @@ public class BcKeyStoreSpi
             try
             {
                 PBEKeySpec          pbeSpec = new PBEKeySpec(password);
    -            SecretKeyFactory    keyFact = SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
    +            SecretKeyFactory    keyFact = helper.createSecretKeyFactory(algorithm);
                 PBEParameterSpec    defParams = new PBEParameterSpec(salt, iterationCount);
     
    -            Cipher cipher = Cipher.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
    +            Cipher cipher = helper.createCipher(algorithm);
     
                 cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams);
     
    @@ -1041,6 +1047,18 @@ public class BcKeyStoreSpi
             }
         }
     
    +    static Provider getBouncyCastleProvider()
    +    {
    +        if (Security.getProvider("BC") != null)
    +        {
    +            return Security.getProvider("BC");
    +        }
    +        else
    +        {
    +            return new BouncyCastleProvider();
    +        }
    +    }
    +
         public static class Std
            extends BcKeyStoreSpi
         {
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
    index 24dac19..ed0fadc 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
    @@ -15,6 +15,7 @@ import java.security.KeyStore.ProtectionParameter;
     import java.security.KeyStoreException;
     import java.security.KeyStoreSpi;
     import java.security.NoSuchAlgorithmException;
    +import java.security.NoSuchProviderException;
     import java.security.Principal;
     import java.security.PrivateKey;
     import java.security.Provider;
    @@ -31,8 +32,10 @@ import java.util.Collections;
     import java.util.Date;
     import java.util.Enumeration;
     import java.util.HashMap;
    +import java.util.HashSet;
     import java.util.Hashtable;
     import java.util.Map;
    +import java.util.Set;
     import java.util.Vector;
     
     import javax.crypto.Cipher;
    @@ -86,12 +89,16 @@ import org.bouncycastle.asn1.x509.Extension;
     import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
     import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
     import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
    -import org.bouncycastle.jcajce.provider.config.PKCS12StoreParameter;
    -import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
    +import org.bouncycastle.crypto.Digest;
    +import org.bouncycastle.crypto.digests.SHA1Digest;
    +import org.bouncycastle.jcajce.PKCS12Key;
    +import org.bouncycastle.jcajce.PKCS12StoreParameter;
     // BEGIN android-removed
     // import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
     // END android-removed
     import org.bouncycastle.jcajce.spec.PBKDF2KeySpec;
    +import org.bouncycastle.jcajce.util.BCJcaJceHelper;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
     import org.bouncycastle.jce.interfaces.BCKeyStore;
     import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
     import org.bouncycastle.jce.provider.BouncyCastleProvider;
    @@ -105,10 +112,11 @@ public class PKCS12KeyStoreSpi
         extends KeyStoreSpi
         implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
     {
    +    private final JcaJceHelper helper = new BCJcaJceHelper();
    +
         private static final int SALT_SIZE = 20;
         private static final int MIN_ITERATIONS = 1024;
     
    -    private static final Provider bcProvider = new BouncyCastleProvider();
         private static final DefaultSecretKeyProvider keySizeProvider = new DefaultSecretKeyProvider();
     
         private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
    @@ -210,10 +218,9 @@ public class PKCS12KeyStoreSpi
         {
             try
             {
    -            SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
    -                (ASN1Sequence)ASN1Primitive.fromByteArray(pubKey.getEncoded()));
    +            SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
     
    -            return new SubjectKeyIdentifier(info);
    +            return new SubjectKeyIdentifier(getDigest(info));
             }
             catch (Exception e)
             {
    @@ -221,6 +228,17 @@ public class PKCS12KeyStoreSpi
             }
         }
     
    +    private static byte[] getDigest(SubjectPublicKeyInfo spki)
    +    {
    +        Digest digest = new SHA1Digest();
    +        byte[]  resBuf = new byte[digest.getDigestSize()];
    +
    +        byte[] bytes = spki.getPublicKeyData().getBytes();
    +        digest.update(bytes, 0, bytes.length);
    +        digest.doFinal(resBuf, 0);
    +        return resBuf;
    +    }
    +
         public void setRandom(
             SecureRandom rand)
         {
    @@ -258,7 +276,8 @@ public class PKCS12KeyStoreSpi
     
         /**
          * this is not quite complete - we should follow up on the chain, a bit
    -     * tricky if a certificate appears in more than one chain...
    +     * tricky if a certificate appears in more than one chain... the store method
    +     * now prunes out unused certificates from the chain map if they are present.
          */
         public void engineDeleteEntry(
             String alias)
    @@ -433,14 +452,21 @@ public class PKCS12KeyStoreSpi
                         }
                     }
     
    -                cs.addElement(c);
    -                if (nextC != c)     // self signed - end of the chain
    +                if (cs.contains(c))
                     {
    -                    c = nextC;
    +                    c = null;          // we've got a certificate chain loop time to stop
                     }
                     else
                     {
    -                    c = null;
    +                    cs.addElement(c);
    +                    if (nextC != c)     // self signed - end of the chain
    +                    {
    +                        c = nextC;
    +                    }
    +                    else
    +                    {
    +                        c = null;
    +                    }
                     }
                 }
     
    @@ -588,23 +614,15 @@ public class PKCS12KeyStoreSpi
                 if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
                 {
                     PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
    -
    -                PBEKeySpec pbeSpec = new PBEKeySpec(password);
    -                PrivateKey out;
    -
    -                SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
    -                    algorithm.getId(), bcProvider);
                     PBEParameterSpec defParams = new PBEParameterSpec(
                         pbeParams.getIV(),
                         pbeParams.getIterations().intValue());
     
    -                SecretKey k = keyFact.generateSecret(pbeSpec);
    -
    -                ((BCPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
    +                Cipher cipher = helper.createCipher(algorithm.getId());
     
    -                Cipher cipher = Cipher.getInstance(algorithm.getId(), bcProvider);
    +                PKCS12Key key = new PKCS12Key(password, wrongPKCS12Zero);
     
    -                cipher.init(Cipher.UNWRAP_MODE, k, defParams);
    +                cipher.init(Cipher.UNWRAP_MODE, key, defParams);
     
                     // we pass "" as the key algorithm type as it is unknown at this point
                     return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
    @@ -638,13 +656,12 @@ public class PKCS12KeyStoreSpi
     
             try
             {
    -            SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
    -                algorithm, bcProvider);
    +            SecretKeyFactory keyFact =  helper.createSecretKeyFactory(algorithm);
                 PBEParameterSpec defParams = new PBEParameterSpec(
                     pbeParams.getIV(),
                     pbeParams.getIterations().intValue());
     
    -            Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
    +            Cipher cipher = helper.createCipher(algorithm);
     
                 cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
     
    @@ -667,6 +684,7 @@ public class PKCS12KeyStoreSpi
             throws IOException
         {
             ASN1ObjectIdentifier algorithm = algId.getAlgorithm();
    +        int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
     
             if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds))
             {
    @@ -675,16 +693,13 @@ public class PKCS12KeyStoreSpi
     
                 try
                 {
    -                SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm.getId(), bcProvider);
                     PBEParameterSpec defParams = new PBEParameterSpec(
                         pbeParams.getIV(),
                         pbeParams.getIterations().intValue());
    -                BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
    +                PKCS12Key key = new PKCS12Key(password, wrongPKCS12Zero);
     
    -                key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
    +                Cipher cipher = helper.createCipher(algorithm.getId());
     
    -                Cipher cipher = Cipher.getInstance(algorithm.getId(), bcProvider);
    -                int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
                     cipher.init(mode, key, defParams);
                     return cipher.doFinal(data);
                 }
    @@ -697,7 +712,7 @@ public class PKCS12KeyStoreSpi
             {
                 try
                 {
    -                Cipher cipher = createCipher(Cipher.DECRYPT_MODE, password, algId);
    +                Cipher cipher = createCipher(mode, password, algId);
     
                     return cipher.doFinal(data);
                 }
    @@ -713,13 +728,13 @@ public class PKCS12KeyStoreSpi
         }
     
         private Cipher createCipher(int mode, char[] password, AlgorithmIdentifier algId)
    -        throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException
    +        throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchProviderException
         {
             PBES2Parameters alg = PBES2Parameters.getInstance(algId.getParameters());
             PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters());
             AlgorithmIdentifier encScheme = AlgorithmIdentifier.getInstance(alg.getEncryptionScheme());
     
    -        SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg.getKeyDerivationFunc().getAlgorithm().getId(), bcProvider);
    +        SecretKeyFactory keyFact = helper.createSecretKeyFactory(alg.getKeyDerivationFunc().getAlgorithm().getId());
             SecretKey key;
     
             if (func.isDefaultPrf())
    @@ -1027,9 +1042,9 @@ public class PKCS12KeyStoreSpi
                                 Enumeration e = b.getBagAttributes().getObjects();
                                 while (e.hasMoreElements())
                                 {
    -                                ASN1Sequence sq = (ASN1Sequence)e.nextElement();
    -                                ASN1ObjectIdentifier aOid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
    -                                ASN1Set attrSet = (ASN1Set)sq.getObjectAt(1);
    +                                ASN1Sequence sq = ASN1Sequence.getInstance(e.nextElement());
    +                                ASN1ObjectIdentifier aOid = ASN1ObjectIdentifier.getInstance(sq.getObjectAt(0));
    +                                ASN1Set attrSet = ASN1Set.getInstance(sq.getObjectAt(1));
                                     ASN1Primitive attr = null;
     
                                     if (attrSet.size() > 0)
    @@ -1050,16 +1065,16 @@ public class PKCS12KeyStoreSpi
                                         {
                                             bagAttr.setBagAttribute(aOid, attr);
                                         }
    -                                }
     
    -                                if (aOid.equals(pkcs_9_at_friendlyName))
    -                                {
    -                                    alias = ((DERBMPString)attr).getString();
    -                                    keys.put(alias, privKey);
    -                                }
    -                                else if (aOid.equals(pkcs_9_at_localKeyId))
    -                                {
    -                                    localId = (ASN1OctetString)attr;
    +                                    if (aOid.equals(pkcs_9_at_friendlyName))
    +                                    {
    +                                        alias = ((DERBMPString)attr).getString();
    +                                        keys.put(alias, privKey);
    +                                    }
    +                                    else if (aOid.equals(pkcs_9_at_localKeyId))
    +                                    {
    +                                        localId = (ASN1OctetString)attr;
    +                                    }
                                     }
                                 }
     
    @@ -1127,38 +1142,43 @@ public class PKCS12KeyStoreSpi
                     Enumeration e = b.getBagAttributes().getObjects();
                     while (e.hasMoreElements())
                     {
    -                    ASN1Sequence sq = (ASN1Sequence)e.nextElement();
    -                    ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)sq.getObjectAt(0);
    -                    ASN1Primitive attr = (ASN1Primitive)((ASN1Set)sq.getObjectAt(1)).getObjectAt(0);
    -                    PKCS12BagAttributeCarrier bagAttr = null;
    +                    ASN1Sequence sq = ASN1Sequence.getInstance(e.nextElement());
    +                    ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(sq.getObjectAt(0));
    +                    ASN1Set attrSet = ASN1Set.getInstance(sq.getObjectAt(1));
     
    -                    if (cert instanceof PKCS12BagAttributeCarrier)
    +                    if (attrSet.size() > 0)   // sometimes this is empty!
                         {
    -                        bagAttr = (PKCS12BagAttributeCarrier)cert;
    +                        ASN1Primitive attr = (ASN1Primitive)attrSet.getObjectAt(0);
    +                        PKCS12BagAttributeCarrier bagAttr = null;
     
    -                        ASN1Encodable existing = bagAttr.getBagAttribute(oid);
    -                        if (existing != null)
    +                        if (cert instanceof PKCS12BagAttributeCarrier)
                             {
    -                            // OK, but the value has to be the same
    -                            if (!existing.toASN1Primitive().equals(attr))
    +                            bagAttr = (PKCS12BagAttributeCarrier)cert;
    +
    +                            ASN1Encodable existing = bagAttr.getBagAttribute(oid);
    +                            if (existing != null)
                                 {
    -                                throw new IOException(
    -                                    "attempt to add existing attribute with different value");
    +                                // OK, but the value has to be the same
    +                                if (!existing.toASN1Primitive().equals(attr))
    +                                {
    +                                    throw new IOException(
    +                                        "attempt to add existing attribute with different value");
    +                                }
    +                            }
    +                            else
    +                            {
    +                                bagAttr.setBagAttribute(oid, attr);
                                 }
                             }
    -                        else
    +
    +                        if (oid.equals(pkcs_9_at_friendlyName))
                             {
    -                            bagAttr.setBagAttribute(oid, attr);
    +                            alias = ((DERBMPString)attr).getString();
    +                        }
    +                        else if (oid.equals(pkcs_9_at_localKeyId))
    +                        {
    +                            localId = (ASN1OctetString)attr;
                             }
    -                    }
    -
    -                    if (oid.equals(pkcs_9_at_friendlyName))
    -                    {
    -                        alias = ((DERBMPString)attr).getString();
    -                    }
    -                    else if (oid.equals(pkcs_9_at_localKeyId))
    -                    {
    -                        localId = (ASN1OctetString)attr;
                         }
                     }
                 }
    @@ -1259,7 +1279,6 @@ public class PKCS12KeyStoreSpi
             //
             ASN1EncodableVector keyS = new ASN1EncodableVector();
     
    -
             Enumeration ks = keys.keys();
     
             while (ks.hasMoreElements())
    @@ -1509,6 +1528,8 @@ public class PKCS12KeyStoreSpi
                 }
             }
     
    +        Set usedSet = getUsedCertificateSet();
    +
             cs = chainCerts.keys();
             while (cs.hasMoreElements())
             {
    @@ -1517,6 +1538,11 @@ public class PKCS12KeyStoreSpi
                     CertId certId = (CertId)cs.nextElement();
                     Certificate cert = (Certificate)chainCerts.get(certId);
     
    +                if (!usedSet.contains(cert))
    +                {
    +                    continue;
    +                }
    +
                     if (doneCerts.get(cert) != null)
                     {
                         continue;
    @@ -1635,7 +1661,35 @@ public class PKCS12KeyStoreSpi
             asn1Out.writeObject(pfx);
         }
     
    -    private static byte[] calculatePbeMac(
    +    private Set getUsedCertificateSet()
    +    {
    +        Set usedSet = new HashSet();
    +
    +        for (Enumeration en = keys.keys(); en.hasMoreElements();)
    +        {
    +            String alias = (String)en.nextElement();
    +
    +                Certificate[] certs = engineGetCertificateChain(alias);
    +
    +                for (int i = 0; i != certs.length; i++)
    +                {
    +                    usedSet.add(certs[i]);
    +                }
    +        }
    +
    +        for (Enumeration en = certs.keys(); en.hasMoreElements();)
    +        {
    +            String alias = (String)en.nextElement();
    +
    +            Certificate cert = engineGetCertificate(alias);
    +
    +            usedSet.add(cert);
    +        }
    +
    +        return usedSet;
    +    }
    +
    +    private byte[] calculatePbeMac(
             ASN1ObjectIdentifier oid,
             byte[] salt,
             int itCount,
    @@ -1644,15 +1698,12 @@ public class PKCS12KeyStoreSpi
             byte[] data)
             throws Exception
         {
    -        SecretKeyFactory keyFact = SecretKeyFactory.getInstance(oid.getId(), bcProvider);
             PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount);
    -        PBEKeySpec pbeSpec = new PBEKeySpec(password);
    -        BCPBEKey key = (BCPBEKey)keyFact.generateSecret(pbeSpec);
    -        key.setTryWrongPKCS12Zero(wrongPkcs12Zero);
     
    -        Mac mac = Mac.getInstance(oid.getId(), bcProvider);
    -        mac.init(key, defParams);
    +        Mac mac = helper.createMac(oid.getId());
    +        mac.init(new PKCS12Key(password, wrongPkcs12Zero), defParams);
             mac.update(data);
    +
             return mac.doFinal();
         }
     
    @@ -1661,20 +1712,19 @@ public class PKCS12KeyStoreSpi
         {
             public BCPKCS12KeyStore()
             {
    -            super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
    +            super(new BouncyCastleProvider(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
             }
         }
    -
         // BEGIN android-removed
         // public static class BCPKCS12KeyStore3DES
         //     extends PKCS12KeyStoreSpi
         // {
         //     public BCPKCS12KeyStore3DES()
         //     {
    -    //         super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
    +    //         super(new BouncyCastleProvider(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
         //     }
         // }
    -    //
    +    // 
         // public static class DefPKCS12KeyStore
         //     extends PKCS12KeyStoreSpi
         // {
    @@ -1683,7 +1733,7 @@ public class PKCS12KeyStoreSpi
         //         super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
         //     }
         // }
    -    //
    +    // 
         // public static class DefPKCS12KeyStore3DES
         //     extends PKCS12KeyStoreSpi
         // {
    @@ -1755,7 +1805,7 @@ public class PKCS12KeyStoreSpi
     
                 keySizes.put(new ASN1ObjectIdentifier("1.2.840.113533.7.66.10"), Integers.valueOf(128));
     
    -            keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192));
    +            keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192));
     
                 keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128));
                 keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
    index 500bf2d..0328ac8 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
    @@ -1,8 +1,9 @@
     package org.bouncycastle.jcajce.provider.symmetric;
     
     import java.io.IOException;
    -import java.lang.reflect.Constructor;
    -import java.lang.reflect.Method;
    +// BEGIN android-added
    +import java.security.NoSuchAlgorithmException;
    +// END android-added
     // BEGIN android-removed
     // import java.security.AlgorithmParameters;
     // import java.security.InvalidAlgorithmParameterException;
    @@ -11,11 +12,15 @@ import java.security.SecureRandom;
     import java.security.spec.AlgorithmParameterSpec;
     import java.security.spec.InvalidParameterSpecException;
     
    -// BEGIN android-removed
    -// import javax.crypto.spec.IvParameterSpec;
    -// END android-removed
    +import javax.crypto.spec.IvParameterSpec;
     
    +// BEGIN android-added
    +import javax.crypto.NoSuchPaddingException;
    +// END android-added
     import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
    +// BEGIN android-removed
    +// import org.bouncycastle.asn1.cms.CCMParameters;
    +// END android-removed
     import org.bouncycastle.asn1.cms.GCMParameters;
     import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
     import org.bouncycastle.crypto.BlockCipher;
    @@ -25,11 +30,15 @@ import org.bouncycastle.crypto.engines.AESFastEngine;
     import org.bouncycastle.crypto.engines.AESWrapEngine;
     // BEGIN android-removed
     // import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
    +// import org.bouncycastle.crypto.engines.RFC5649WrapEngine;
     // import org.bouncycastle.crypto.generators.Poly1305KeyGenerator;
     // import org.bouncycastle.crypto.macs.CMac;
     // import org.bouncycastle.crypto.macs.GMac;
     // END android-removed
     import org.bouncycastle.crypto.modes.CBCBlockCipher;
    +// BEGIN android-removed
    +// import org.bouncycastle.crypto.modes.CCMBlockCipher;
    +// END android-removed
     import org.bouncycastle.crypto.modes.CFBBlockCipher;
     import org.bouncycastle.crypto.modes.GCMBlockCipher;
     import org.bouncycastle.crypto.modes.OFBBlockCipher;
    @@ -47,10 +56,6 @@ import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
     import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider;
     import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
     import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
    -// BEGIN android-removed
    -// import org.bouncycastle.jce.provider.BouncyCastleProvider;
    -// END android-removed
    -import org.bouncycastle.util.Integers;
     
     public final class AES
     {
    @@ -108,10 +113,28 @@ public final class AES
             public GCM()
             {
                 super(new GCMBlockCipher(new AESFastEngine()));
    +            // BEGIN android-added
    +            try {
    +                engineSetMode("GCM");
    +                engineSetPadding("NoPadding");
    +            } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
    +                // this should not be possible
    +                throw new RuntimeException("Could not set mode or padding for GCM mode", e);
    +            }
    +            // END android-added
             }
         }
     
         // BEGIN android-removed
    +    // static public class CCM
    +    //     extends BaseBlockCipher
    +    // {
    +    //     public CCM()
    +    //     {
    +    //         super(new CCMBlockCipher(new AESFastEngine()), false, 16);
    +    //     }
    +    // }
    +    //
         // public static class AESCMAC
         //     extends BaseMac
         // {
    @@ -157,7 +180,7 @@ public final class AES
                 super(new AESWrapEngine());
             }
         }
    -    
    +
         // BEGIN android-removed
         // public static class RFC3211Wrap
         //     extends BaseWrapCipher
    @@ -167,9 +190,17 @@ public final class AES
         //         super(new RFC3211WrapEngine(new AESFastEngine()), 16);
         //     }
         // }
    +    //
    +    // public static class RFC5649Wrap
    +    //     extends BaseWrapCipher
    +    // {
    +    //     public RFC5649Wrap()
    +    //     {
    +    //         super(new RFC5649WrapEngine(new AESFastEngine()));
    +    //     }
    +    // }
         // END android-removed
     
    -    
         /**
          * PBEWithAES-CBC
          */
    @@ -181,13 +212,75 @@ public final class AES
                 super(new CBCBlockCipher(new AESFastEngine()));
             }
         }
    -    
    +
    +    /**
    +     * PBEWithSHA1AES-CBC
    +     */
    +    static public class PBEWithSHA1AESCBC128
    +        extends BaseBlockCipher
    +    {
    +        public PBEWithSHA1AESCBC128()
    +        {
    +            super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 128, 16);
    +        }
    +    }
    +
    +    static public class PBEWithSHA1AESCBC192
    +        extends BaseBlockCipher
    +    {
    +        public PBEWithSHA1AESCBC192()
    +        {
    +            super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 192, 16);
    +        }
    +    }
    +
    +    static public class PBEWithSHA1AESCBC256
    +        extends BaseBlockCipher
    +    {
    +        public PBEWithSHA1AESCBC256()
    +        {
    +            super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA1, 256, 16);
    +        }
    +    }
    +
    +    /**
    +     * PBEWithSHA256AES-CBC
    +     */
    +    static public class PBEWithSHA256AESCBC128
    +        extends BaseBlockCipher
    +    {
    +        public PBEWithSHA256AESCBC128()
    +        {
    +            super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 128, 16);
    +        }
    +    }
    +
    +    static public class PBEWithSHA256AESCBC192
    +        extends BaseBlockCipher
    +    {
    +        public PBEWithSHA256AESCBC192()
    +        {
    +            super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 192, 16);
    +        }
    +    }
    +
    +    static public class PBEWithSHA256AESCBC256
    +        extends BaseBlockCipher
    +    {
    +        public PBEWithSHA256AESCBC256()
    +        {
    +            super(new CBCBlockCipher(new AESFastEngine()), PKCS12, SHA256, 256, 16);
    +        }
    +    }
    +
         public static class KeyGen
             extends BaseKeyGenerator
         {
             public KeyGen()
             {
    -            this(192);
    +            // BEGIN android-changed
    +            this(128);
    +            // END android-changed
             }
     
             public KeyGen(int keySize)
    @@ -360,7 +453,7 @@ public final class AES
         //
         //         try
         //         {
    -    //             params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
    +    //             params = createParametersInstance("AES");
         //             params.init(new IvParameterSpec(iv));
         //         }
         //         catch (Exception e)
    @@ -371,6 +464,82 @@ public final class AES
         //         return params;
         //     }
         // }
    +    //
    +    // public static class AlgParamGenCCM
    +    //     extends BaseAlgorithmParameterGenerator
    +    // {
    +    //     protected void engineInit(
    +    //         AlgorithmParameterSpec genParamSpec,
    +    //         SecureRandom random)
    +    //         throws InvalidAlgorithmParameterException
    +    //     {
    +    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
    +    //     }
    +    //
    +    //     protected AlgorithmParameters engineGenerateParameters()
    +    //     {
    +    //         byte[]  iv = new byte[12];
    +    //
    +    //         if (random == null)
    +    //         {
    +    //             random = new SecureRandom();
    +    //         }
    +    //
    +    //         random.nextBytes(iv);
    +    //
    +    //         AlgorithmParameters params;
    +    //
    +    //         try
    +    //         {
    +    //             params = createParametersInstance("CCM");
    +    //             params.init(new CCMParameters(iv, 12).getEncoded());
    +    //         }
    +    //         catch (Exception e)
    +    //         {
    +    //             throw new RuntimeException(e.getMessage());
    +    //         }
    +    //
    +    //         return params;
    +    //     }
    +    // }
    +    //
    +    // public static class AlgParamGenGCM
    +    //     extends BaseAlgorithmParameterGenerator
    +    // {
    +    //     protected void engineInit(
    +    //         AlgorithmParameterSpec genParamSpec,
    +    //         SecureRandom random)
    +    //         throws InvalidAlgorithmParameterException
    +    //     {
    +    //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for AES parameter generation.");
    +    //     }
    +    //
    +    //     protected AlgorithmParameters engineGenerateParameters()
    +    //     {
    +    //         byte[]  nonce = new byte[12];
    +    //
    +    //         if (random == null)
    +    //         {
    +    //             random = new SecureRandom();
    +    //         }
    +    //
    +    //         random.nextBytes(nonce);
    +    //
    +    //         AlgorithmParameters params;
    +    //
    +    //         try
    +    //         {
    +    //             params = createParametersInstance("GCM");
    +    //             params.init(new GCMParameters(nonce, 12).getEncoded());
    +    //         }
    +    //         catch (Exception e)
    +    //         {
    +    //             throw new RuntimeException(e.getMessage());
    +    //         }
    +    //
    +    //         return params;
    +    //     }
    +    // }
         // END android-removed
     
         public static class AlgParams
    @@ -390,20 +559,13 @@ public final class AES
             protected void engineInit(AlgorithmParameterSpec paramSpec)
                 throws InvalidParameterSpecException
             {
    -            if (gcmSpecClass != null)
    +            if (GcmSpecUtil.isGcmSpec(paramSpec))
                 {
    -                try
    -                {
    -                    Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
    -                    Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
    -
    -
    -                    gcmParams = new GCMParameters((byte[])iv.invoke(paramSpec, new Object[0]), ((Integer)tLen.invoke(paramSpec, new Object[0])).intValue());
    -                }
    -                catch (Exception e)
    -                {
    -                    throw new InvalidParameterSpecException("Cannot process GCMParameterSpec.");
    -                }
    +                gcmParams = GcmSpecUtil.extractGcmParameters(paramSpec);
    +            }
    +            else
    +            {
    +                throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + paramSpec.getClass().getName());
                 }
             }
     
    @@ -449,28 +611,102 @@ public final class AES
             protected AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
                 throws InvalidParameterSpecException
             {
    -            if (gcmSpecClass != null)
    +            if (paramSpec == AlgorithmParameterSpec.class || GcmSpecUtil.isGcmSpec(paramSpec))
                 {
    -                try
    -                {
    -                    Constructor constructor = gcmSpecClass.getConstructor(new Class[] { byte[].class, Integer.class });
    -
    -                    return (AlgorithmParameterSpec)constructor.newInstance(new Object[] { gcmParams.getNonce(), Integers.valueOf(gcmParams.getIcvLen()) });
    -                }
    -                catch (NoSuchMethodException e)
    -                {
    -                    throw new InvalidParameterSpecException("no constructor found!");   // should never happen
    -                }
    -                catch (Exception e)
    +                if (GcmSpecUtil.gcmSpecExists())
                     {
    -                    throw new InvalidParameterSpecException("construction failed: " + e.getMessage());   // should never happen
    +                    return GcmSpecUtil.extractGcmSpec(gcmParams.toASN1Primitive());
                     }
    +                return new IvParameterSpec(gcmParams.getNonce());
    +            }
    +            if (paramSpec == IvParameterSpec.class)
    +            {
    +                return new IvParameterSpec(gcmParams.getNonce());
                 }
     
    -            throw new InvalidParameterSpecException("unknown parameter spec: " + paramSpec.getName());
    +            throw new InvalidParameterSpecException("AlgorithmParameterSpec not recognized: " + paramSpec.getName());
             }
         }
     
    +    // BEGIN android-removed
    +    // public static class AlgParamsCCM
    +    //     extends BaseAlgorithmParameters
    +    // {
    +    //     private CCMParameters ccmParams;
    +    //
    +    //     protected void engineInit(AlgorithmParameterSpec paramSpec)
    +    //         throws InvalidParameterSpecException
    +    //     {
    +    //         if (GcmSpecUtil.isGcmSpec(paramSpec))
    +    //         {
    +    //             ccmParams = CCMParameters.getInstance(GcmSpecUtil.extractGcmParameters(paramSpec));
    +    //         }
    +    //         else
    +    //         {
    +    //             throw new InvalidParameterSpecException("AlgorithmParameterSpec class not recognized: " + paramSpec.getClass().getName());
    +    //         }
    +    //     }
    +    //
    +    //     protected void engineInit(byte[] params)
    +    //         throws IOException
    +    //     {
    +    //         ccmParams = CCMParameters.getInstance(params);
    +    //     }
    +    //
    +    //     protected void engineInit(byte[] params, String format)
    +    //         throws IOException
    +    //     {
    +    //         if (!isASN1FormatString(format))
    +    //         {
    +    //             throw new IOException("unknown format specified");
    +    //         }
    +    //
    +    //         ccmParams = CCMParameters.getInstance(params);
    +    //     }
    +    //
    +    //     protected byte[] engineGetEncoded()
    +    //         throws IOException
    +    //     {
    +    //         return ccmParams.getEncoded();
    +    //     }
    +    //
    +    //     protected byte[] engineGetEncoded(String format)
    +    //         throws IOException
    +    //     {
    +    //         if (!isASN1FormatString(format))
    +    //         {
    +    //             throw new IOException("unknown format specified");
    +    //         }
    +    //
    +    //         return ccmParams.getEncoded();
    +    //     }
    +    //
    +    //     protected String engineToString()
    +    //     {
    +    //         return "CCM";
    +    //     }
    +    //
    +    //     protected AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
    +    //         throws InvalidParameterSpecException
    +    //     {
    +    //         if (paramSpec == AlgorithmParameterSpec.class || GcmSpecUtil.isGcmSpec(paramSpec))
    +    //         {
    +    //             if (GcmSpecUtil.gcmSpecExists())
    +    //             {
    +    //                 return GcmSpecUtil.extractGcmSpec(ccmParams.toASN1Primitive());
    +    //             }
    +    //             return new IvParameterSpec(ccmParams.getNonce());
    +    //         }
    +    //         if (paramSpec == IvParameterSpec.class)
    +    //         {
    +    //             return new IvParameterSpec(ccmParams.getNonce());
    +    //         }
    +    //
    +    //         throw new InvalidParameterSpecException("AlgorithmParameterSpec not recognized: " + paramSpec.getName());
    +    //     }
    +    // }
    +    // END android-removed
    +
         public static class Mappings
             extends SymmetricAlgorithmProvider
         {
    @@ -503,8 +739,12 @@ public final class AES
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
    -
                 // BEGIN android-removed
    +            // provider.addAlgorithm("AlgorithmParameters.CCM", PREFIX + "$AlgParamsCCM");
    +            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_CCM, "CCM");
    +            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CCM, "CCM");
    +            // provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CCM, "CCM");
    +            //
                 // provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen");
                 // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
                 // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
    @@ -519,70 +759,96 @@ public final class AES
                 provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES192, "AES");
                 provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES256, "AES");
                 // BEGIN android-removed
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$ECB");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$ECB");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$ECB");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$OFB");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$OFB");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$OFB");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$CFB");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$CFB");
    -            // provider.addAlgorithm("Cipher." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$CFB");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$ECB");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$ECB");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$ECB");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$CBC");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$CBC");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$CBC");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$OFB");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$OFB");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$OFB");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$CFB");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$CFB");
    +            // provider.addAlgorithm("Cipher", NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$CFB");
                 // END android-removed
                 provider.addAlgorithm("Cipher.AESWRAP", PREFIX + "$Wrap");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
    +            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes128_wrap, "AESWRAP");
    +            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes192_wrap, "AESWRAP");
    +            provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes256_wrap, "AESWRAP");
    +            provider.addAlgorithm("Alg.Alias.Cipher.AESKW", "AESWRAP");
    +
                 // BEGIN android-removed
                 // provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap");
    +            // provider.addAlgorithm("Cipher.AESRFC5649WRAP", PREFIX + "$RFC5649Wrap");
    +            //
    +            // provider.addAlgorithm("AlgorithmParameterGenerator.CCM", PREFIX + "$AlgParamGenCCM");
    +            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CCM, "CCM");
    +            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CCM, "CCM");
    +            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CCM, "CCM");
    +            //
    +            // provider.addAlgorithm("Cipher.CCM", PREFIX + "$CCM");
    +            // provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes128_CCM, "CCM");
    +            // provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes192_CCM, "CCM");
    +            // provider.addAlgorithm("Alg.Alias.Cipher", NISTObjectIdentifiers.id_aes256_CCM, "CCM");
    +            //
    +            // provider.addAlgorithm("AlgorithmParameterGenerator.GCM", PREFIX + "$AlgParamGenGCM");
    +            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
    +            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
    +            // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
                 // END android-removed
     
    -            provider.addAlgorithm("Cipher.GCM", PREFIX + "$GCM");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_GCM, "GCM");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_GCM, "GCM");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_GCM, "GCM");
    +            // BEGIN android-changed
    +            provider.addAlgorithm("Cipher.AES/GCM/NOPADDING", PREFIX + "$GCM");
    +            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes128_GCM, "AES/GCM/NOPADDING");
    +            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes192_GCM, "AES/GCM/NOPADDING");
    +            provider.addAlgorithm("Alg.Alias.Cipher." + NISTObjectIdentifiers.id_aes256_GCM, "AES/GCM/NOPADDING");
    +            // END android-changed
     
                 provider.addAlgorithm("KeyGenerator.AES", PREFIX + "$KeyGen");
                 // BEGIN android-removed
                 // provider.addAlgorithm("KeyGenerator." + wrongAES128, PREFIX + "$KeyGen128");
                 // provider.addAlgorithm("KeyGenerator." + wrongAES192, PREFIX + "$KeyGen192");
                 // provider.addAlgorithm("KeyGenerator." + wrongAES256, PREFIX + "$KeyGen256");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$KeyGen128");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$KeyGen128");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$KeyGen128");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$KeyGen128");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$KeyGen192");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$KeyGen192");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$KeyGen192");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$KeyGen192");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$KeyGen256");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$KeyGen256");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$KeyGen256");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$KeyGen256");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_ECB, PREFIX + "$KeyGen128");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_CBC, PREFIX + "$KeyGen128");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_OFB, PREFIX + "$KeyGen128");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_CFB, PREFIX + "$KeyGen128");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_ECB, PREFIX + "$KeyGen192");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_CBC, PREFIX + "$KeyGen192");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_OFB, PREFIX + "$KeyGen192");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_CFB, PREFIX + "$KeyGen192");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_ECB, PREFIX + "$KeyGen256");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_CBC, PREFIX + "$KeyGen256");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_OFB, PREFIX + "$KeyGen256");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_CFB, PREFIX + "$KeyGen256");
                 // provider.addAlgorithm("KeyGenerator.AESWRAP", PREFIX + "$KeyGen");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes128_wrap, PREFIX + "$KeyGen128");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes192_wrap, PREFIX + "$KeyGen192");
    -            // provider.addAlgorithm("KeyGenerator." + NISTObjectIdentifiers.id_aes256_wrap, PREFIX + "$KeyGen256");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_wrap, PREFIX + "$KeyGen128");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_wrap, PREFIX + "$KeyGen192");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_wrap, PREFIX + "$KeyGen256");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_GCM, PREFIX + "$KeyGen128");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_GCM, PREFIX + "$KeyGen192");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_GCM, PREFIX + "$KeyGen256");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes128_CCM, PREFIX + "$KeyGen128");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes192_CCM, PREFIX + "$KeyGen192");
    +            // provider.addAlgorithm("KeyGenerator", NISTObjectIdentifiers.id_aes256_CCM, PREFIX + "$KeyGen256");
                 //
                 // provider.addAlgorithm("Mac.AESCMAC", PREFIX + "$AESCMAC");
                 // END android-removed
                 
    -            provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PBEWITHSHAAND256BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
    -    
    -            provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
    -            provider.addAlgorithm("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
    -            provider.addAlgorithm("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
    -            provider.addAlgorithm("Cipher.PBEWITHSHA256AND128BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
    -            provider.addAlgorithm("Cipher.PBEWITHSHA256AND192BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
    -            provider.addAlgorithm("Cipher.PBEWITHSHA256AND256BITAES-CBC-BC", PREFIX + "$PBEWithAESCBC");
    +            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc, "PBEWITHSHAAND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc, "PBEWITHSHAAND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc, "PBEWITHSHAAND256BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc, "PBEWITHSHA256AND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc, "PBEWITHSHA256AND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc, "PBEWITHSHA256AND256BITAES-CBC-BC");
    +
    +            provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", PREFIX + "$PBEWithSHA1AESCBC128");
    +            provider.addAlgorithm("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", PREFIX + "$PBEWithSHA1AESCBC192");
    +            provider.addAlgorithm("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", PREFIX + "$PBEWithSHA1AESCBC256");
    +            provider.addAlgorithm("Cipher.PBEWITHSHA256AND128BITAES-CBC-BC", PREFIX + "$PBEWithSHA256AESCBC128");
    +            provider.addAlgorithm("Cipher.PBEWITHSHA256AND192BITAES-CBC-BC", PREFIX + "$PBEWithSHA256AESCBC192");
    +            provider.addAlgorithm("Cipher.PBEWITHSHA256AND256BITAES-CBC-BC", PREFIX + "$PBEWithSHA256AESCBC256");
                 
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
    @@ -590,10 +856,25 @@ public final class AES
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND128BITAES-BC","PBEWITHSHAAND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND192BITAES-BC", "PBEWITHSHAAND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND256BITAES-BC", "PBEWITHSHAAND256BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITAES-BC","PBEWITHSHAAND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND192BITAES-BC","PBEWITHSHAAND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND256BITAES-BC","PBEWITHSHAAND256BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND128BITAES-BC","PBEWITHSHAAND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND192BITAES-BC","PBEWITHSHAAND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-1AND256BITAES-BC","PBEWITHSHAAND256BITAES-CBC-BC");
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
    -            
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA256AND128BITAES-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA256AND192BITAES-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA256AND256BITAES-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND128BITAES-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND192BITAES-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA-256AND256BITAES-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
    +
                 provider.addAlgorithm("Cipher.PBEWITHMD5AND128BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
                 provider.addAlgorithm("Cipher.PBEWITHMD5AND192BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
                 provider.addAlgorithm("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", PREFIX + "$PBEWithAESCBC");
    @@ -617,12 +898,15 @@ public final class AES
                 provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
                 provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
                 provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PBEWITHSHAAND256BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND128BITAES-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND192BITAES-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND256BITAES-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc, "PBEWITHSHAAND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc, "PBEWITHSHAAND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc, "PBEWITHSHAAND256BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc, "PBEWITHSHA256AND128BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc, "PBEWITHSHA256AND192BITAES-CBC-BC");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc, "PBEWITHSHA256AND256BITAES-CBC-BC");
                 
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITAES-CBC-BC", "PKCS12PBE");
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND192BITAES-CBC-BC", "PKCS12PBE");
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
    index 9de8ef0..c780d12 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
    @@ -68,7 +68,7 @@ public final class ARC4
         {
             public PBEWithSHAAnd128Bit()
             {
    -            super(new RC4Engine(), 0);
    +            super(new RC4Engine(), 0, 128, SHA1);
             }
         }
     
    @@ -80,7 +80,7 @@ public final class ARC4
         {
             public PBEWithSHAAnd40Bit()
             {
    -            super(new RC4Engine(), 0);
    +            super(new RC4Engine(), 0, 40, SHA1);
             }
         }
     
    @@ -96,7 +96,7 @@ public final class ARC4
             public void configure(ConfigurableProvider provider)
             {
                 provider.addAlgorithm("Cipher.ARC4", PREFIX + "$Base");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.rc4, "ARC4");
    +            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.rc4, "ARC4");
                 provider.addAlgorithm("Alg.Alias.Cipher.ARCFOUR", "ARC4");
                 provider.addAlgorithm("Alg.Alias.Cipher.RC4", "ARC4");
                 provider.addAlgorithm("KeyGenerator.ARC4", PREFIX + "$KeyGen");
    @@ -113,14 +113,14 @@ public final class ARC4
                 provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITRC4", PREFIX + "$PBEWithSHAAnd128Bit");
                 provider.addAlgorithm("Cipher.PBEWITHSHAAND40BITRC4", PREFIX + "$PBEWithSHAAnd40Bit");
     
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PBEWITHSHAAND128BITRC4");
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PBEWITHSHAAND40BITRC4");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PBEWITHSHAAND128BITRC4");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PBEWITHSHAAND40BITRC4");
     
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "PBEWITHSHAAND128BITRC4");
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "PBEWITHSHAAND40BITRC4");
     
    -            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PBEWITHSHAAND128BITRC4");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PBEWITHSHAAND40BITRC4");
    +            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, "PBEWITHSHAAND128BITRC4");
    +            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC4, "PBEWITHSHAAND40BITRC4");
             }
         }
     }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
    index 0e37487..c0a0949 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
    @@ -1,11 +1,18 @@
     package org.bouncycastle.jcajce.provider.symmetric;
     
    +import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
     import org.bouncycastle.crypto.CipherKeyGenerator;
     import org.bouncycastle.crypto.engines.BlowfishEngine;
    +// BEGIN android-removed
    +// import org.bouncycastle.crypto.macs.CMac;
    +// END android-removed
     import org.bouncycastle.crypto.modes.CBCBlockCipher;
     import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
     import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
     import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
    +// BEGIN android-removed
    +// import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
    +// END android-removed
     import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
     import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
     
    @@ -33,6 +40,17 @@ public final class Blowfish
             }
         }
     
    +    // BEGIN android-removed
    +    // public static class CMAC
    +    //     extends BaseMac
    +    // {
    +    //     public CMAC()
    +    //     {
    +    //         super(new CMac(new BlowfishEngine()));
    +    //     }
    +    // }
    +    // END android-removed
    +
         public static class KeyGen
             extends BaseKeyGenerator
         {
    @@ -62,15 +80,17 @@ public final class Blowfish
     
             public void configure(ConfigurableProvider provider)
             {
    -
    +            // BEGIN android-removed
    +            // provider.addAlgorithm("Mac.BLOWFISHCMAC", PREFIX + "$CMAC");
    +            // END android-removed
                 provider.addAlgorithm("Cipher.BLOWFISH", PREFIX + "$ECB");
                 // BEGIN android-removed
    -            // provider.addAlgorithm("Cipher.1.3.6.1.4.1.3029.1.2", PREFIX + "$CBC");
    +            // provider.addAlgorithm("Cipher", MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CBC, PREFIX + "$CBC");
                 // END android-removed
                 provider.addAlgorithm("KeyGenerator.BLOWFISH", PREFIX + "$KeyGen");
    -            provider.addAlgorithm("Alg.Alias.KeyGenerator.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
    +            provider.addAlgorithm("Alg.Alias.KeyGenerator", MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CBC, "BLOWFISH");
                 provider.addAlgorithm("AlgorithmParameters.BLOWFISH", PREFIX + "$AlgParams");
    -            provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
    +            provider.addAlgorithm("Alg.Alias.AlgorithmParameters", MiscObjectIdentifiers.cryptlib_algorithm_blowfish_CBC, "BLOWFISH");
     
             }
         }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
    index 6d5c5e8..5a4f8cd 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
    @@ -44,7 +44,6 @@ import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
     import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
     import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
     import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
    -import org.bouncycastle.jce.provider.BouncyCastleProvider;
     
     public final class DES
     {
    @@ -187,7 +186,7 @@ public final class DES
     
                 try
                 {
    -                params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
    +                params = createParametersInstance("DES");
                     params.init(new IvParameterSpec(iv));
                 }
                 catch (Exception e)
    @@ -406,7 +405,7 @@ public final class DES
         // {
         //     public PBEWithMD2()
         //     {
    -    //         super(new CBCBlockCipher(new DESEngine()));
    +    //         super(new CBCBlockCipher(new DESEngine()), PKCS5S1, MD2, 64, 8);
         //     }
         // }
         // END android-removed
    @@ -419,7 +418,7 @@ public final class DES
         {
             public PBEWithMD5()
             {
    -            super(new CBCBlockCipher(new DESEngine()));
    +            super(new CBCBlockCipher(new DESEngine()), PKCS5S1, MD5, 64, 8);
             }
         }
     
    @@ -431,7 +430,7 @@ public final class DES
         {
             public PBEWithSHA1()
             {
    -            super(new CBCBlockCipher(new DESEngine()));
    +            super(new CBCBlockCipher(new DESEngine()), PKCS5S1, SHA1, 64, 8);
             }
         }
         
    @@ -450,7 +449,7 @@ public final class DES
     
                 provider.addAlgorithm("Cipher.DES", PREFIX + "$ECB");
                 // BEGIN android-removed
    -            // provider.addAlgorithm("Cipher." + OIWObjectIdentifiers.desCBC, PREFIX + "$CBC");
    +            // provider.addAlgorithm("Cipher", OIWObjectIdentifiers.desCBC, PREFIX + "$CBC");
                 //
                 // addAlias(provider, OIWObjectIdentifiers.desCBC, "DES");
                 //
    @@ -487,7 +486,7 @@ public final class DES
                 // END android-removed
     
                 provider.addAlgorithm("AlgorithmParameters.DES", PACKAGE + ".util.IvAlgorithmParameters");
    -            provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + OIWObjectIdentifiers.desCBC, "DES");
    +            provider.addAlgorithm("Alg.Alias.AlgorithmParameters", OIWObjectIdentifiers.desCBC, "DES");
     
                 // BEGIN android-removed
                 // provider.addAlgorithm("AlgorithmParameterGenerator.DES",  PREFIX + "$AlgParamGen");
    @@ -499,13 +498,19 @@ public final class DES
                 provider.addAlgorithm("Cipher.PBEWITHSHA1ANDDES", PREFIX + "$PBEWithSHA1");
                 
                 // BEGIN android-removed
    -            // provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
    +            // provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
                 // END android-removed
    -            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
    -            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
    -            
    +            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
    +            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
    +
    +            // BEGIN android-removed
    +            // provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHMD2ANDDES-CBC", "PBEWITHMD2ANDDES");
    +            // BEGIN android-removed
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHMD5ANDDES-CBC", "PBEWITHMD5ANDDES");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDDES-CBC", "PBEWITHSHA1ANDDES");
    +
                 // BEGIN android-removed
    -            // provider.addAlgorithm("SecretKeyFactory.PBEWITHMD2ANDDES", PREFIX + "$PBEWithMD2KeyFactory");
    +            // provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHMD2ANDDES-CBC", "PBEWITHMD2ANDDES");
                 // END android-removed
                 provider.addAlgorithm("SecretKeyFactory.PBEWITHMD5ANDDES", PREFIX + "$PBEWithMD5KeyFactory");
                 provider.addAlgorithm("SecretKeyFactory.PBEWITHSHA1ANDDES", PREFIX + "$PBEWithSHA1KeyFactory");
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
    index 6b9b6d6..64d8972 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
    @@ -43,7 +43,6 @@ import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
     import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
     import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher;
     import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
    -import org.bouncycastle.jce.provider.BouncyCastleProvider;
     
     public final class DESede
     {
    @@ -106,7 +105,7 @@ public final class DESede
                 super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
             }
         }
    -    
    +
         public static class CBCMAC
             extends BaseMac
         {
    @@ -126,7 +125,7 @@ public final class DESede
         //     }
         // }
         // END android-removed
    -    
    +
         public static class Wrap
             extends BaseWrapCipher
         {
    @@ -135,7 +134,7 @@ public final class DESede
                 super(new DESedeWrapEngine());
             }
         }
    -    
    +
         // BEGIN android-removed
         // public static class RFC3211
         //     extends BaseWrapCipher
    @@ -219,7 +218,7 @@ public final class DESede
         {
             public PBEWithSHAAndDES3Key()
             {
    -            super(new CBCBlockCipher(new DESedeEngine()));
    +            super(new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1, 192, 8);
             }
         }
     
    @@ -231,7 +230,7 @@ public final class DESede
         {
             public PBEWithSHAAndDES2Key()
             {
    -            super(new CBCBlockCipher(new DESedeEngine()));
    +            super(new CBCBlockCipher(new DESedeEngine()), PKCS12, SHA1, 128, 8);
             }
         }
     
    @@ -270,30 +269,30 @@ public final class DESede
         //     {
         //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DES parameter generation.");
         //     }
    -    //
    +
         //     protected AlgorithmParameters engineGenerateParameters()
         //     {
         //         byte[]  iv = new byte[8];
    -    //
    +
         //         if (random == null)
         //         {
         //             random = new SecureRandom();
         //         }
    -    //
    +
         //         random.nextBytes(iv);
    -    //
    +
         //         AlgorithmParameters params;
    -    //
    +
         //         try
         //         {
    -    //             params = AlgorithmParameters.getInstance("DES", BouncyCastleProvider.PROVIDER_NAME);
    +    //             params = createParametersInstance("DES");
         //             params.init(new IvParameterSpec(iv));
         //         }
         //         catch (Exception e)
         //         {
         //             throw new RuntimeException(e.getMessage());
         //         }
    -    //
    +
         //         return params;
         //     }
         // }
    @@ -382,7 +381,7 @@ public final class DESede
             {
                 provider.addAlgorithm("Cipher.DESEDE", PREFIX + "$ECB");
                 // BEGIN android-removed
    -            // provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$CBC");
    +            // provider.addAlgorithm("Cipher", PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$CBC");
                 // END android-removed
                 provider.addAlgorithm("Cipher.DESEDEWRAP", PREFIX + "$Wrap");
                 // BEGIN android-changed
    @@ -390,6 +389,7 @@ public final class DESede
                 // END android-changed
                 // BEGIN android-removed
                 // provider.addAlgorithm("Cipher.DESEDERFC3211WRAP", PREFIX + "$RFC3211");
    +            // provider.addAlgorithm("Alg.Alias.Cipher.DESEDERFC3217WRAP", "DESEDEWRAP");
                 // END android-removed
     
                 provider.addAlgorithm("Alg.Alias.Cipher.TDEA", "DESEDE");
    @@ -412,11 +412,16 @@ public final class DESede
                     // BEGIN android-removed
                     // provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES2Key");
                     // END android-removed
    -                provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
    -                provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
    +                provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
    +                provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
                     provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
                     provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYTRIPLEDES-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
                     provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYTRIPLEDES-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
    +                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND3-KEYDESEDE-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
    +                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAAND2-KEYDESEDE-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
    +                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND3-KEYDESEDE-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
    +                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND2-KEYDESEDE-CBC", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
    +                provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDDESEDE-CBC", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
                 }
     
                 provider.addAlgorithm("KeyGenerator.DESEDE", PREFIX + "$KeyGenerator");
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java
    new file mode 100644
    index 0000000..5ccc8ff
    --- /dev/null
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GcmSpecUtil.java
    @@ -0,0 +1,78 @@
    +package org.bouncycastle.jcajce.provider.symmetric;
    +
    +import java.lang.reflect.Constructor;
    +import java.lang.reflect.Method;
    +import java.security.spec.AlgorithmParameterSpec;
    +import java.security.spec.InvalidParameterSpecException;
    +
    +import org.bouncycastle.asn1.ASN1Primitive;
    +import org.bouncycastle.asn1.cms.GCMParameters;
    +import org.bouncycastle.util.Integers;
    +
    +class GcmSpecUtil
    +{
    +    static final Class gcmSpecClass = lookup("javax.crypto.spec.GCMParameterSpec");
    +
    +    static boolean gcmSpecExists()
    +    {
    +        return gcmSpecClass != null;
    +    }
    +
    +    static boolean isGcmSpec(AlgorithmParameterSpec paramSpec)
    +    {
    +        return gcmSpecClass != null && gcmSpecClass.isInstance(paramSpec);
    +    }
    +
    +    static boolean isGcmSpec(Class paramSpecClass)
    +    {
    +        return gcmSpecClass == paramSpecClass;
    +    }
    +
    +    static AlgorithmParameterSpec extractGcmSpec(ASN1Primitive spec)
    +        throws InvalidParameterSpecException
    +    {
    +        try
    +        {
    +            GCMParameters gcmParams = GCMParameters.getInstance(spec);
    +            Constructor constructor = gcmSpecClass.getConstructor(new Class[]{Integer.TYPE, byte[].class});
    +
    +            return (AlgorithmParameterSpec)constructor.newInstance(new Object[] { Integers.valueOf(gcmParams.getIcvLen() * 8), gcmParams.getNonce() });
    +        }
    +        catch (NoSuchMethodException e)
    +        {
    +            throw new InvalidParameterSpecException("No constructor found!");   // should never happen
    +        }
    +        catch (Exception e)
    +        {
    +            throw new InvalidParameterSpecException("Construction failed: " + e.getMessage());   // should never happen
    +        }
    +    }
    +
    +    static GCMParameters extractGcmParameters(AlgorithmParameterSpec paramSpec)
    +        throws InvalidParameterSpecException
    +    {
    +        try
    +        {
    +            Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
    +            Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
    +
    +            return new GCMParameters((byte[])iv.invoke(paramSpec, new Object[0]), ((Integer)tLen.invoke(paramSpec, new Object[0])).intValue() / 8);
    +        }
    +        catch (Exception e)
    +        {
    +            throw new InvalidParameterSpecException("Cannot process GCMParameterSpec");
    +        }
    +    }
    +
    +    private static Class lookup(String className)
    +    {
    +        try
    +        {
    +            return GcmSpecUtil.class.getClassLoader().loadClass(className);
    +        }
    +        catch (Exception e)
    +        {
    +            return null;
    +        }
    +    }
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java
    index 09426b2..343fa0c 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC2.java
    @@ -36,10 +36,7 @@ import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
     // END android-removed
     import org.bouncycastle.jcajce.provider.symmetric.util.PBESecretKeyFactory;
     import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
    -import org.bouncycastle.jce.provider.BouncyCastleProvider;
    -// BEGIN android-removed
    -// import org.bouncycastle.util.Arrays;
    -// END android-removed
    +import org.bouncycastle.util.Arrays;
     
     public final class RC2
     {
    @@ -147,7 +144,7 @@ public final class RC2
         {
             public PBEWithMD5AndRC2()
             {
    -            super(new CBCBlockCipher(new RC2Engine()));
    +            super(new CBCBlockCipher(new RC2Engine()), PKCS5S1, MD5, 64, 8);
             }
         }
         
    @@ -159,7 +156,7 @@ public final class RC2
         {
             public PBEWithSHA1AndRC2()
             {
    -            super(new CBCBlockCipher(new RC2Engine()));
    +            super(new CBCBlockCipher(new RC2Engine()), PKCS5S1, SHA1, 64, 8);
             }
         }
     
    @@ -171,7 +168,7 @@ public final class RC2
         {
             public PBEWithSHAAnd128BitRC2()
             {
    -            super(new CBCBlockCipher(new RC2Engine()));
    +            super(new CBCBlockCipher(new RC2Engine()), PKCS12, SHA1, 128, 8);
             }
         }
     
    @@ -183,7 +180,7 @@ public final class RC2
         {
             public PBEWithSHAAnd40BitRC2()
             {
    -            super(new CBCBlockCipher(new RC2Engine()));
    +            super(new CBCBlockCipher(new RC2Engine()), PKCS12, SHA1, 40, 8);
             }
         }
     
    @@ -218,7 +215,7 @@ public final class RC2
         //     extends BaseAlgorithmParameterGenerator
         // {
         //     RC2ParameterSpec spec = null;
    -    //
    +    // 
         //     protected void engineInit(
         //         AlgorithmParameterSpec genParamSpec,
         //         SecureRandom random)
    @@ -229,28 +226,28 @@ public final class RC2
         //             spec = (RC2ParameterSpec)genParamSpec;
         //             return;
         //         }
    -    //
    +    // 
         //         throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for RC2 parameter generation.");
         //     }
    -    //
    +    // 
         //     protected AlgorithmParameters engineGenerateParameters()
         //     {
         //         AlgorithmParameters params;
    -    //
    +    // 
         //         if (spec == null)
         //         {
         //             byte[] iv = new byte[8];
    -    //
    +    // 
         //             if (random == null)
         //             {
         //                 random = new SecureRandom();
         //             }
    -    //
    +    // 
         //             random.nextBytes(iv);
    -    //
    +    // 
         //             try
         //             {
    -    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
    +    //                 params = createParametersInstance("RC2");
         //                 params.init(new IvParameterSpec(iv));
         //             }
         //             catch (Exception e)
    @@ -262,7 +259,7 @@ public final class RC2
         //         {
         //             try
         //             {
    -    //                 params = AlgorithmParameters.getInstance("RC2", BouncyCastleProvider.PROVIDER_NAME);
    +    //                 params = createParametersInstance("RC2");
         //                 params.init(spec);
         //             }
         //             catch (Exception e)
    @@ -270,11 +267,11 @@ public final class RC2
         //                 throw new RuntimeException(e.getMessage());
         //             }
         //         }
    -    //
    +    // 
         //         return params;
         //     }
         // }
    -    //
    +    // 
         // public static class KeyGenerator
         //     extends BaseKeyGenerator
         // {
    @@ -283,7 +280,7 @@ public final class RC2
         //         super("RC2", 128, new CipherKeyGenerator());
         //     }
         // }
    -    //
    +    // 
         // public static class AlgParams
         //     extends BaseAlgorithmParameters
         // {
    @@ -305,7 +302,7 @@ public final class RC2
         //         0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f,
         //         0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab
         //     };
    -    //
    +    // 
         //     private static final short[] ekb = {
         //         0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5,
         //         0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5,
    @@ -324,15 +321,15 @@ public final class RC2
         //         0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7,
         //         0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd
         //     };
    -    //
    +    // 
         //     private byte[] iv;
         //     private int parameterVersion = 58;
    -    //
    +    // 
         //     protected byte[] engineGetEncoded()
         //     {
         //         return Arrays.clone(iv);
         //     }
    -    //
    +    // 
         //     protected byte[] engineGetEncoded(
         //         String format)
         //         throws IOException
    @@ -348,15 +345,15 @@ public final class RC2
         //                 return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
         //             }
         //         }
    -    //
    +    // 
         //         if (format.equals("RAW"))
         //         {
         //             return engineGetEncoded();
         //         }
    -    //
    +    // 
         //         return null;
         //     }
    -    //
    +    // 
         //     protected AlgorithmParameterSpec localEngineGetParameterSpec(
         //         Class paramSpec)
         //         throws InvalidParameterSpecException
    @@ -375,15 +372,15 @@ public final class RC2
         //                 }
         //             }
         //         }
    -    //
    +    // 
         //         if (paramSpec == IvParameterSpec.class)
         //         {
         //             return new IvParameterSpec(iv);
         //         }
    -    //
    +    // 
         //         throw new InvalidParameterSpecException("unknown parameter spec passed to RC2 parameters object.");
         //     }
    -    //
    +    // 
         //     protected void engineInit(
         //         AlgorithmParameterSpec paramSpec)
         //         throws InvalidParameterSpecException
    @@ -406,7 +403,7 @@ public final class RC2
         //                     parameterVersion = effKeyBits;
         //                 }
         //             }
    -    //
    +    // 
         //             this.iv = ((RC2ParameterSpec)paramSpec).getIV();
         //         }
         //         else
    @@ -414,14 +411,14 @@ public final class RC2
         //             throw new InvalidParameterSpecException("IvParameterSpec or RC2ParameterSpec required to initialise a RC2 parameters algorithm parameters object");
         //         }
         //     }
    -    //
    +    // 
         //     protected void engineInit(
         //         byte[] params)
         //         throws IOException
         //     {
         //         this.iv = Arrays.clone(params);
         //     }
    -    //
    +    // 
         //     protected void engineInit(
         //         byte[] params,
         //         String format)
    @@ -430,26 +427,26 @@ public final class RC2
         //         if (this.isASN1FormatString(format))
         //         {
         //             RC2CBCParameter p = RC2CBCParameter.getInstance(ASN1Primitive.fromByteArray(params));
    -    //
    +    // 
         //             if (p.getRC2ParameterVersion() != null)
         //             {
         //                 parameterVersion = p.getRC2ParameterVersion().intValue();
         //             }
    -    //
    +    // 
         //             iv = p.getIV();
    -    //
    +    // 
         //             return;
         //         }
    -    //
    +    // 
         //         if (format.equals("RAW"))
         //         {
         //             engineInit(params);
         //             return;
         //         }
    -    //
    +    // 
         //         throw new IOException("Unknown parameters format in IV parameters object");
         //     }
    -    //
    +    // 
         //     protected String engineToString()
         //     {
         //         return "RC2 Parameters";
    @@ -468,7 +465,6 @@ public final class RC2
     
             public void configure(ConfigurableProvider provider)
             {
    -
                 // BEGIN android-removed
                 // provider.addAlgorithm("AlgorithmParameterGenerator.RC2", PREFIX + "$AlgParamGen");
                 // provider.addAlgorithm("AlgorithmParameterGenerator.1.2.840.113549.3.2", PREFIX + "$AlgParamGen");
    @@ -481,8 +477,8 @@ public final class RC2
                 //
                 // provider.addAlgorithm("Cipher.RC2", PREFIX + "$ECB");
                 // provider.addAlgorithm("Cipher.RC2WRAP", PREFIX + "$Wrap");
    -            // provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2WRAP");
    -            // provider.addAlgorithm("Cipher.1.2.840.113549.3.2", PREFIX + "$CBC");
    +            // provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.id_alg_CMSRC2wrap, "RC2WRAP");
    +            // provider.addAlgorithm("Cipher", PKCSObjectIdentifiers.RC2_CBC, PREFIX + "$CBC");
                 //
                 // provider.addAlgorithm("Mac.RC2MAC", PREFIX + "$CBCMAC");
                 // provider.addAlgorithm("Alg.Alias.Mac.RC2", "RC2MAC");
    @@ -497,12 +493,12 @@ public final class RC2
                 provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDRC2-CBC", "PBEWITHSHA1ANDRC2");
     
                 // BEGIN android-removed
    -            // provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
    +            // provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
                 // END android-removed
     
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
     
    -            provider.addAlgorithm("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
    +            provider.addAlgorithm("Alg.Alias.SecretKeyFactory", PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
                 provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
                 provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
     
    @@ -514,28 +510,31 @@ public final class RC2
     
                 provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND128BITRC2-CBC", PREFIX + "$PBEWithSHAAnd128BitKeyFactory");
                 provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND40BITRC2-CBC", PREFIX + "$PBEWithSHAAnd40BitKeyFactory");
    -            
    +
                 // BEGIN android-removed
    -            // provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
    +            // provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
                 // END android-removed
     
    -            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
    +            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
     
    -            provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
    +            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
     
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.5", "PKCS12PBE");
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6", "PKCS12PBE");
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWithSHAAnd3KeyTripleDES", "PKCS12PBE");
     
    -            provider.addAlgorithm("Alg.Alias.Cipher.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
    -            provider.addAlgorithm("Alg.Alias.Cipher.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
    +            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, "PBEWITHSHAAND128BITRC2-CBC");
    +            provider.addAlgorithm("Alg.Alias.Cipher", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, "PBEWITHSHAAND40BITRC2-CBC");
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "PBEWITHSHAAND128BITRC2-CBC");
                 provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC");
                 provider.addAlgorithm("Cipher.PBEWITHSHA1ANDRC2", PREFIX + "$PBEWithSHA1AndRC2");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHAANDRC2-CBC", "PBEWITHSHA1ANDRC2");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHSHA1ANDRC2-CBC", "PBEWITHSHA1ANDRC2");
     
                 provider.addAlgorithm("Cipher.PBEWITHSHAAND128BITRC2-CBC", PREFIX + "$PBEWithSHAAnd128BitRC2");
                 provider.addAlgorithm("Cipher.PBEWITHSHAAND40BITRC2-CBC", PREFIX + "$PBEWithSHAAnd40BitRC2");
                 provider.addAlgorithm("Cipher.PBEWITHMD5ANDRC2", PREFIX + "$PBEWithMD5AndRC2");
    +            provider.addAlgorithm("Alg.Alias.Cipher.PBEWITHMD5ANDRC2-CBC", "PBEWITHMD5ANDRC2");
     
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2", "PKCS12PBE");
                 provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDRC2", "PKCS12PBE");
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
    index fc34865..7ac79e7 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SymmetricAlgorithmProvider.java
    @@ -7,6 +7,19 @@ abstract class SymmetricAlgorithmProvider
         extends AlgorithmProvider
     {
         // BEGIN android-removed
    +    // protected void addCMacAlgorithm(
    +    //     ConfigurableProvider provider,
    +    //     String algorithm,
    +    //     String algorithmClassName,
    +    //     String keyGeneratorClassName)
    +    // {
    +    //     provider.addAlgorithm("Mac." + algorithm + "-CMAC", algorithmClassName);
    +    //     provider.addAlgorithm("Alg.Alias.Mac." + algorithm + "CMAC", algorithm + "-CMAC");
    +    //
    +    //     provider.addAlgorithm("KeyGenerator." + algorithm + "-CMAC", keyGeneratorClassName);
    +    //     provider.addAlgorithm("Alg.Alias.KeyGenerator." + algorithm + "CMAC",  algorithm + "-CMAC");
    +    // }
    +    //
         // protected void addGMacAlgorithm(
         //     ConfigurableProvider provider,
         //     String algorithm,
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
    index e2b2efd..c666ac1 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java
    @@ -102,7 +102,7 @@ public final class Twofish
         {
             public PBEWithSHA()
             {
    -            super(new CBCBlockCipher(new TwofishEngine()));
    +            super(new CBCBlockCipher(new TwofishEngine()), PKCS12, SHA1, 256, 16);
             }
         }
     
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
    index 63d6548..296d692 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
    @@ -1,14 +1,32 @@
     package org.bouncycastle.jcajce.provider.symmetric.util;
     
     import java.security.AlgorithmParameterGeneratorSpi;
    +import java.security.AlgorithmParameters;
    +import java.security.NoSuchAlgorithmException;
    +import java.security.NoSuchProviderException;
     import java.security.SecureRandom;
     
    +import org.bouncycastle.jcajce.util.BCJcaJceHelper;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
    +
     public abstract class BaseAlgorithmParameterGenerator
         extends AlgorithmParameterGeneratorSpi
     {
    +    private final JcaJceHelper helper = new BCJcaJceHelper();
    +
         protected SecureRandom  random;
         protected int           strength = 1024;
     
    +    public BaseAlgorithmParameterGenerator()
    +    {
    +    }
    +
    +    protected final AlgorithmParameters createParametersInstance(String algorithm)
    +        throws NoSuchAlgorithmException, NoSuchProviderException
    +    {
    +        return helper.createAlgorithmParameters(algorithm);
    +    }
    +
         protected void engineInit(
             int             strength,
             SecureRandom    random)
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
    index 5b85ef5..fd9b9a9 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
    @@ -1,5 +1,6 @@
     package org.bouncycastle.jcajce.provider.symmetric.util;
     
    +import java.lang.reflect.Constructor;
     import java.lang.reflect.Method;
     import java.nio.ByteBuffer;
     import java.security.AlgorithmParameters;
    @@ -17,6 +18,7 @@ import javax.crypto.IllegalBlockSizeException;
     import javax.crypto.NoSuchPaddingException;
     import javax.crypto.SecretKey;
     import javax.crypto.ShortBufferException;
    +import javax.crypto.interfaces.PBEKey;
     import javax.crypto.spec.IvParameterSpec;
     import javax.crypto.spec.PBEParameterSpec;
     // BEGIN android-removed
    @@ -68,10 +70,15 @@ import org.bouncycastle.crypto.params.ParametersWithRandom;
     import org.bouncycastle.crypto.params.RC2Parameters;
     // BEGIN android-removed
     // import org.bouncycastle.crypto.params.RC5Parameters;
    +// import org.bouncycastle.jcajce.PBKDF1Key;
    +// import org.bouncycastle.jcajce.PBKDF1KeyWithParameters;
    +// END android-removed
    +import org.bouncycastle.jcajce.PKCS12Key;
    +import org.bouncycastle.jcajce.PKCS12KeyWithParameters;
    +// BEGIN android-removed
     // import org.bouncycastle.jcajce.spec.GOST28147ParameterSpec;
     // import org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec;
     // END android-removed
    -import org.bouncycastle.jce.provider.BouncyCastleProvider;
     import org.bouncycastle.util.Strings;
     
     public class BaseBlockCipher
    @@ -89,12 +96,12 @@ public class BaseBlockCipher
                                             // RC2ParameterSpec.class,
                                             // RC5ParameterSpec.class,
                                             // END android-removed
    +                                        gcmSpecClass,
                                             IvParameterSpec.class,
                                             PBEParameterSpec.class,
                                             // BEGIN android-removed
    -                                        // GOST28147ParameterSpec.class,
    +                                        // GOST28147ParameterSpec.class
                                             // END android-removed
    -                                        gcmSpecClass
                                         };
     
         private BlockCipher             baseEngine;
    @@ -103,10 +110,14 @@ public class BaseBlockCipher
         private ParametersWithIV        ivParam;
         private AEADParameters          aeadParams;
     
    +    private int keySizeInBits;
    +    private int scheme = -1;
    +    private int digest;
    +
         private int                     ivLength = 0;
     
         private boolean                 padded;
    -
    +    private boolean                 fixedIv = true;
         private PBEParameterSpec        pbeSpec = null;
         private String                  pbeAlgorithm = null;
     
    @@ -134,6 +145,23 @@ public class BaseBlockCipher
             cipher = new BufferedGenericBlockCipher(engine);
         }
     
    +    protected BaseBlockCipher(
    +        BlockCipher engine,
    +        int scheme,
    +        int digest,
    +        int keySizeInBits,
    +        int ivLength)
    +    {
    +        baseEngine = engine;
    +
    +        this.scheme = scheme;
    +        this.digest = digest;
    +        this.keySizeInBits = keySizeInBits;
    +        this.ivLength = ivLength;
    +
    +        cipher = new BufferedGenericBlockCipher(engine);
    +    }
    +
         protected BaseBlockCipher(
             BlockCipherProvider provider)
         {
    @@ -151,6 +179,17 @@ public class BaseBlockCipher
             cipher = new AEADGenericBlockCipher(engine);
         }
     
    +    protected BaseBlockCipher(
    +        AEADBlockCipher engine,
    +        boolean fixedIv,
    +        int ivLength)
    +    {
    +        this.baseEngine = engine.getUnderlyingCipher();
    +        this.fixedIv = fixedIv;
    +        this.ivLength = ivLength;
    +        this.cipher = new AEADGenericBlockCipher(engine);
    +    }
    +
         protected BaseBlockCipher(
             org.bouncycastle.crypto.BlockCipher engine,
             int ivLength)
    @@ -178,11 +217,11 @@ public class BaseBlockCipher
     
         protected byte[] engineGetIV()
         {
    -        // BEGIN android-added
    -        if (aeadParams != null) {
    +        if (aeadParams != null)
    +        {
                 return aeadParams.getNonce();
             }
    -        // END android-added
    +
             return (ivParam != null) ? ivParam.getIV() : null;
         }
     
    @@ -206,7 +245,7 @@ public class BaseBlockCipher
                 {
                     try
                     {
    -                    engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
    +                    engineParams = createParametersInstance(pbeAlgorithm);
                         engineParams.init(pbeSpec);
                     }
                     catch (Exception e)
    @@ -225,7 +264,7 @@ public class BaseBlockCipher
     
                     try
                     {
    -                    engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
    +                    engineParams = createParametersInstance(name);
                         engineParams.init(ivParam.getIV());
                     }
                     catch (Exception e)
    @@ -237,8 +276,8 @@ public class BaseBlockCipher
                 {
                     try
                     {
    -                    engineParams = AlgorithmParameters.getInstance("GCM", BouncyCastleProvider.PROVIDER_NAME);
    -                    engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize()).getEncoded());
    +                    engineParams = createParametersInstance("GCM");
    +                    engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded());
                     }
                     catch (Exception e)
                     {
    @@ -321,6 +360,7 @@ public class BaseBlockCipher
             //     {
             //         throw new IllegalArgumentException("Warning: SIC-Mode can become a twotime-pad if the blocksize of the cipher is too small. Use a cipher with a block size of at least 128 bits (e.g. AES)");
             //     }
    +        //     fixedIv = false;
             //     cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
             //                 new SICBlockCipher(baseEngine)));
             // }
    @@ -328,6 +368,7 @@ public class BaseBlockCipher
             else if (modeName.startsWith("CTR"))
             {
                 ivLength = baseEngine.getBlockSize();
    +            fixedIv = false;
                 cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
                             new SICBlockCipher(baseEngine)));
             }
    @@ -360,7 +401,9 @@ public class BaseBlockCipher
             // {
             //     if (engineProvider != null)
             //     {
    -        //         // Nonce restricted to max 120 bits over 128 bit block cipher since draft-irtf-cfrg-ocb-03
    +        //         /*
    +        //          * RFC 7253 4.2. Nonce is a string of no more than 120 bits
    +        //          */
             //         ivLength = 15;
             //         cipher = new AEADGenericBlockCipher(new OCBBlockCipher(baseEngine, engineProvider.get()));
             //     }
    @@ -442,6 +485,14 @@ public class BaseBlockCipher
             }
         }
     
    +    // BEGIN android-added
    +    // TODO(27995180): This might need to be removed if we drop support for BCPBE keys without IV
    +    // in PKCS12
    +    private boolean isBCPBEKeyWithoutIV(Key key) {
    +        return (key instanceof BCPBEKey) && !(((BCPBEKey)key).getParam() instanceof ParametersWithIV);
    +    }
    +    // END android-added
    +
         protected void engineInit(
             int                     opmode,
             Key                     key,
    @@ -475,7 +526,99 @@ public class BaseBlockCipher
             //
             // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
             //
    -        if (key instanceof BCPBEKey)
    +        // BEGIN android-changed
    +        // Was: if (scheme == PKCS12 || key instanceof PKCS12Key)
    +        // If the key is a BCPBE one without an IV, ignore the fact that the scheme is PKCS12.
    +        // TODO(27995180): consider whether we want to keep support for these keys and PKCS12.
    +        if ((scheme == PKCS12 || key instanceof PKCS12Key) && !isBCPBEKeyWithoutIV(key))
    +        // END android-changed
    +        {
    +            SecretKey k;
    +            try
    +            {
    +                k = (SecretKey)key;
    +            }
    +            catch (Exception e)
    +            {
    +                throw new InvalidKeyException("PKCS12 requires a SecretKey/PBEKey");
    +            }
    +
    +            if (params instanceof  PBEParameterSpec)
    +            {
    +                pbeSpec = (PBEParameterSpec)params;
    +            }
    +
    +            if (k instanceof PBEKey && pbeSpec == null)
    +            {
    +                // BEGIN android-added
    +                if (((PBEKey)k).getSalt() == null) {
    +                    throw new InvalidAlgorithmParameterException("Parameters for the algorithm are null "
    +                        + "and the PBEKey has null salt");
    +                }
    +                // END android-added
    +                pbeSpec = new PBEParameterSpec(((PBEKey)k).getSalt(), ((PBEKey)k).getIterationCount());
    +            }
    +
    +            if (pbeSpec == null && !(k instanceof PBEKey))
    +            {
    +                throw new InvalidKeyException("Algorithm requires a PBE key");
    +            }
    +            if (key instanceof BCPBEKey)
    +            {
    +                // BEGIN android-changed
    +                // Was:
    +                // if (((BCPBEKey)key).getParam() != null)
    +                // Change taken from:
    +                // https://github.com/bcgit/bc-java/commit/fcba5c782188d772148ba168beae368d06646ee2
    +                // PKCS#12 sets an IV, if we get a key that doesn't have ParametersWithIV we need to forget about the fact
    +                // it's a BCPBEKey
    +                if (((BCPBEKey)key).getParam() != null && ((BCPBEKey)key).getParam() instanceof ParametersWithIV)
    +                // END android-changed
    +                {
    +                    param = ((BCPBEKey)key).getParam();
    +                }
    +                else
    +                {
    +                    // BEGIN android-changed
    +                    // Was: param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
    +                    // TODO(27995180): consider rejecting such keys for PKCS12
    +                    // See above for the android-changed with a TODO for the same bug that makes
    +                    // this code unreachable.
    +                    // END android-changed
    +                    throw new IllegalStateException("Unreachable code");
    +                }
    +            }
    +            else
    +            {
    +                param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
    +            }
    +            if (param instanceof ParametersWithIV)
    +            {
    +                ivParam = (ParametersWithIV)param;
    +            }
    +        }
    +        // BEGIN android-removed
    +        // else if (key instanceof PBKDF1Key)
    +        // {
    +        //     PBKDF1Key k = (PBKDF1Key)key;
    +
    +        //     if (params instanceof PBEParameterSpec)
    +        //     {
    +        //         pbeSpec = (PBEParameterSpec)params;
    +        //     }
    +        //     if (k instanceof PBKDF1KeyWithParameters && pbeSpec == null)
    +        //     {
    +        //         pbeSpec = new PBEParameterSpec(((PBKDF1KeyWithParameters)k).getSalt(), ((PBKDF1KeyWithParameters)k).getIterationCount());
    +        //     }
    +
    +        //     param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS5S1, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
    +        //     if (param instanceof ParametersWithIV)
    +        //     {
    +        //         ivParam = (ParametersWithIV)param;
    +        //     }
    +        // }
    +        // END android-removed
    +        else if (key instanceof BCPBEKey)
             {
                 BCPBEKey k = (BCPBEKey)key;
     
    @@ -490,27 +633,7 @@ public class BaseBlockCipher
     
                 if (k.getParam() != null)
                 {
    -                param = k.getParam();
    -                if (params instanceof IvParameterSpec)
    -                {
    -                    IvParameterSpec iv = (IvParameterSpec)params;
    -
    -                    param = new ParametersWithIV(param, iv.getIV());
    -                }
    -                // BEGIN android-removed
    -                // else if (params instanceof GOST28147ParameterSpec)
    -                // {
    -                //     // need to pick up IV and SBox.
    -                //     GOST28147ParameterSpec    gost28147Param = (GOST28147ParameterSpec)params;
    -                //
    -                //     param = new ParametersWithSBox(param, gost28147Param.getSbox());
    -                //
    -                //     if (gost28147Param.getIV() != null && ivLength != 0)
    -                //     {
    -                //         param = new ParametersWithIV(param, gost28147Param.getIV());
    -                //     }
    -                // }
    -                // END android-removed
    +                param = adjustParameters(params, k.getParam());
                 }
                 else if (params instanceof PBEParameterSpec)
                 {
    @@ -527,33 +650,59 @@ public class BaseBlockCipher
                     ivParam = (ParametersWithIV)param;
                 }
             }
    -        else if (params == null)
    +        else if (key instanceof PBEKey)
    +        {
    +            PBEKey k = (PBEKey)key;
    +            pbeSpec = (PBEParameterSpec)params;
    +            if (k instanceof PKCS12KeyWithParameters && pbeSpec == null)
    +            {
    +                pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount());
    +            }
    +
    +            param = PBE.Util.makePBEParameters(k.getEncoded(), scheme, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
    +            if (param instanceof ParametersWithIV)
    +            {
    +                ivParam = (ParametersWithIV)param;
    +            }
    +        }
    +        // BEGIN android-changed
    +        // Was: else if (!(key instanceof RepeatedSecretKeySpec))
    +        else
    +        // END android-changed
             {
    +            if (scheme == PKCS5S1 || scheme == PKCS5S1_UTF8 || scheme == PKCS5S2 || scheme == PKCS5S2_UTF8)
    +            {
    +                throw new InvalidKeyException("Algorithm requires a PBE key");
    +            }
                 param = new KeyParameter(key.getEncoded());
             }
    -        else if (params instanceof IvParameterSpec)
    +        // BEGIN android-removed
    +        // else
    +        // {
    +        //    param = null;
    +        // }
    +        // END android-removed
    +
    +        if (params instanceof IvParameterSpec)
             {
                 if (ivLength != 0)
                 {
                     IvParameterSpec p = (IvParameterSpec)params;
     
    -                if (p.getIV().length != ivLength && !isAEADModeName(modeName))
    +                if (p.getIV().length != ivLength && !(cipher instanceof AEADGenericBlockCipher) && fixedIv)
                     {
                         throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
                     }
     
    -                // BEGIN android-removed
    -                // if (key instanceof RepeatedSecretKeySpec)
    -                // {
    -                //     param = new ParametersWithIV(null, p.getIV());
    -                //     ivParam = (ParametersWithIV)param;
    -                // }
    -                // else
    -                // END android-removed
    +                if (param instanceof ParametersWithIV)
                     {
    -                    param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
    -                    ivParam = (ParametersWithIV)param;
    +                    param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), p.getIV());
    +                }
    +                else
    +                {
    +                    param = new ParametersWithIV(param, p.getIV());
                     }
    +                ivParam = (ParametersWithIV)param;
                 }
                 else
                 {
    @@ -561,8 +710,6 @@ public class BaseBlockCipher
                     {
                         throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
                     }
    -                
    -                param = new KeyParameter(key.getEncoded());
                 }
             }
             // BEGIN android-removed
    @@ -575,7 +722,14 @@ public class BaseBlockCipher
             //
             //     if (gost28147Param.getIV() != null && ivLength != 0)
             //     {
    -        //         param = new ParametersWithIV(param, gost28147Param.getIV());
    +        //         if (param instanceof ParametersWithIV)
    +        //         {
    +        //             param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), gost28147Param.getIV());
    +        //         }
    +        //         else
    +        //         {
    +        //             param = new ParametersWithIV(param, gost28147Param.getIV());
    +        //         }
             //         ivParam = (ParametersWithIV)param;
             //     }
             // }
    @@ -587,7 +741,14 @@ public class BaseBlockCipher
             //
             //     if (rc2Param.getIV() != null && ivLength != 0)
             //     {
    -        //         param = new ParametersWithIV(param, rc2Param.getIV());
    +        //         if (param instanceof ParametersWithIV)
    +        //         {
    +        //             param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), rc2Param.getIV());
    +        //         }
    +        //         else
    +        //         {
    +        //             param = new ParametersWithIV(param, rc2Param.getIV());
    +        //         }
             //         ivParam = (ParametersWithIV)param;
             //     }
             // }
    @@ -619,7 +780,14 @@ public class BaseBlockCipher
             //     }
             //     if ((rc5Param.getIV() != null) && (ivLength != 0))
             //     {
    -        //         param = new ParametersWithIV(param, rc5Param.getIV());
    +        //         if (param instanceof ParametersWithIV)
    +        //         {
    +        //             param = new ParametersWithIV(((ParametersWithIV)param).getParameters(), rc5Param.getIV());
    +        //         }
    +        //         else
    +        //         {
    +        //             param = new ParametersWithIV(param, rc5Param.getIV());
    +        //         }
             //         ivParam = (ParametersWithIV)param;
             //     }
             // }
    @@ -636,23 +804,23 @@ public class BaseBlockCipher
                     Method tLen = gcmSpecClass.getDeclaredMethod("getTLen", new Class[0]);
                     Method iv= gcmSpecClass.getDeclaredMethod("getIV", new Class[0]);
     
    -                // BEGIN android-removed
    -                // if (key instanceof RepeatedSecretKeySpec)
    -                // {
    -                //     param = aeadParams = new AEADParameters(null, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
    -                // }
    -                // else
    -                // END android-removed
    +                KeyParameter keyParam;
    +                if (param instanceof ParametersWithIV)
                     {
    -                    param = aeadParams = new AEADParameters(new KeyParameter(key.getEncoded()), ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
    +                    keyParam = (KeyParameter)((ParametersWithIV)param).getParameters();
                     }
    +                else
    +                {
    +                    keyParam = (KeyParameter)param;
    +                }
    +                param = aeadParams = new AEADParameters(keyParam, ((Integer)tLen.invoke(params, new Object[0])).intValue(), (byte[])iv.invoke(params, new Object[0]));
                 }
                 catch (Exception e)
                 {
                     throw new InvalidAlgorithmParameterException("Cannot process GCMParameterSpec.");
                 }
             }
    -        else
    +        else if (params != null && !(params instanceof PBEParameterSpec))
             {
                 throw new InvalidAlgorithmParameterException("unknown parameter type.");
             }
    @@ -665,18 +833,35 @@ public class BaseBlockCipher
                 {
                     ivRandom = new SecureRandom();
                 }
    -
                 if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE))
                 {
                     byte[]  iv = new byte[ivLength];
     
    -                ivRandom.nextBytes(iv);
    +                // BEGIN android-changed
    +                // Was: ivRandom.nextBytes(iv);
    +                // TODO(27995180): for such keys, consider whether we want to reject them or
    +                // allow them if the IV is passed in the parameters
    +                if (!isBCPBEKeyWithoutIV(key)) {
    +                    ivRandom.nextBytes(iv);
    +                }
    +                // END android-changed
                     param = new ParametersWithIV(param, iv);
                     ivParam = (ParametersWithIV)param;
                 }
                 else if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
                 {
    -                throw new InvalidAlgorithmParameterException("no IV set when one expected");
    +                // BEGIN android-changed
    +                // Was: throw new InvalidAlgorithmParameterException("no IV set when one expected");
    +                // TODO(27995180): for such keys, consider whether we want to reject them or
    +                // allow them if the IV is passed in the parameters
    +                if (!isBCPBEKeyWithoutIV(key)) {
    +                    throw new InvalidAlgorithmParameterException("no IV set when one expected");
    +                } else {
    +                    // Mimic behaviour in 1.52 by using an IV of 0's
    +                    param = new ParametersWithIV(param, new byte[ivLength]);
    +                    ivParam = (ParametersWithIV)param;
    +                }
    +                // END android-changed
                 }
             }
     
    @@ -701,10 +886,73 @@ public class BaseBlockCipher
                     throw new InvalidParameterException("unknown opmode " + opmode + " passed");
                 }
             }
    -        catch (Exception e)
    +        catch (final Exception e)
             {
    -            throw new InvalidKeyException(e.getMessage());
    +            throw new InvalidKeyException(e.getMessage())
    +            {
    +                public Throwable getCause()
    +                {
    +                    return e;
    +                }
    +            };
    +        }
    +    }
    +
    +    private CipherParameters adjustParameters(AlgorithmParameterSpec params, CipherParameters param)
    +    {
    +        CipherParameters key;
    +
    +        if (param instanceof ParametersWithIV)
    +        {
    +            key = ((ParametersWithIV)param).getParameters();
    +            if (params instanceof IvParameterSpec)
    +            {
    +                IvParameterSpec iv = (IvParameterSpec)params;
    +
    +                ivParam = new ParametersWithIV(key, iv.getIV());
    +                param = ivParam;
    +            }
    +            // BEGIN android-removed
    +            // else if (params instanceof GOST28147ParameterSpec)
    +            // {
    +            //     // need to pick up IV and SBox.
    +            //     GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
    +            //
    +            //     param = new ParametersWithSBox(param, gost28147Param.getSbox());
    +            //
    +            //     if (gost28147Param.getIV() != null && ivLength != 0)
    +            //     {
    +            //         ivParam = new ParametersWithIV(key, gost28147Param.getIV());
    +            //         param = ivParam;
    +            //     }
    +            // }
    +            // END android-removed
             }
    +        else
    +        {
    +            if (params instanceof IvParameterSpec)
    +            {
    +                IvParameterSpec iv = (IvParameterSpec)params;
    +
    +                ivParam = new ParametersWithIV(param, iv.getIV());
    +                param = ivParam;
    +            }
    +            // BEGIN android-removed
    +            // else if (params instanceof GOST28147ParameterSpec)
    +            // {
    +            //     // need to pick up IV and SBox.
    +            //     GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
    +            //
    +            //     param = new ParametersWithSBox(param, gost28147Param.getSbox());
    +            //
    +            //     if (gost28147Param.getIV() != null && ivLength != 0)
    +            //     {
    +            //         param = new ParametersWithIV(param, gost28147Param.getIV());
    +            //     }
    +            // }
    +            // END android-removed
    +        }
    +        return param;
         }
     
         protected void engineInit(
    @@ -817,13 +1065,19 @@ public class BaseBlockCipher
             int     outputOffset)
             throws ShortBufferException
         {
    +        if (outputOffset + cipher.getUpdateOutputSize(inputLen) > output.length)
    +        {
    +            throw new ShortBufferException("output buffer too short for input.");
    +        }
    +
             try
             {
                 return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
             }
             catch (DataLengthException e)
             {
    -            throw new ShortBufferException(e.getMessage());
    +            // should never occur
    +            throw new IllegalStateException(e.toString());
             }
         }
     
    @@ -849,10 +1103,6 @@ public class BaseBlockCipher
             {
                 throw new IllegalBlockSizeException(e.getMessage());
             }
    -        catch (InvalidCipherTextException e)
    -        {
    -            throw new BadPaddingException(e.getMessage());
    -        }
     
             if (len == tmp.length)
             {
    @@ -874,10 +1124,15 @@ public class BaseBlockCipher
             int     outputOffset)
             throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
         {
    -        try
    +        int     len = 0;
    +
    +        if (outputOffset + engineGetOutputSize(inputLen) > output.length)
             {
    -            int     len = 0;
    +            throw new ShortBufferException("output buffer too short for input.");
    +        }
     
    +        try
    +        {
                 if (inputLen != 0)
                 {
                     len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
    @@ -887,16 +1142,12 @@ public class BaseBlockCipher
             }
             catch (OutputLengthException e)
             {
    -            throw new ShortBufferException(e.getMessage());
    +            throw new IllegalBlockSizeException(e.getMessage());
             }
             catch (DataLengthException e)
             {
                 throw new IllegalBlockSizeException(e.getMessage());
             }
    -        catch (InvalidCipherTextException e)
    -        {
    -            throw new BadPaddingException(e.getMessage());
    -        }
         }
     
         private boolean isAEADModeName(
    @@ -935,7 +1186,8 @@ public class BaseBlockCipher
                 throws DataLengthException;
     
             public int doFinal(byte[] out, int outOff)
    -            throws IllegalStateException, InvalidCipherTextException;
    +            throws IllegalStateException,
    +            BadPaddingException;
         }
     
         private static class BufferedGenericBlockCipher
    @@ -1004,15 +1256,48 @@ public class BaseBlockCipher
                 return cipher.processBytes(in, inOff, len, out, outOff);
             }
     
    -        public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
    +        public int doFinal(byte[] out, int outOff) throws IllegalStateException, BadPaddingException
             {
    -            return cipher.doFinal(out, outOff);
    +            try
    +            {
    +                return cipher.doFinal(out, outOff);
    +            }
    +            catch (InvalidCipherTextException e)
    +            {
    +                throw new BadPaddingException(e.getMessage());
    +            }
             }
         }
     
         private static class AEADGenericBlockCipher
             implements GenericBlockCipher
         {
    +        private static final Constructor aeadBadTagConstructor;
    +
    +        static {
    +            Class aeadBadTagClass = lookup("javax.crypto.AEADBadTagException");
    +            if (aeadBadTagClass != null)
    +            {
    +                aeadBadTagConstructor = findExceptionConstructor(aeadBadTagClass);
    +            }
    +            else
    +            {
    +                aeadBadTagConstructor = null;
    +            }
    +        }
    +
    +        private static Constructor findExceptionConstructor(Class clazz)
    +        {
    +            try
    +            {
    +                return clazz.getConstructor(new Class[]{String.class});
    +            }
    +            catch (Exception e)
    +            {
    +                return null;
    +            }
    +        }
    +
             private AEADBlockCipher cipher;
     
             AEADGenericBlockCipher(AEADBlockCipher cipher)
    @@ -1066,9 +1351,33 @@ public class BaseBlockCipher
                 return cipher.processBytes(in, inOff, len, out, outOff);
             }
     
    -        public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
    +        public int doFinal(byte[] out, int outOff) throws IllegalStateException, BadPaddingException
             {
    -            return cipher.doFinal(out, outOff);
    +            try
    +            {
    +                return cipher.doFinal(out, outOff);
    +            }
    +            catch (InvalidCipherTextException e)
    +            {
    +                if (aeadBadTagConstructor != null)
    +                {
    +                    BadPaddingException aeadBadTag = null;
    +                    try
    +                    {
    +                        aeadBadTag = (BadPaddingException)aeadBadTagConstructor
    +                                .newInstance(new Object[]{e.getMessage()});
    +                    }
    +                    catch (Exception i)
    +                    {
    +                        // Shouldn't happen, but fall through to BadPaddingException
    +                    }
    +                    if (aeadBadTag != null)
    +                    {
    +                        throw aeadBadTag;
    +                    }
    +                }
    +                throw new BadPaddingException(e.getMessage());
    +            }
             }
         }
     }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
    index d014972..f607617 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
    @@ -9,6 +9,8 @@ import java.util.Iterator;
     import java.util.Map;
     
     import javax.crypto.MacSpi;
    +import javax.crypto.SecretKey;
    +import javax.crypto.interfaces.PBEKey;
     import javax.crypto.spec.IvParameterSpec;
     import javax.crypto.spec.PBEParameterSpec;
     
    @@ -18,6 +20,9 @@ import org.bouncycastle.crypto.params.KeyParameter;
     import org.bouncycastle.crypto.params.ParametersWithIV;
     // BEGIN android-removed
     // import org.bouncycastle.crypto.params.SkeinParameters;
    +// END android-removed
    +import org.bouncycastle.jcajce.PKCS12Key;
    +// BEGIN android-removed
     // import org.bouncycastle.jcajce.spec.SkeinParameterSpec;
     // END android-removed
     
    @@ -26,7 +31,7 @@ public class BaseMac
     {
         private Mac macEngine;
     
    -    private int                     pbeType = PKCS12;
    +    private int scheme = PKCS12;
         private int                     pbeHash = SHA1;
         private int                     keySize = 160;
     
    @@ -38,12 +43,12 @@ public class BaseMac
     
         protected BaseMac(
             Mac macEngine,
    -        int pbeType,
    +        int scheme,
             int pbeHash,
             int keySize)
         {
             this.macEngine = macEngine;
    -        this.pbeType = pbeType;
    +        this.scheme = scheme;
             this.pbeHash = pbeHash;
             this.keySize = keySize;
         }
    @@ -60,7 +65,54 @@ public class BaseMac
                 throw new InvalidKeyException("key is null");
             }
     
    -        if (key instanceof BCPBEKey)
    +        if (key instanceof PKCS12Key)
    +        {
    +            SecretKey k;
    +            PBEParameterSpec pbeSpec;
    +
    +            try
    +            {
    +                k = (SecretKey)key;
    +            }
    +            catch (Exception e)
    +            {
    +                throw new InvalidKeyException("PKCS12 requires a SecretKey/PBEKey");
    +            }
    +
    +            try
    +            {
    +                pbeSpec = (PBEParameterSpec)params;
    +            }
    +            catch (Exception e)
    +            {
    +                throw new InvalidAlgorithmParameterException("PKCS12 requires a PBEParameterSpec");
    +            }
    +
    +            if (k instanceof PBEKey && pbeSpec == null)
    +            {
    +                pbeSpec = new PBEParameterSpec(((PBEKey)k).getSalt(), ((PBEKey)k).getIterationCount());
    +            }
    +
    +            int digest = SHA1;
    +            int keySize = 160;
    +            // BEGIN android-removed
    +            // if (macEngine.getAlgorithmName().startsWith("GOST"))
    +            // {
    +            //      digest = GOST3411;
    +            //      keySize = 256;
    +            // }
    +            // BEGIN android-changed
    +            // Was: else if (macEngine.getAlgorithmName().startsWith("SHA256"))
    +            if (macEngine.getAlgorithmName().startsWith("SHA256"))
    +            // END android-changed
    +            {
    +                digest = SHA256;
    +                keySize = 256;
    +            }
    +            // TODO: add correct handling for other digests
    +            param = PBE.Util.makePBEMacParameters(k, PKCS12, digest, keySize, pbeSpec);
    +        }
    +        else if (key instanceof BCPBEKey)
             {
                 BCPBEKey k = (BCPBEKey)key;
     
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
    index eb045bf..ea3ac5b 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
    @@ -19,14 +19,13 @@ import javax.crypto.spec.PBEParameterSpec;
     // import javax.crypto.spec.RC5ParameterSpec;
     // END android-removed
     
    -import org.bouncycastle.crypto.BlockCipher;
     import org.bouncycastle.crypto.CipherParameters;
     import org.bouncycastle.crypto.DataLengthException;
    -import org.bouncycastle.crypto.StreamBlockCipher;
     import org.bouncycastle.crypto.StreamCipher;
     import org.bouncycastle.crypto.params.KeyParameter;
     import org.bouncycastle.crypto.params.ParametersWithIV;
    -import org.bouncycastle.jce.provider.BouncyCastleProvider;
    +import org.bouncycastle.jcajce.PKCS12Key;
    +import org.bouncycastle.jcajce.PKCS12KeyWithParameters;
     
     public class BaseStreamCipher
         extends BaseWrapCipher
    @@ -46,6 +45,8 @@ public class BaseStreamCipher
                                         };
     
         private StreamCipher       cipher;
    +    private int keySizeInBits;
    +    private int digest;
         private ParametersWithIV   ivParam;
     
         private int                     ivLength = 0;
    @@ -57,17 +58,19 @@ public class BaseStreamCipher
             StreamCipher engine,
             int ivLength)
         {
    -        cipher = engine;
    -        this.ivLength = ivLength;
    +        this(engine, ivLength, -1, -1);
         }
     
         protected BaseStreamCipher(
    -        BlockCipher engine,
    -        int ivLength)
    +        StreamCipher engine,
    +        int ivLength,
    +        int keySizeInBits,
    +        int digest)
         {
    +        cipher = engine;
             this.ivLength = ivLength;
    -
    -        cipher = new StreamBlockCipher(engine);
    +        this.keySizeInBits = keySizeInBits;
    +        this.digest = digest;
         }
     
         protected int engineGetBlockSize()
    @@ -100,7 +103,7 @@ public class BaseStreamCipher
                 {
                     try
                     {
    -                    AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
    +                    AlgorithmParameters engineParams = createParametersInstance(pbeAlgorithm);
                         engineParams.init(pbeSpec);
     
                         return engineParams;
    @@ -162,7 +165,18 @@ public class BaseStreamCipher
                 throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption.");
             }
     
    -        if (key instanceof BCPBEKey)
    +        if (key instanceof PKCS12Key)
    +        {
    +            PKCS12Key k = (PKCS12Key)key;
    +            pbeSpec = (PBEParameterSpec)params;
    +            if (k instanceof PKCS12KeyWithParameters && pbeSpec == null)
    +            {
    +                pbeSpec = new PBEParameterSpec(((PKCS12KeyWithParameters)k).getSalt(), ((PKCS12KeyWithParameters)k).getIterationCount());
    +            }
    +
    +            param = PBE.Util.makePBEParameters(k.getEncoded(), PKCS12, digest, keySizeInBits, ivLength * 8, pbeSpec, cipher.getAlgorithmName());
    +        }
    +        else if (key instanceof BCPBEKey)
             {
                 BCPBEKey k = (BCPBEKey)key;
     
    @@ -197,6 +211,10 @@ public class BaseStreamCipher
             }
             else if (params == null)
             {
    +            if (digest > 0)
    +            {
    +                throw new InvalidKeyException("Algorithm requires a PBE key");
    +            }
                 param = new KeyParameter(key.getEncoded());
             }
             else if (params instanceof IvParameterSpec)
    @@ -324,15 +342,21 @@ public class BaseStreamCipher
             int     outputOffset) 
             throws ShortBufferException 
         {
    +        if (outputOffset + inputLen > output.length)
    +        {
    +            throw new ShortBufferException("output buffer too short for input.");
    +        }
    +
             try
             {
    -        cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
    +            cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
     
    -        return inputLen;
    +            return inputLen;
             }
             catch (DataLengthException e)
             {
    -            throw new ShortBufferException(e.getMessage());
    +            // should never happen
    +            throw new IllegalStateException(e.getMessage());
             }
         }
     
    @@ -360,8 +384,14 @@ public class BaseStreamCipher
             int     inputOffset,
             int     inputLen,
             byte[]  output,
    -        int     outputOffset) 
    +        int     outputOffset)
    +        throws ShortBufferException
         {
    +        if (outputOffset + inputLen > output.length)
    +        {
    +            throw new ShortBufferException("output buffer too short for input.");
    +        }
    +
             if (inputLen != 0)
             {
                 cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
    index 98e5771..ece0d14 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
    @@ -34,7 +34,11 @@ import org.bouncycastle.crypto.InvalidCipherTextException;
     import org.bouncycastle.crypto.Wrapper;
     import org.bouncycastle.crypto.params.KeyParameter;
     import org.bouncycastle.crypto.params.ParametersWithIV;
    +import org.bouncycastle.crypto.params.ParametersWithRandom;
    +import org.bouncycastle.jcajce.util.BCJcaJceHelper;
    +import org.bouncycastle.jcajce.util.JcaJceHelper;
     import org.bouncycastle.jce.provider.BouncyCastleProvider;
    +import org.bouncycastle.util.Arrays;
     
     public abstract class BaseWrapCipher
         extends CipherSpi
    @@ -65,6 +69,8 @@ public abstract class BaseWrapCipher
         private int                       ivSize;
         private byte[]                    iv;
     
    +    private final JcaJceHelper helper = new BCJcaJceHelper();
    +
         protected BaseWrapCipher()
         {
         }
    @@ -90,7 +96,7 @@ public abstract class BaseWrapCipher
     
         protected byte[] engineGetIV()
         {
    -        return (byte[])iv.clone();
    +        return Arrays.clone(iv);
         }
     
         protected int engineGetKeySize(
    @@ -110,6 +116,12 @@ public abstract class BaseWrapCipher
             return null;
         }
     
    +    protected final AlgorithmParameters createParametersInstance(String algorithm)
    +        throws NoSuchAlgorithmException, NoSuchProviderException
    +    {
    +        return helper.createAlgorithmParameters(algorithm);
    +    }
    +
         protected void engineSetMode(
             String  mode)
             throws NoSuchAlgorithmException
    @@ -168,6 +180,11 @@ public abstract class BaseWrapCipher
                 param = new ParametersWithIV(param, iv);
             }
     
    +        if (random != null)
    +        {
    +            param = new ParametersWithRandom(param, random);
    +        }
    +
             switch (opmode)
             {
             case Cipher.WRAP_MODE:
    @@ -368,7 +385,7 @@ public abstract class BaseWrapCipher
             {
                 try
                 {
    -                KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
    +                KeyFactory kf = helper.createKeyFactory(wrappedKeyAlgorithm);
     
                     if (wrappedKeyType == Cipher.PUBLIC_KEY)
                     {
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
    index c39a2d3..8fead80 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
    @@ -1,7 +1,9 @@
     package org.bouncycastle.jcajce.provider.symmetric.util;
     
    +import java.security.InvalidAlgorithmParameterException;
     import java.security.spec.AlgorithmParameterSpec;
     
    +import javax.crypto.SecretKey;
     import javax.crypto.spec.PBEKeySpec;
     import javax.crypto.spec.PBEParameterSpec;
     
    @@ -175,6 +177,70 @@ public interface PBE
                 return generator;
             }
     
    +        /**
    +         * construct a key and iv (if necessary) suitable for use with a
    +         * Cipher.
    +         */
    +        public static CipherParameters makePBEParameters(
    +            byte[] pbeKey,
    +            int scheme,
    +            int digest,
    +            int keySize,
    +            int ivSize,
    +            AlgorithmParameterSpec spec,
    +            String targetAlgorithm)
    +            throws InvalidAlgorithmParameterException
    +        {
    +            if ((spec == null) || !(spec instanceof PBEParameterSpec))
    +            {
    +                throw new InvalidAlgorithmParameterException("Need a PBEParameter spec with a PBE key.");
    +            }
    +
    +            PBEParameterSpec        pbeParam = (PBEParameterSpec)spec;
    +            PBEParametersGenerator  generator = makePBEGenerator(scheme, digest);
    +            byte[]                  key = pbeKey;
    +            CipherParameters        param;
    +
    +//            if (pbeKey.shouldTryWrongPKCS12())
    +//            {
    +//                key = new byte[2];
    +//            }
    +
    +            generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
    +
    +            if (ivSize != 0)
    +            {
    +                param = generator.generateDerivedParameters(keySize, ivSize);
    +            }
    +            else
    +            {
    +                param = generator.generateDerivedParameters(keySize);
    +            }
    +
    +            if (targetAlgorithm.startsWith("DES"))
    +            {
    +                if (param instanceof ParametersWithIV)
    +                {
    +                    KeyParameter    kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
    +
    +                    DESParameters.setOddParity(kParam.getKey());
    +                }
    +                else
    +                {
    +                    KeyParameter    kParam = (KeyParameter)param;
    +
    +                    DESParameters.setOddParity(kParam.getKey());
    +                }
    +            }
    +
    +            for (int i = 0; i != key.length; i++)
    +            {
    +                key[i] = 0;
    +            }
    +
    +            return param;
    +        }
    +
             /**
              * construct a key and iv (if necessary) suitable for use with a 
              * Cipher.
    @@ -252,11 +318,6 @@ public interface PBE
                 PBEParametersGenerator  generator = makePBEGenerator(pbeKey.getType(), pbeKey.getDigest());
                 byte[]                  key = pbeKey.getEncoded();
                 CipherParameters        param;
    -    
    -            if (pbeKey.shouldTryWrongPKCS12())
    -            {
    -                key = new byte[2];
    -            }
                 
                 generator.init(key, pbeParam.getSalt(), pbeParam.getIterationCount());
     
    @@ -269,7 +330,36 @@ public interface PBE
     
                 return param;
             }
    -    
    +
    +        /**
    +         * generate a PBE based key suitable for a MAC algorithm, the
    +         * key size is chosen according the MAC size, or the hashing algorithm,
    +         * whichever is greater.
    +         */
    +        public static CipherParameters makePBEMacParameters(
    +            PBEKeySpec keySpec,
    +            int type,
    +            int hash,
    +            int keySize)
    +        {
    +            PBEParametersGenerator  generator = makePBEGenerator(type, hash);
    +            byte[]                  key;
    +            CipherParameters        param;
    +
    +            key = convertPassword(type, keySpec);
    +
    +            generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
    +
    +            param = generator.generateDerivedMacParameters(keySize);
    +
    +            for (int i = 0; i != key.length; i++)
    +            {
    +                key[i] = 0;
    +            }
    +
    +            return param;
    +        }
    +
             /**
              * construct a key and iv (if necessary) suitable for use with a 
              * Cipher.
    @@ -306,31 +396,30 @@ public interface PBE
                 return param;
             }
     
    -
             /**
              * generate a PBE based key suitable for a MAC algorithm, the
              * key size is chosen according the MAC size, or the hashing algorithm,
              * whichever is greater.
              */
             public static CipherParameters makePBEMacParameters(
    -            PBEKeySpec keySpec,
    +            SecretKey key,
                 int type,
                 int hash,
    -            int keySize)
    +            int keySize,
    +            PBEParameterSpec pbeSpec)
             {
                 PBEParametersGenerator  generator = makePBEGenerator(type, hash);
    -            byte[]                  key;
                 CipherParameters        param;
         
    -            key = convertPassword(type, keySpec);
    +            byte[] keyBytes = key.getEncoded();
                 
    -            generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
    +            generator.init(key.getEncoded(), pbeSpec.getSalt(), pbeSpec.getIterationCount());
     
                 param = generator.generateDerivedMacParameters(keySize);
     
    -            for (int i = 0; i != key.length; i++)
    +            for (int i = 0; i != keyBytes.length; i++)
                 {
    -                key[i] = 0;
    +                keyBytes[i] = 0;
                 }
         
                 return param;
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
    index 19ca6b1..ce8bb36 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
    @@ -17,6 +17,7 @@ import org.bouncycastle.crypto.Digest;
     // import org.bouncycastle.crypto.digests.SHA256Digest;
     // import org.bouncycastle.crypto.digests.SHA384Digest;
     // import org.bouncycastle.crypto.digests.SHA512Digest;
    +// import org.bouncycastle.crypto.digests.SHA512tDigest;
     // END android-removed
     // BEGIN android-added
     import org.bouncycastle.crypto.digests.AndroidDigestFactory;
    @@ -31,7 +32,11 @@ public class DigestFactory
         private static Set sha256 = new HashSet();
         private static Set sha384 = new HashSet();
         private static Set sha512 = new HashSet();
    -    
    +    // BEGIN android-removed
    +    // private static Set sha512_224 = new HashSet();
    +    // private static Set sha512_256 = new HashSet();
    +    // END android-removed
    +
         private static Map oids = new HashMap();
         
         static
    @@ -59,6 +64,16 @@ public class DigestFactory
             sha512.add("SHA-512");
             sha512.add(NISTObjectIdentifiers.id_sha512.getId()); 
     
    +        // BEGIN android-removed
    +        // sha512_224.add("SHA512(224)");
    +        // sha512_224.add("SHA-512(224)");
    +        // sha512_224.add(NISTObjectIdentifiers.id_sha512_224.getId());
    +
    +        // sha512_256.add("SHA512(256)");
    +        // sha512_256.add("SHA-512(256)");
    +        // sha512_256.add(NISTObjectIdentifiers.id_sha512_256.getId());
    +        // END android-removed
    +
             oids.put("MD5", PKCSObjectIdentifiers.md5);
             oids.put(PKCSObjectIdentifiers.md5.getId(), PKCSObjectIdentifiers.md5);
             
    @@ -80,7 +95,15 @@ public class DigestFactory
             
             oids.put("SHA512", NISTObjectIdentifiers.id_sha512);
             oids.put("SHA-512", NISTObjectIdentifiers.id_sha512);
    -        oids.put(NISTObjectIdentifiers.id_sha512.getId(), NISTObjectIdentifiers.id_sha512); 
    +        oids.put(NISTObjectIdentifiers.id_sha512.getId(), NISTObjectIdentifiers.id_sha512);
    +
    +        oids.put("SHA512(224)", NISTObjectIdentifiers.id_sha512_224);
    +        oids.put("SHA-512(224)", NISTObjectIdentifiers.id_sha512_224);
    +        oids.put(NISTObjectIdentifiers.id_sha512_224.getId(), NISTObjectIdentifiers.id_sha512_224);
    +
    +        oids.put("SHA512(256)", NISTObjectIdentifiers.id_sha512_256);
    +        oids.put("SHA-512(256)", NISTObjectIdentifiers.id_sha512_256);
    +        oids.put(NISTObjectIdentifiers.id_sha512_256.getId(), NISTObjectIdentifiers.id_sha512_256);
         }
         
         public static Digest getDigest(
    @@ -124,7 +147,17 @@ public class DigestFactory
                 return AndroidDigestFactory.getSHA512();
                 // END android-changed
             }
    -        
    +        // BEGIN android-removed
    +        // if (sha512_224.contains(digestName))
    +        // {
    +        //     return new SHA512tDigest(224);
    +        // }
    +        // if (sha512_256.contains(digestName))
    +        // {
    +        //     return new SHA512tDigest(256);
    +        // }
    +        // END android-removed
    +
             return null;
         }
         
    @@ -137,6 +170,10 @@ public class DigestFactory
                 || (sha256.contains(digest1) && sha256.contains(digest2))
                 || (sha384.contains(digest1) && sha384.contains(digest2))
                 || (sha512.contains(digest1) && sha512.contains(digest2))
    +            // BEGIN android-removed
    +            // || (sha512_224.contains(digest1) && sha512_224.contains(digest2))
    +            // || (sha512_256.contains(digest1) && sha512_256.contains(digest2))
    +            // END android-removed
                 || (md5.contains(digest1) && md5.contains(digest2));
         }
         
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
    index 214a5eb..df0c145 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/spec/PBKDF2KeySpec.java
    @@ -4,11 +4,23 @@ import javax.crypto.spec.PBEKeySpec;
     
     import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
     
    +/**
    + * Extension of PBEKeySpec which takes into account the PRF algorithm setting available in PKCS#5 PBKDF2.
    + */
     public class PBKDF2KeySpec
         extends PBEKeySpec
     {
         private AlgorithmIdentifier prf;
     
    +    /**
    +     * Base constructor.
    +     *
    +     * @param password password to use as the seed of the PBE key generator.
    +     * @param salt salt to use in the generator,
    +     * @param iterationCount iteration count to use in the generator.
    +     * @param keySize size of the key to be generated (in bits).
    +     * @param prf identifier and parameters for the PRF algorithm to use.
    +     */
         public PBKDF2KeySpec(char[] password, byte[] salt, int iterationCount, int keySize, AlgorithmIdentifier prf)
         {
             super(password, salt, iterationCount, keySize);
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpec.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpec.java
    new file mode 100644
    index 0000000..d813531
    --- /dev/null
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpec.java
    @@ -0,0 +1,21 @@
    +package org.bouncycastle.jcajce.spec;
    +
    +import java.security.spec.AlgorithmParameterSpec;
    +
    +import org.bouncycastle.util.Arrays;
    +
    +public class UserKeyingMaterialSpec
    +    implements AlgorithmParameterSpec
    +{
    +    private final byte[] userKeyingMaterial;
    +
    +    public UserKeyingMaterialSpec(byte[] userKeyingMaterial)
    +    {
    +        this.userKeyingMaterial = Arrays.clone(userKeyingMaterial);
    +    }
    +
    +    public byte[] getUserKeyingMaterial()
    +    {
    +        return Arrays.clone(userKeyingMaterial);
    +    }
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceUtils.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java
    similarity index 68%
    rename from bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceUtils.java
    rename to bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java
    index d7677f3..4a1a92a 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceUtils.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/AlgorithmParametersUtils.java
    @@ -1,4 +1,7 @@
    -package org.bouncycastle.jcajce;
    +/***************************************************************/
    +/******    DO NOT EDIT THIS CLASS bc-java SOURCE FILE     ******/
    +/***************************************************************/
    +package org.bouncycastle.jcajce.util;
     
     import java.io.IOException;
     import java.security.AlgorithmParameters;
    @@ -6,9 +9,14 @@ import java.security.AlgorithmParameters;
     import org.bouncycastle.asn1.ASN1Encodable;
     import org.bouncycastle.asn1.ASN1Primitive;
     
    -public class JcaJceUtils
    +/**
    + * General JCA/JCE utility methods.
    + */
    +public class AlgorithmParametersUtils
     {
    -    private JcaJceUtils()
    +
    +
    +    private AlgorithmParametersUtils()
         {
     
         }
    @@ -37,6 +45,13 @@ public class JcaJceUtils
             return asn1Params;
         }
     
    +    /**
    +     * Load an AlgorithmParameters object with the passed in ASN.1 encodable - if possible.
    +     *
    +     * @param params the AlgorithmParameters object to be initialised.
    +     * @param sParams the ASN.1 encodable to initialise params with.
    +     * @throws IOException if the parameters cannot be initialised.
    +     */
         public static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams)
             throws IOException
         {
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
    new file mode 100644
    index 0000000..4008761
    --- /dev/null
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/BCJcaJceHelper.java
    @@ -0,0 +1,30 @@
    +package org.bouncycastle.jcajce.util;
    +
    +import java.security.Provider;
    +import java.security.Security;
    +
    +import org.bouncycastle.jce.provider.BouncyCastleProvider;
    +
    +/**
    + * A JCA/JCE helper that refers to the BC provider for all it's needs.
    + */
    +public class BCJcaJceHelper
    +    extends ProviderJcaJceHelper
    +{
    +    private static Provider getBouncyCastleProvider()
    +    {
    +        if (Security.getProvider("BC") != null)
    +        {
    +            return Security.getProvider("BC");
    +        }
    +        else
    +        {
    +            return new BouncyCastleProvider();
    +        }
    +    }
    +
    +    public BCJcaJceHelper()
    +    {
    +        super(getBouncyCastleProvider());
    +    }
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java
    similarity index 92%
    rename from bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java
    rename to bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java
    index 6a7b4e2..27ca55a 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java
    @@ -1,4 +1,4 @@
    -package org.bouncycastle.jcajce;
    +package org.bouncycastle.jcajce.util;
     
     import java.security.AlgorithmParameterGenerator;
     import java.security.AlgorithmParameters;
    @@ -17,6 +17,10 @@ import javax.crypto.Mac;
     import javax.crypto.NoSuchPaddingException;
     import javax.crypto.SecretKeyFactory;
     
    +/**
    + * {@link JcaJceHelper} that obtains all algorithms using the default JCA/JCE mechanism (i.e.
    + * without specifying a provider).
    + */
     public class DefaultJcaJceHelper
         implements JcaJceHelper
     {
    @@ -88,7 +92,7 @@ public class DefaultJcaJceHelper
         }
     
         public CertificateFactory createCertificateFactory(String algorithm)
    -        throws NoSuchAlgorithmException, CertificateException
    +        throws CertificateException
         {
             return CertificateFactory.getInstance(algorithm);
         }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java
    similarity index 92%
    rename from bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java
    rename to bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java
    index 645b440..7a78193 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceHelper.java
    @@ -1,4 +1,4 @@
    -package org.bouncycastle.jcajce;
    +package org.bouncycastle.jcajce.util;
     
     import java.security.AlgorithmParameterGenerator;
     import java.security.AlgorithmParameters;
    @@ -18,6 +18,9 @@ import javax.crypto.Mac;
     import javax.crypto.NoSuchPaddingException;
     import javax.crypto.SecretKeyFactory;
     
    +/**
    + * Factory interface for instantiating JCA/JCE primitives.
    + */
     public interface JcaJceHelper
     {
         Cipher createCipher(
    @@ -55,5 +58,5 @@ public interface JcaJceHelper
             throws NoSuchAlgorithmException, NoSuchProviderException;
     
         CertificateFactory createCertificateFactory(String algorithm)
    -        throws NoSuchAlgorithmException, NoSuchProviderException, CertificateException;
    +        throws NoSuchProviderException, CertificateException;
     }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceUtils.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceUtils.java
    new file mode 100644
    index 0000000..5148601
    --- /dev/null
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/JcaJceUtils.java
    @@ -0,0 +1,133 @@
    +package org.bouncycastle.jcajce.util;
    +
    +import java.io.IOException;
    +import java.security.AlgorithmParameters;
    +
    +import org.bouncycastle.asn1.ASN1Encodable;
    +import org.bouncycastle.asn1.ASN1ObjectIdentifier;
    +import org.bouncycastle.asn1.ASN1Primitive;
    +// BEGIN android-removed
    +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
    +// END android-removed
    +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
    +
    +/**
    + * General JCA/JCE utility methods.
    + */
    +public class JcaJceUtils
    +{
    +    private JcaJceUtils()
    +    {
    +
    +    }
    +
    +    /**
    +     * Extract an ASN.1 encodable from an AlgorithmParameters object.
    +     *
    +     * @param params the object to get the encoding used to create the return value.
    +     * @return an ASN.1 object representing the primitives making up the params parameter.
    +     * @throws IOException if an encoding cannot be extracted.
    +     * @deprecated use AlgorithmParametersUtils.extractParameters(AlgorithmParameters params)
    +     */
    +    public static ASN1Encodable extractParameters(AlgorithmParameters params)
    +        throws IOException
    +    {
    +        // we try ASN.1 explicitly first just in case and then role back to the default.
    +        ASN1Encodable asn1Params;
    +        try
    +        {
    +            asn1Params = ASN1Primitive.fromByteArray(params.getEncoded("ASN.1"));
    +        }
    +        catch (Exception ex)
    +        {
    +            asn1Params = ASN1Primitive.fromByteArray(params.getEncoded());
    +        }
    +
    +        return asn1Params;
    +    }
    +
    +    /**
    +     * Load an AlgorithmParameters object with the passed in ASN.1 encodable - if possible.
    +     *
    +     * @param params the AlgorithmParameters object to be initialised.
    +     * @param sParams the ASN.1 encodable to initialise params with.
    +     * @throws IOException if the parameters cannot be initialised.
    +     * @deprecated use AlgorithmParametersUtils.loadParameters(AlgorithmParameters params, ASN1Encodable sParams)
    +     */
    +    public static void loadParameters(AlgorithmParameters params, ASN1Encodable sParams)
    +        throws IOException
    +    {
    +        // we try ASN.1 explicitly first just in case and then role back to the default.
    +        try
    +        {
    +            params.init(sParams.toASN1Primitive().getEncoded(), "ASN.1");
    +        }
    +        catch (Exception ex)
    +        {
    +            params.init(sParams.toASN1Primitive().getEncoded());
    +        }
    +    }
    +
    +    /**
    +     * Attempt to find a standard JCA name for the digest represented by the past in OID.
    +     *
    +     * @param digestAlgOID the OID of the digest algorithm of interest.
    +     * @return a string representing the standard name - the OID as a string if none available.
    +     * @deprecated use MessageDigestUtils,getDigestName()
    +     */
    +    public static String getDigestAlgName(
    +        ASN1ObjectIdentifier digestAlgOID)
    +    {
    +        if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
    +        {
    +            return "MD5";
    +        }
    +        else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
    +        {
    +            return "SHA1";
    +        }
    +        else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
    +        {
    +            return "SHA224";
    +        }
    +        else if (NISTObjectIdentifiers.id_sha256.equals(digestAlgOID))
    +        {
    +            return "SHA256";
    +        }
    +        else if (NISTObjectIdentifiers.id_sha384.equals(digestAlgOID))
    +        {
    +            return "SHA384";
    +        }
    +        else if (NISTObjectIdentifiers.id_sha512.equals(digestAlgOID))
    +        {
    +            return "SHA512";
    +        }
    +        // BEGIN android-removed
    +        // else if (TeleTrusTObjectIdentifiers.ripemd128.equals(digestAlgOID))
    +        // {
    +        //     return "RIPEMD128";
    +        // }
    +        // else if (TeleTrusTObjectIdentifiers.ripemd160.equals(digestAlgOID))
    +        // {
    +        //     return "RIPEMD160";
    +        // }
    +        // else if (TeleTrusTObjectIdentifiers.ripemd256.equals(digestAlgOID))
    +        // {
    +        //     return "RIPEMD256";
    +        // }
    +        // else if (CryptoProObjectIdentifiers.gostR3411.equals(digestAlgOID))
    +        // {
    +        //     return "GOST3411";
    +        // }
    +        // END android-removed
    +        else
    +        {
    +            return digestAlgOID.getId();
    +        }
    +    }
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
    new file mode 100644
    index 0000000..80ce603
    --- /dev/null
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
    @@ -0,0 +1,63 @@
    +package org.bouncycastle.jcajce.util;
    +
    +import java.util.HashMap;
    +import java.util.Map;
    +
    +import org.bouncycastle.asn1.ASN1ObjectIdentifier;
    +// BEGIN android-removed
    +// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
    +// import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
    +// import org.bouncycastle.asn1.iso.ISOIECObjectIdentifiers;
    +// END android-removed
    +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
    +
    +public class MessageDigestUtils
    +{
    +    private static Map digestOidMap = new HashMap();
    +
    +    static
    +    {
    +        // BEGIN android-removed
    +        // digestOidMap.put(PKCSObjectIdentifiers.md2, "MD2");
    +        // digestOidMap.put(PKCSObjectIdentifiers.md4, "MD4");
    +        // END android-removed
    +        digestOidMap.put(PKCSObjectIdentifiers.md5, "MD5");
    +        digestOidMap.put(OIWObjectIdentifiers.idSHA1, "SHA-1");
    +        digestOidMap.put(NISTObjectIdentifiers.id_sha224, "SHA-224");
    +        digestOidMap.put(NISTObjectIdentifiers.id_sha256, "SHA-256");
    +        digestOidMap.put(NISTObjectIdentifiers.id_sha384, "SHA-384");
    +        digestOidMap.put(NISTObjectIdentifiers.id_sha512, "SHA-512");
    +        // BEGIN android-removed
    +        // digestOidMap.put(TeleTrusTObjectIdentifiers.ripemd128, "RIPEMD-128");
    +        // digestOidMap.put(TeleTrusTObjectIdentifiers.ripemd160, "RIPEMD-160");
    +        // digestOidMap.put(TeleTrusTObjectIdentifiers.ripemd256, "RIPEMD-128");
    +        // digestOidMap.put(ISOIECObjectIdentifiers.ripemd128, "RIPEMD-128");
    +        // digestOidMap.put(ISOIECObjectIdentifiers.ripemd160, "RIPEMD-160");
    +        // digestOidMap.put(CryptoProObjectIdentifiers.gostR3411, "GOST3411");
    +        // digestOidMap.put(GNUObjectIdentifiers.Tiger_192, "Tiger");
    +        // digestOidMap.put(ISOIECObjectIdentifiers.whirlpool, "Whirlpool");
    +        // END android-removed
    +    }
    +
    +    /**
    +     * Attempt to find a standard JCA name for the digest represented by the passed in OID.
    +     *
    +     * @param digestAlgOID the OID of the digest algorithm of interest.
    +     * @return a string representing the standard name - the OID as a string if none available.
    +     */
    +    public static String getDigestName(ASN1ObjectIdentifier digestAlgOID)
    +    {
    +        String name = (String)digestOidMap.get(digestAlgOID);  // for pre 1.5 JDK
    +        if (name != null)
    +        {
    +            return name;
    +        }
    +
    +        return digestAlgOID.getId();
    +    }
    +}
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java
    similarity index 94%
    rename from bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java
    rename to bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java
    index 03f1006..280539d 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java
    @@ -1,4 +1,4 @@
    -package org.bouncycastle.jcajce;
    +package org.bouncycastle.jcajce.util;
     
     import java.security.AlgorithmParameterGenerator;
     import java.security.AlgorithmParameters;
    @@ -18,6 +18,9 @@ import javax.crypto.Mac;
     import javax.crypto.NoSuchPaddingException;
     import javax.crypto.SecretKeyFactory;
     
    +/**
    + * {@link JcaJceHelper} that obtains all algorithms using a specific named provider.
    + */
     public class NamedJcaJceHelper
         implements JcaJceHelper
     {
    @@ -96,7 +99,7 @@ public class NamedJcaJceHelper
         }
     
         public CertificateFactory createCertificateFactory(String algorithm)
    -        throws NoSuchAlgorithmException, CertificateException, NoSuchProviderException
    +        throws CertificateException, NoSuchProviderException
         {
             return CertificateFactory.getInstance(algorithm, providerName);
         }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java
    similarity index 94%
    rename from bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java
    rename to bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java
    index 90a8f68..fb4b9a7 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java
    @@ -1,4 +1,4 @@
    -package org.bouncycastle.jcajce;
    +package org.bouncycastle.jcajce.util;
     
     import java.security.AlgorithmParameterGenerator;
     import java.security.AlgorithmParameters;
    @@ -18,6 +18,9 @@ import javax.crypto.Mac;
     import javax.crypto.NoSuchPaddingException;
     import javax.crypto.SecretKeyFactory;
     
    +/**
    + * {@link JcaJceHelper} that obtains all algorithms from a specific {@link Provider} instance.
    + */
     public class ProviderJcaJceHelper
         implements JcaJceHelper
     {
    @@ -96,7 +99,7 @@ public class ProviderJcaJceHelper
         }
     
         public CertificateFactory createCertificateFactory(String algorithm)
    -        throws NoSuchAlgorithmException, CertificateException
    +        throws CertificateException
         {
             return CertificateFactory.getInstance(algorithm, provider);
         }
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
    index 941f476..5ad207a 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
    @@ -21,19 +21,35 @@ public class ECNamedCurveTable
         public static ECNamedCurveParameterSpec getParameterSpec(
             String  name)
         {
    -        X9ECParameters  ecP = org.bouncycastle.asn1.x9.ECNamedCurveTable.getByName(name);
    +        X9ECParameters  ecP = org.bouncycastle.crypto.ec.CustomNamedCurves.getByName(name);
             if (ecP == null)
             {
                 try
                 {
    -                ecP = org.bouncycastle.asn1.x9.ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(name));
    +                ecP = org.bouncycastle.crypto.ec.CustomNamedCurves.getByOID(new ASN1ObjectIdentifier(name));
                 }
                 catch (IllegalArgumentException e)
                 {
                     // ignore - not an oid
                 }
    +
    +            if (ecP == null)
    +            {
    +                ecP = org.bouncycastle.asn1.x9.ECNamedCurveTable.getByName(name);
    +                if (ecP == null)
    +                {
    +                    try
    +                    {
    +                        ecP = org.bouncycastle.asn1.x9.ECNamedCurveTable.getByOID(new ASN1ObjectIdentifier(name));
    +                    }
    +                    catch (IllegalArgumentException e)
    +                    {
    +                        // ignore - not an oid
    +                    }
    +                }
    +            }
             }
    -        
    +
             if (ecP == null)
             {
                 return null;
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
    index 4c34850..0c41c88 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
    @@ -24,12 +24,12 @@ import org.bouncycastle.asn1.ASN1Encodable;
     import org.bouncycastle.asn1.ASN1Encoding;
     import org.bouncycastle.asn1.ASN1InputStream;
     import org.bouncycastle.asn1.ASN1Integer;
    +import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     import org.bouncycastle.asn1.ASN1Primitive;
     import org.bouncycastle.asn1.ASN1Sequence;
     import org.bouncycastle.asn1.ASN1Set;
     import org.bouncycastle.asn1.DERBitString;
     import org.bouncycastle.asn1.DERNull;
    -import org.bouncycastle.asn1.DERObjectIdentifier;
     // BEGIN android-removed
     // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
     // END android-removed
    @@ -87,14 +87,14 @@ public class PKCS10CertificationRequest
         {
             // BEGIN android-removed
             // Dropping MD2
    -        // algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
    -        // algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
    +        // algorithms.put("MD2WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"));
    +        // algorithms.put("MD2WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"));
             // END android-removed
    -        algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
    -        algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
    -        algorithms.put("RSAWITHMD5", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
    -        algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
    -        algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
    +        algorithms.put("MD5WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"));
    +        algorithms.put("MD5WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"));
    +        algorithms.put("RSAWITHMD5", new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"));
    +        algorithms.put("SHA1WITHRSAENCRYPTION", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"));
    +        algorithms.put("SHA1WITHRSA", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"));
             algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
             algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
             algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
    @@ -108,7 +108,7 @@ public class PKCS10CertificationRequest
             algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
             algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
             algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
    -        algorithms.put("RSAWITHSHA1", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
    +        algorithms.put("RSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"));
             // BEGIN android-removed
             // algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
             // algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
    @@ -117,8 +117,8 @@ public class PKCS10CertificationRequest
             // algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
             // algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
             // END android-removed
    -        algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
    -        algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
    +        algorithms.put("SHA1WITHDSA", new ASN1ObjectIdentifier("1.2.840.10040.4.3"));
    +        algorithms.put("DSAWITHSHA1", new ASN1ObjectIdentifier("1.2.840.10040.4.3"));
             algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
             algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
             algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
    @@ -140,7 +140,7 @@ public class PKCS10CertificationRequest
             //
             // reverse mappings
             //
    -        oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
    +        oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
             oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
             oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
             oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
    @@ -150,12 +150,11 @@ public class PKCS10CertificationRequest
             // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
             // END android-removed
             
    -        oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
    +        oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
             // BEGIN android-removed
    -        // Dropping MD2
    -        // oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
    +        // oids.put(new ASN1ObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
             // END android-removed
    -        oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
    +        oids.put(new ASN1ObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
             oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
             oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
             oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
    @@ -324,13 +323,13 @@ public class PKCS10CertificationRequest
                     InvalidKeyException, SignatureException
         {
             String algorithmName = Strings.toUpperCase(signatureAlgorithm);
    -        DERObjectIdentifier sigOID = (DERObjectIdentifier)algorithms.get(algorithmName);
    +        ASN1ObjectIdentifier sigOID = (ASN1ObjectIdentifier)algorithms.get(algorithmName);
     
             if (sigOID == null)
             {
                 try
                 {
    -                sigOID = new DERObjectIdentifier(algorithmName);
    +                sigOID = new ASN1ObjectIdentifier(algorithmName);
                 }
                 catch (Exception e)
                 {
    @@ -364,7 +363,7 @@ public class PKCS10CertificationRequest
             try
             {
                 ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(key.getEncoded());
    -            this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo(seq), attributes);
    +            this.reqInfo = new CertificationRequestInfo(subject, SubjectPublicKeyInfo.getInstance(seq), attributes);
             }
             catch (IOException e)
             {
    @@ -415,7 +414,7 @@ public class PKCS10CertificationRequest
             
             try
             {
    -            X509EncodedKeySpec      xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes());
    +            X509EncodedKeySpec      xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getOctets());
                 AlgorithmIdentifier     keyAlg = subjectPKInfo.getAlgorithm();
                 try
                 {
    @@ -433,9 +432,9 @@ public class PKCS10CertificationRequest
                     //
                     // try an alternate
                     //
    -                if (keyAlgorithms.get(keyAlg.getObjectId()) != null)
    +                if (keyAlgorithms.get(keyAlg.getAlgorithm()) != null)
                     {
    -                    String  keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getObjectId());
    +                    String  keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getAlgorithm());
                         
                         if (provider == null)
                         {
    @@ -508,9 +507,9 @@ public class PKCS10CertificationRequest
                 //
                 // try an alternate
                 //
    -            if (oids.get(sigAlgId.getObjectId()) != null)
    +            if (oids.get(sigAlgId.getAlgorithm()) != null)
                 {
    -                String  signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId());
    +                String  signatureAlgorithm = (String)oids.get(sigAlgId.getAlgorithm());
     
                     if (provider == null)
                     {
    @@ -540,7 +539,7 @@ public class PKCS10CertificationRequest
                 throw new SignatureException("exception encoding TBS cert request - " + e);
             }
     
    -        return sig.verify(sigBits.getBytes());
    +        return sig.verify(sigBits.getOctets());
         }
     
         /**
    @@ -597,18 +596,18 @@ public class PKCS10CertificationRequest
     
             if (params != null && !DERNull.INSTANCE.equals(params))
             {
    -            if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
    +            if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
                 {
                     RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
    -                return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
    +                return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1";
                 }
             }
     
    -        return sigAlgId.getObjectId().getId();
    +        return sigAlgId.getAlgorithm().getId();
         }
     
         private static String getDigestAlgName(
    -        DERObjectIdentifier digestAlgOID)
    +        ASN1ObjectIdentifier digestAlgOID)
         {
             if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
             {
    diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java
    index ddd38e8..b1daa98 100644
    --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java
    +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java
    @@ -129,7 +129,7 @@ public class X509Principal
          * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
          * some such, converting it into an ordered set of name attributes. lookUp 
          * should provide a table of lookups, indexed by lowercase only strings and
    -     * yielding a DERObjectIdentifier, other than that OID. and numeric oids
    +     * yielding a ASN1ObjectIdentifier, other than that OID. and numeric oids
          * will be processed automatically.
          * 

    * If reverse is true, create the encoded version of the sequence starting diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java index 39dd35a..f8a1a6f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java @@ -86,9 +86,8 @@ public class NetscapeCertRequest + spkac.size()); } - sigAlg = new AlgorithmIdentifier((ASN1Sequence)spkac - .getObjectAt(1)); - sigBits = ((DERBitString)spkac.getObjectAt(2)).getBytes(); + sigAlg = AlgorithmIdentifier.getInstance(spkac.getObjectAt(1)); + sigBits = ((DERBitString)spkac.getObjectAt(2)).getOctets(); // // PublicKeyAndChallenge ::= SEQUENCE { @@ -110,14 +109,13 @@ public class NetscapeCertRequest //could potentially alter the bytes content = new DERBitString(pkac); - SubjectPublicKeyInfo pubkeyinfo = new SubjectPublicKeyInfo( - (ASN1Sequence)pkac.getObjectAt(0)); + SubjectPublicKeyInfo pubkeyinfo = SubjectPublicKeyInfo.getInstance(pkac.getObjectAt(0)); X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString( pubkeyinfo).getBytes()); - keyAlg = pubkeyinfo.getAlgorithmId(); - pubkey = KeyFactory.getInstance(keyAlg.getObjectId().getId(), "BC") + keyAlg = pubkeyinfo.getAlgorithm(); + pubkey = KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), "BC") .generatePublic(xspec); } @@ -205,7 +203,7 @@ public class NetscapeCertRequest // Verify the signature .. shows the response was generated // by someone who knew the associated private key // - Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(), + Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(), "BC"); sig.initVerify(pubkey); sig.update(content.getBytes()); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java index c9ac46e..e8a8abe 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java @@ -8,14 +8,14 @@ public class AnnotatedException { private Throwable _underlyingException; - AnnotatedException(String string, Throwable e) + public AnnotatedException(String string, Throwable e) { super(string); _underlyingException = e; } - AnnotatedException(String string) + public AnnotatedException(String string) { this(string, null); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java index ab6c42f..00f23e8 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java @@ -44,7 +44,7 @@ import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; public final class BouncyCastleProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Security Provider v1.50"; + private static String info = "BouncyCastle Security Provider v1.54"; public static final String PROVIDER_NAME = "BC"; @@ -74,8 +74,8 @@ public final class BouncyCastleProvider extends Provider // BEGIN android-removed // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede", // "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5", - // "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "TEA", "Twofish", "Threefish", - // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20" + // "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "SM4", "TEA", "Twofish", "Threefish", + // "VMPC", "VMPCKSA3", "XTEA", "XSalsa20", "OpenSSLPBKDF" // END android-removed // BEGIN android-added "AES", "ARC4", "Blowfish", "DES", "DESede", "RC2", "Twofish", @@ -116,7 +116,8 @@ public final class BouncyCastleProvider extends Provider private static final String[] DIGESTS = { // BEGIN android-removed - // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool" + // "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", + // "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b" // END android-removed // BEGIN android-added "MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", @@ -139,7 +140,7 @@ public final class BouncyCastleProvider extends Provider */ public BouncyCastleProvider() { - super(PROVIDER_NAME, 1.50, info); + super(PROVIDER_NAME, 1.54, info); AccessController.doPrivileged(new PrivilegedAction() { @@ -276,6 +277,12 @@ public final class BouncyCastleProvider extends Provider put(key, value); } + public void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className) + { + addAlgorithm(type + "." + oid, className); + addAlgorithm(type + ".OID." + oid, className); + } + public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter) { keyInfoConverters.put(oid, keyInfoConverter); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java index c62966d..1094b3b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java @@ -122,7 +122,15 @@ public class CertBlacklist { private static final Set readSerialBlackList(String path) { - // start out with a base set of known bad values + /* Start out with a base set of known bad values. + * + * WARNING: Do not add short serials to this list! + * + * Since this currently doesn't compare the serial + issuer, you + * should only add serials that have enough entropy here. Short + * serials may inadvertently match a certificate that was issued + * not in compliance with the Baseline Requirements. + */ Set bl = new HashSet(Arrays.asList( // From http://src.chromium.org/viewvc/chrome/trunk/src/net/base/x509_certificate.cc?revision=78748&view=markup // Not a real certificate. For testing only. @@ -135,10 +143,7 @@ public class CertBlacklist { new BigInteger("d7558fdaf5f1105bb213282b707729a3", 16), new BigInteger("f5c86af36162f13a64f54f6dc9587c06", 16), new BigInteger("392a434f0e07df1f8aa305de34e0c229", 16), - new BigInteger("3e75ced46b693021218830ae86a82a71", 16), - new BigInteger("864", 16), - new BigInteger("827", 16), - new BigInteger("31da7", 16) + new BigInteger("3e75ced46b693021218830ae86a82a71", 16) )); // attempt to augment it with values taken from gservices diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java index eb663dc..b6a9d6a 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java @@ -13,7 +13,6 @@ import java.security.cert.CertStore; import java.security.cert.CertStoreException; import java.security.cert.Certificate; import java.security.cert.CertificateParsingException; -import java.security.cert.PKIXParameters; import java.security.cert.PolicyQualifierInfo; import java.security.cert.TrustAnchor; import java.security.cert.X509CRL; @@ -27,10 +26,12 @@ import java.security.spec.DSAPublicKeySpec; import java.text.ParseException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -38,19 +39,22 @@ import java.util.Set; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1GeneralizedTime; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1OutputStream; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DEREnumerated; -import org.bouncycastle.asn1.DERGeneralizedTime; -import org.bouncycastle.asn1.DERIA5String; -import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.isismtt.ISISMTTObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.style.RFC4519Style; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x509.CRLDistPoint; import org.bouncycastle.asn1.x509.CRLReason; import org.bouncycastle.asn1.x509.DistributionPoint; @@ -60,27 +64,22 @@ import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.PolicyInformation; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.asn1.x509.X509Extension; -// BEGIN android-removed -// import org.bouncycastle.jce.X509LDAPCertStoreParameters; -// END android-removed +import org.bouncycastle.jcajce.PKIXCRLStore; +import org.bouncycastle.jcajce.PKIXCRLStoreSelector; +import org.bouncycastle.jcajce.PKIXCertStore; +import org.bouncycastle.jcajce.PKIXCertStoreSelector; +import org.bouncycastle.jcajce.PKIXExtendedParameters; +import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.exception.ExtCertPathValidatorException; -import org.bouncycastle.util.Integers; import org.bouncycastle.util.Selector; +import org.bouncycastle.util.Store; import org.bouncycastle.util.StoreException; -import org.bouncycastle.x509.ExtendedPKIXBuilderParameters; -import org.bouncycastle.x509.ExtendedPKIXParameters; -// BEGIN android-removed -// import org.bouncycastle.x509.X509AttributeCertStoreSelector; -// END android-removed import org.bouncycastle.x509.X509AttributeCertificate; -import org.bouncycastle.x509.X509CRLStoreSelector; -import org.bouncycastle.x509.X509CertStoreSelector; // BEGIN android-removed -// import org.bouncycastle.x509.X509Store; +// import org.bouncycastle.x509.extension.X509ExtensionUtil; // END android-removed -public class CertPathValidatorUtilities +class CertPathValidatorUtilities { protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil(); @@ -166,7 +165,7 @@ public class CertPathValidatorUtilities Exception invalidKeyEx = null; X509CertSelector certSelectX509 = new X509CertSelector(); - X500Principal certIssuer = getEncodedIssuerPrincipal(cert); + X500Name certIssuer = PrincipalUtils.getEncodedIssuerPrincipal(cert); try { @@ -197,7 +196,7 @@ public class CertPathValidatorUtilities { try { - X500Principal caName = new X500Principal(trust.getCAName()); + X500Name caName = PrincipalUtils.getCA(trust); if (certIssuer.equals(caName)) { trustPublicKey = trust.getCAPublicKey(); @@ -240,50 +239,41 @@ public class CertPathValidatorUtilities return trust; } - protected static void addAdditionalStoresFromAltNames( - X509Certificate cert, - ExtendedPKIXParameters pkixParams) + static List getAdditionalStoresFromAltNames( + byte[] issuerAlternativeName, + Map altNameCertStoreMap) throws CertificateParsingException { // if in the IssuerAltName extension an URI - // is given, add an additinal X.509 store - if (cert.getIssuerAlternativeNames() != null) + // is given, add an additional X.509 store + if (issuerAlternativeName != null) { - Iterator it = cert.getIssuerAlternativeNames().iterator(); - while (it.hasNext()) + GeneralNames issuerAltName = GeneralNames.getInstance(ASN1OctetString.getInstance(issuerAlternativeName).getOctets()); + + GeneralName[] names = issuerAltName.getNames(); + List stores = new ArrayList(); + + for (int i = 0; i != names.length; i++) { - // look for URI - List list = (List)it.next(); - if (list.get(0).equals(Integers.valueOf(GeneralName.uniformResourceIdentifier))) + GeneralName altName = names[i]; + + PKIXCertStore altStore = altNameCertStoreMap.get(altName); + + if (altStore != null) { - // found - String temp = (String)list.get(1); - CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams); + stores.add(altStore); } } - } - } - /** - * Returns the issuer of an attribute certificate or certificate. - * - * @param cert The attribute certificate or certificate. - * @return The issuer as X500Principal. - */ - protected static X500Principal getEncodedIssuerPrincipal( - Object cert) - { - if (cert instanceof X509Certificate) - { - return ((X509Certificate)cert).getIssuerX500Principal(); + return stores; } else { - return (X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0]; + return Collections.EMPTY_LIST; } } - protected static Date getValidDate(PKIXParameters paramsPKIX) + protected static Date getValidDate(PKIXExtendedParameters paramsPKIX) { Date validDate = paramsPKIX.getDate(); @@ -295,11 +285,6 @@ public class CertPathValidatorUtilities return validDate; } - protected static X500Principal getSubjectPrincipal(X509Certificate cert) - { - return cert.getSubjectX500Principal(); - } - protected static boolean isSelfIssued(X509Certificate cert) { return cert.getSubjectDN().equals(cert.getIssuerDN()); @@ -346,11 +331,6 @@ public class CertPathValidatorUtilities } } - protected static X500Principal getIssuerPrincipal(X509CRL crl) - { - return crl.getIssuerX500Principal(); - } - protected static AlgorithmIdentifier getAlgorithmIdentifier( PublicKey key) throws CertPathValidatorException @@ -361,7 +341,7 @@ public class CertPathValidatorUtilities SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject()); - return info.getAlgorithmId(); + return info.getAlgorithm(); } catch (Exception e) { @@ -461,7 +441,7 @@ public class CertPathValidatorUtilities protected static boolean processCertD1i( int index, List[] policyNodes, - DERObjectIdentifier pOid, + ASN1ObjectIdentifier pOid, Set pq) { List policyNodeVec = policyNodes[index - 1]; @@ -496,7 +476,7 @@ public class CertPathValidatorUtilities protected static void processCertD1ii( int index, List[] policyNodes, - DERObjectIdentifier _poid, + ASN1ObjectIdentifier _poid, Set _pq) { List policyNodeVec = policyNodes[index - 1]; @@ -655,73 +635,22 @@ public class CertPathValidatorUtilities return policySet == null || policySet.contains(ANY_POLICY) || policySet.isEmpty(); } - protected static void addAdditionalStoreFromLocation(String location, - ExtendedPKIXParameters pkixParams) - { - if (pkixParams.isAdditionalLocationsEnabled()) - { - try - { - // BEGIN android-removed - // if (location.startsWith("ldap://")) - // { - // // ldap://directory.d-trust.net/CN=D-TRUST - // // Qualified CA 2003 1:PN,O=D-Trust GmbH,C=DE - // // skip "ldap://" - // location = location.substring(7); - // // after first / baseDN starts - // String base = null; - // String url = null; - // if (location.indexOf("/") != -1) - // { - // base = location.substring(location.indexOf("/")); - // // URL - // url = "ldap://" - // + location.substring(0, location.indexOf("/")); - // } - // else - // { - // url = "ldap://" + location; - // } - // // use all purpose parameters - // X509LDAPCertStoreParameters params = new X509LDAPCertStoreParameters.Builder( - // url, base).build(); - // pkixParams.addAdditionalStore(X509Store.getInstance( - // "CERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME)); - // pkixParams.addAdditionalStore(X509Store.getInstance( - // "CRL/LDAP", params, BouncyCastleProvider.PROVIDER_NAME)); - // pkixParams.addAdditionalStore(X509Store.getInstance( - // "ATTRIBUTECERTIFICATE/LDAP", params, BouncyCastleProvider.PROVIDER_NAME)); - // pkixParams.addAdditionalStore(X509Store.getInstance( - // "CERTIFICATEPAIR/LDAP", params, BouncyCastleProvider.PROVIDER_NAME)); - // } - // END android-removed - } - catch (Exception e) - { - // cannot happen - throw new RuntimeException("Exception adding X.509 stores."); - } - } - } - /** * Return a Collection of all certificates or attribute certificates found * in the X509Store's that are matching the certSelect criteriums. * * @param certSelect a {@link Selector} object that will be used to select * the certificates - * @param certStores a List containing only {@link X509Store} objects. These + * @param certStores a List containing only {@link Store} objects. These * are used to search for certificates. - * @return a Collection of all found {@link X509Certificate} or - * {@link org.bouncycastle.x509.X509AttributeCertificate} objects. + * @return a Collection of all found {@link X509Certificate} * May be empty but never null. */ - protected static Collection findCertificates(X509CertStoreSelector certSelect, + protected static Collection findCertificates(PKIXCertStoreSelector certSelect, List certStores) throws AnnotatedException { - Set certs = new HashSet(); + Set certs = new LinkedHashSet(); Iterator iter = certStores.iterator(); while (iter.hasNext()) @@ -749,7 +678,7 @@ public class CertPathValidatorUtilities try { - certs.addAll(certStore.getCertificates(certSelect)); + certs.addAll(PKIXCertStoreSelector.getCertificates(certSelect, certStore)); } catch (CertStoreException e) { @@ -762,38 +691,7 @@ public class CertPathValidatorUtilities return certs; } - // BEGIN android-removed - // protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect, - // List certStores) - // throws AnnotatedException - // { - // Set certs = new HashSet(); - // Iterator iter = certStores.iterator(); - // - // while (iter.hasNext()) - // { - // Object obj = iter.next(); - // - // if (obj instanceof X509Store) - // { - // X509Store certStore = (X509Store)obj; - // try - // { - // certs.addAll(certStore.getMatches(certSelect)); - // } - // catch (StoreException e) - // { - // throw new AnnotatedException( - // "Problem while picking certificates from X.509 store.", e); - // } - // } - // } - // return certs; - // } - // END android-removed - - protected static void addAdditionalStoresFromCRLDistributionPoint( - CRLDistPoint crldp, ExtendedPKIXParameters pkixParams) + static List getAdditionalStoresFromCRLDistributionPoint(CRLDistPoint crldp, Map namedCRLStoreMap) throws AnnotatedException { if (crldp != null) @@ -808,6 +706,8 @@ public class CertPathValidatorUtilities throw new AnnotatedException( "Distribution points could not be read.", e); } + List stores = new ArrayList(); + for (int i = 0; i < dps.length; i++) { DistributionPointName dpn = dps[i].getDistributionPoint(); @@ -818,21 +718,24 @@ public class CertPathValidatorUtilities { GeneralName[] genNames = GeneralNames.getInstance( dpn.getName()).getNames(); - // look for an URI + for (int j = 0; j < genNames.length; j++) { - if (genNames[j].getTagNo() == GeneralName.uniformResourceIdentifier) + PKIXCRLStore store = namedCRLStoreMap.get(genNames[j]); + if (store != null) { - String location = DERIA5String.getInstance( - genNames[j].getName()).getString(); - CertPathValidatorUtilities - .addAdditionalStoreFromLocation(location, - pkixParams); + stores.add(store); } } } } } + + return stores; + } + else + { + return Collections.EMPTY_LIST; } } @@ -840,26 +743,22 @@ public class CertPathValidatorUtilities * Add the CRL issuers from the cRLIssuer field of the distribution point or * from the certificate if not given to the issuer criterion of the * selector. - *

    + *

    * The issuerPrincipals are a collection with a single - * X500Principal for X509Certificates. For - * {@link X509AttributeCertificate}s the issuer may contain more than one - * X500Principal. - * + * X500Name for X509Certificates. + *

    * @param dp The distribution point. * @param issuerPrincipals The issuers of the certificate or attribute * certificate which contains the distribution point. * @param selector The CRL selector. - * @param pkixParams The PKIX parameters containing the cert stores. * @throws AnnotatedException if an exception occurs while processing. * @throws ClassCastException if issuerPrincipals does not - * contain only X500Principals. + * contain only X500Names. */ protected static void getCRLIssuersFromDistributionPoint( DistributionPoint dp, Collection issuerPrincipals, - X509CRLSelector selector, - ExtendedPKIXParameters pkixParams) + X509CRLSelector selector) throws AnnotatedException { List issuers = new ArrayList(); @@ -874,7 +773,7 @@ public class CertPathValidatorUtilities { try { - issuers.add(new X500Principal(genNames[j].getName() + issuers.add(X500Name.getInstance(genNames[j].getName() .toASN1Primitive().getEncoded())); } catch (IOException e) @@ -900,7 +799,7 @@ public class CertPathValidatorUtilities // add and check issuer principals for (Iterator it = issuerPrincipals.iterator(); it.hasNext(); ) { - issuers.add((X500Principal)it.next()); + issuers.add(it.next()); } } // TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid @@ -952,7 +851,7 @@ public class CertPathValidatorUtilities { try { - selector.addIssuerName(((X500Principal)it.next()).getEncoded()); + selector.addIssuerName(((X500Name)it.next()).getEncoded()); } catch (IOException ex) { @@ -965,14 +864,7 @@ public class CertPathValidatorUtilities private static BigInteger getSerialNumber( Object cert) { - if (cert instanceof X509Certificate) - { - return ((X509Certificate)cert).getSerialNumber(); - } - else - { - return ((X509AttributeCertificate)cert).getSerialNumber(); - } + return ((X509Certificate)cert).getSerialNumber(); } protected static void getCertStatus( @@ -1002,20 +894,23 @@ public class CertPathValidatorUtilities { return; } - - X500Principal certIssuer = crl_entry.getCertificateIssuer(); - - if (certIssuer == null) + X500Principal certificateIssuer = crl_entry.getCertificateIssuer(); + X500Name certIssuer; + if (certificateIssuer == null) { - certIssuer = getIssuerPrincipal(crl); + certIssuer = PrincipalUtils.getIssuerPrincipal(crl); + } + else + { + certIssuer = X500Name.getInstance(certificateIssuer.getEncoded()); } - if (!getEncodedIssuerPrincipal(cert).equals(certIssuer)) + if (! PrincipalUtils.getEncodedIssuerPrincipal(cert).equals(certIssuer)) { return; } } - else if (!getEncodedIssuerPrincipal(cert).equals(getIssuerPrincipal(crl))) + else if (! PrincipalUtils.getEncodedIssuerPrincipal(cert).equals(PrincipalUtils.getIssuerPrincipal(crl))) { return; // not for our issuer, ignore } @@ -1029,15 +924,15 @@ public class CertPathValidatorUtilities } } - DEREnumerated reasonCode = null; + ASN1Enumerated reasonCode = null; if (crl_entry.hasExtensions()) { try { - reasonCode = DEREnumerated + reasonCode = ASN1Enumerated .getInstance(CertPathValidatorUtilities .getExtensionValue(crl_entry, - X509Extension.reasonCode.getId())); + Extension.reasonCode.getId())); } catch (Exception e) { @@ -1074,31 +969,29 @@ public class CertPathValidatorUtilities /** * Fetches delta CRLs according to RFC 3280 section 5.2.4. * - * @param currentDate The date for which the delta CRLs must be valid. - * @param paramsPKIX The extended PKIX parameters. + * @param validityDate The date for which the delta CRLs must be valid. * @param completeCRL The complete CRL the delta CRL is for. * @return A Set of X509CRLs with delta CRLs. * @throws AnnotatedException if an exception occurs while picking the delta * CRLs. */ - protected static Set getDeltaCRLs(Date currentDate, - ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL) + protected static Set getDeltaCRLs(Date validityDate, + X509CRL completeCRL, List certStores, List pkixCrlStores) throws AnnotatedException { - - X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector(); - + X509CRLSelector baseDeltaSelect = new X509CRLSelector(); // 5.2.4 (a) try { - deltaSelect.addIssuerName(CertPathValidatorUtilities - .getIssuerPrincipal(completeCRL).getEncoded()); + baseDeltaSelect.addIssuerName(PrincipalUtils.getIssuerPrincipal(completeCRL).getEncoded()); } catch (IOException e) { throw new AnnotatedException("Cannot extract issuer from CRL.", e); } + + BigInteger completeCRLNumber = null; try { @@ -1130,17 +1023,21 @@ public class CertPathValidatorUtilities // 5.2.4 (d) - deltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber + baseDeltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber .add(BigInteger.valueOf(1))); - deltaSelect.setIssuingDistributionPoint(idp); - deltaSelect.setIssuingDistributionPointEnabled(true); + PKIXCRLStoreSelector.Builder selBuilder = new PKIXCRLStoreSelector.Builder(baseDeltaSelect); + + selBuilder.setIssuingDistributionPoint(idp); + selBuilder.setIssuingDistributionPointEnabled(true); // 5.2.4 (c) - deltaSelect.setMaxBaseCRLNumber(completeCRLNumber); + selBuilder.setMaxBaseCRLNumber(completeCRLNumber); + + PKIXCRLStoreSelector deltaSelect = selBuilder.build(); // find delta CRLs - Set temp = CRL_UTIL.findCRLs(deltaSelect, paramsPKIX, currentDate); + Set temp = CRL_UTIL.findCRLs(deltaSelect, validityDate, certStores, pkixCrlStores); Set result = new HashSet(); @@ -1173,8 +1070,7 @@ public class CertPathValidatorUtilities * Fetches complete CRLs according to RFC 3280. * * @param dp The distribution point for which the complete CRL - * @param cert The X509Certificate or - * {@link org.bouncycastle.x509.X509AttributeCertificate} for + * @param cert The X509Certificate for * which the CRL should be searched. * @param currentDate The date for which the delta CRLs must be valid. * @param paramsPKIX The extended PKIX parameters. @@ -1184,66 +1080,51 @@ public class CertPathValidatorUtilities * or no CRLs are found. */ protected static Set getCompleteCRLs(DistributionPoint dp, Object cert, - Date currentDate, ExtendedPKIXParameters paramsPKIX) + Date currentDate, PKIXExtendedParameters paramsPKIX) throws AnnotatedException { - X509CRLStoreSelector crlselect = new X509CRLStoreSelector(); + X509CRLSelector baseCrlSelect = new X509CRLSelector(); + try { Set issuers = new HashSet(); - if (cert instanceof X509AttributeCertificate) - { - issuers.add(((X509AttributeCertificate)cert) - .getIssuer().getPrincipals()[0]); - } - else - { - issuers.add(getEncodedIssuerPrincipal(cert)); - } - CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX); + + issuers.add(PrincipalUtils.getEncodedIssuerPrincipal(cert)); + + CertPathValidatorUtilities.getCRLIssuersFromDistributionPoint(dp, issuers, baseCrlSelect); } catch (AnnotatedException e) { throw new AnnotatedException( "Could not get issuer information from distribution point.", e); } + if (cert instanceof X509Certificate) { - crlselect.setCertificateChecking((X509Certificate)cert); - } - else if (cert instanceof X509AttributeCertificate) - { - crlselect.setAttrCertificateChecking((X509AttributeCertificate)cert); + baseCrlSelect.setCertificateChecking((X509Certificate)cert); } + PKIXCRLStoreSelector crlSelect = new PKIXCRLStoreSelector.Builder(baseCrlSelect).setCompleteCRLEnabled(true).build(); - crlselect.setCompleteCRLEnabled(true); - - Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate); + Date validityDate = currentDate; - if (crls.isEmpty()) + if (paramsPKIX.getDate() != null) { - if (cert instanceof X509AttributeCertificate) - { - X509AttributeCertificate aCert = (X509AttributeCertificate)cert; + validityDate = paramsPKIX.getDate(); + } - throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\""); - } - else - { - X509Certificate xCert = (X509Certificate)cert; + Set crls = CRL_UTIL.findCRLs(crlSelect, validityDate, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores()); + + checkCRLsNotEmpty(crls, cert); - throw new AnnotatedException("No CRLs found for issuer \"" + xCert.getIssuerX500Principal() + "\""); - } - } return crls; } protected static Date getValidCertDateFromValidityModel( - ExtendedPKIXParameters paramsPKIX, CertPath certPath, int index) + PKIXExtendedParameters paramsPKIX, CertPath certPath, int index) throws AnnotatedException { - if (paramsPKIX.getValidityModel() == ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL) + if (paramsPKIX.getValidityModel() == PKIXExtendedParameters.CHAIN_VALIDITY_MODEL) { // if end cert use given signing/encryption/... time if (index <= 0) @@ -1255,13 +1136,13 @@ public class CertPathValidatorUtilities { if (index - 1 == 0) { - DERGeneralizedTime dateOfCertgen = null; + ASN1GeneralizedTime dateOfCertgen = null; try { byte[] extBytes = ((X509Certificate)certPath.getCertificates().get(index - 1)).getExtensionValue(ISISMTTObjectIdentifiers.id_isismtt_at_dateOfCertGen.getId()); if (extBytes != null) { - dateOfCertgen = DERGeneralizedTime.getInstance(ASN1Primitive.fromByteArray(extBytes)); + dateOfCertgen = ASN1GeneralizedTime.getInstance(ASN1Primitive.fromByteArray(extBytes)); } } catch (IOException e) @@ -1324,7 +1205,7 @@ public class CertPathValidatorUtilities * index extended with DSA parameters if applicable. * @throws AnnotatedException if DSA parameters cannot be inherited. */ - protected static PublicKey getNextWorkingKey(List certs, int index) + protected static PublicKey getNextWorkingKey(List certs, int index, JcaJceHelper helper) throws CertPathValidatorException { Certificate cert = (Certificate)certs.get(index); @@ -1357,7 +1238,7 @@ public class CertPathValidatorUtilities dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()); try { - KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME); + KeyFactory keyFactory = helper.createKeyFactory("DSA"); return keyFactory.generatePublic(dsaPubKeySpec); } catch (Exception exception) @@ -1372,37 +1253,57 @@ public class CertPathValidatorUtilities * Find the issuer certificates of a given certificate. * * @param cert The certificate for which an issuer should be found. - * @param pkixParams * @return A Collection object containing the issuer * X509Certificates. Never null. * @throws AnnotatedException if an error occurs. */ - protected static Collection findIssuerCerts( + static Collection findIssuerCerts( X509Certificate cert, - ExtendedPKIXBuilderParameters pkixParams) + List certStores, + List pkixCertStores) throws AnnotatedException { - X509CertStoreSelector certSelect = new X509CertStoreSelector(); - Set certs = new HashSet(); + X509CertSelector selector = new X509CertSelector(); + try { - certSelect.setSubject(cert.getIssuerX500Principal().getEncoded()); + selector.setSubject(PrincipalUtils.getIssuerPrincipal(cert).getEncoded()); } - catch (IOException ex) + catch (IOException e) { throw new AnnotatedException( - "Subject criteria for certificate selector to find issuer certificate could not be set.", ex); + "Subject criteria for certificate selector to find issuer certificate could not be set.", e); + } + + try + { + byte[] akiExtensionValue = cert.getExtensionValue(AUTHORITY_KEY_IDENTIFIER); + if (akiExtensionValue != null) + { + ASN1OctetString aki = ASN1OctetString.getInstance(akiExtensionValue); + byte[] authorityKeyIdentifier = AuthorityKeyIdentifier.getInstance(aki.getOctets()).getKeyIdentifier(); + if (authorityKeyIdentifier != null) + { + selector.setSubjectKeyIdentifier(new DEROctetString(authorityKeyIdentifier).getEncoded()); + } + } + } + catch (Exception e) + { + // authority key identifier could not be retrieved from target cert, just search without it } + PKIXCertStoreSelector certSelect = new PKIXCertStoreSelector.Builder(selector).build(); + Set certs = new LinkedHashSet(); + Iterator iter; try { List matches = new ArrayList(); - matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getCertStores())); - matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getStores())); - matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixParams.getAdditionalStores())); + matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, certStores)); + matches.addAll(CertPathValidatorUtilities.findCertificates(certSelect, pkixCertStores)); iter = matches.iterator(); } @@ -1435,4 +1336,24 @@ public class CertPathValidatorUtilities cert.verify(publicKey, sigProvider); } } + + static void checkCRLsNotEmpty(Set crls, Object cert) + throws AnnotatedException + { + if (crls.isEmpty()) + { + if (cert instanceof X509AttributeCertificate) + { + X509AttributeCertificate aCert = (X509AttributeCertificate)cert; + + throw new AnnotatedException("No CRLs found for issuer \"" + aCert.getIssuer().getPrincipals()[0] + "\""); + } + else + { + X509Certificate xCert = (X509Certificate)cert; + + throw new AnnotatedException("No CRLs found for issuer \"" + RFC4519Style.INSTANCE.toString(PrincipalUtils.getIssuerPrincipal(xCert)) + "\""); + } + } + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java index b38f60b..a30b2df 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java @@ -12,10 +12,9 @@ import javax.crypto.spec.DHPrivateKeySpec; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.pkcs.DHParameter; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; @@ -61,8 +60,8 @@ public class JCEDHPrivateKey throws IOException { ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters()); - DERInteger derX = DERInteger.getInstance(info.parsePrivateKey()); - DERObjectIdentifier id = info.getAlgorithmId().getAlgorithm(); + ASN1Integer derX = ASN1Integer.getInstance(info.parsePrivateKey()); + ASN1ObjectIdentifier id = info.getAlgorithmId().getAlgorithm(); this.info = info; this.x = derX.getValue(); @@ -129,7 +128,7 @@ public class JCEDHPrivateKey return info.getEncoded(ASN1Encoding.DER); } - PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new DERInteger(getX())); + PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new ASN1Integer(getX())); return info.getEncoded(ASN1Encoding.DER); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java index 6ff1e08..3e6a09a 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java @@ -9,9 +9,9 @@ import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.spec.DHPublicKeySpec; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.pkcs.DHParameter; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; @@ -64,10 +64,10 @@ public class JCEDHPublicKey { this.info = info; - DERInteger derY; + ASN1Integer derY; try { - derY = (DERInteger)info.parsePublicKey(); + derY = (ASN1Integer)info.parsePublicKey(); } catch (IOException e) { @@ -77,7 +77,7 @@ public class JCEDHPublicKey this.y = derY.getValue(); ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters()); - DERObjectIdentifier id = info.getAlgorithmId().getAlgorithm(); + ASN1ObjectIdentifier id = info.getAlgorithmId().getAlgorithm(); // we need the PKCS check to handle older keys marked with the X9 oid. if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq)) @@ -122,7 +122,7 @@ public class JCEDHPublicKey return KeyUtil.getEncodedSubjectPublicKeyInfo(info); } - return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new DERInteger(y)); + return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new ASN1Integer(y)); } public DHParameterSpec getParams() @@ -147,8 +147,8 @@ public class JCEDHPublicKey return false; } - DERInteger l = DERInteger.getInstance(seq.getObjectAt(2)); - DERInteger p = DERInteger.getInstance(seq.getObjectAt(0)); + ASN1Integer l = ASN1Integer.getInstance(seq.getObjectAt(2)); + ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(0)); if (l.getValue().compareTo(BigInteger.valueOf(p.getValue().bitLength())) > 0) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java index 53f4ec7..20ca6f2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java @@ -13,13 +13,12 @@ import java.util.Enumeration; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERObjectIdentifier; // BEGIN android-removed // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; // import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; @@ -40,6 +39,7 @@ import org.bouncycastle.jce.interfaces.ECPointEncoder; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; import org.bouncycastle.jce.spec.ECNamedCurveSpec; import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.util.Strings; public class JCEECPrivateKey implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder @@ -254,9 +254,9 @@ public class JCEECPrivateKey } ASN1Encodable privKey = info.parsePrivateKey(); - if (privKey instanceof DERInteger) + if (privKey instanceof ASN1Integer) { - DERInteger derD = DERInteger.getInstance(privKey); + ASN1Integer derD = ASN1Integer.getInstance(privKey); this.d = derD.getValue(); } @@ -296,10 +296,10 @@ public class JCEECPrivateKey if (ecSpec instanceof ECNamedCurveSpec) { - DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); + ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName()); if (curveOid == null) // guess it's the OID { - curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); + curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName()); } params = new X962Parameters(curveOid); } @@ -433,7 +433,7 @@ public class JCEECPrivateKey public String toString() { StringBuffer buf = new StringBuffer(); - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); buf.append("EC Private Key").append(nl); buf.append(" S: ").append(this.d.toString(16)).append(nl); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java index 6fff8a6..94fb728 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java @@ -44,6 +44,9 @@ import org.bouncycastle.jce.interfaces.ECPointEncoder; // END android-removed import org.bouncycastle.jce.spec.ECNamedCurveSpec; import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.custom.sec.SecP256K1Point; +import org.bouncycastle.math.ec.custom.sec.SecP256R1Point; +import org.bouncycastle.util.Strings; public class JCEECPublicKey implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder @@ -189,7 +192,8 @@ public class JCEECPublicKey private void populateFromPubKeyInfo(SubjectPublicKeyInfo info) { - // if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001)) + // BEGIN android-removed + // if (info.getAlgorithmId().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001)) // { // DERBitString bits = info.getPublicKeyData(); // ASN1OctetString key; @@ -452,14 +456,7 @@ public class JCEECPublicKey { if (ecSpec == null) { - if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp) - { - return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getAffineXCoord(), q.getAffineYCoord()); - } - else - { - return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getAffineXCoord(), q.getAffineYCoord()); - } + return q.getDetachedPoint(); } return q; @@ -483,7 +480,7 @@ public class JCEECPublicKey public String toString() { StringBuffer buf = new StringBuffer(); - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); buf.append("EC Public Key").append(nl); buf.append(" X: ").append(this.q.getAffineXCoord().toBigInteger().toString(16)).append(nl); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java index f9bb5dd..40f007f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java @@ -12,6 +12,7 @@ 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; +import org.bouncycastle.util.Strings; /** * A provider representation for a RSA private key, with CRT factors included. @@ -224,7 +225,7 @@ public class JCERSAPrivateCrtKey public String toString() { StringBuffer buf = new StringBuffer(); - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); buf.append("RSA Private CRT Key").append(nl); buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java index a09295d..adf0e3e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java @@ -5,14 +5,13 @@ import java.math.BigInteger; import java.security.interfaces.RSAPublicKey; import java.security.spec.RSAPublicKeySpec; -import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.RSAPublicKeyStructure; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; +import org.bouncycastle.util.Strings; public class JCERSAPublicKey implements RSAPublicKey @@ -48,7 +47,7 @@ public class JCERSAPublicKey { try { - RSAPublicKeyStructure pubKey = new RSAPublicKeyStructure((ASN1Sequence)info.parsePublicKey()); + org.bouncycastle.asn1.pkcs.RSAPublicKey pubKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey()); this.modulus = pubKey.getModulus(); this.publicExponent = pubKey.getPublicExponent(); @@ -91,7 +90,7 @@ public class JCERSAPublicKey public byte[] getEncoded() { - return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKeyStructure(getModulus(), getPublicExponent())); + return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent())); } public int hashCode() @@ -120,7 +119,7 @@ public class JCERSAPublicKey public String toString() { StringBuffer buf = new StringBuffer(); - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); buf.append("RSA Public Key").append(nl); buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java deleted file mode 100644 index 7471b0b..0000000 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java +++ /dev/null @@ -1,623 +0,0 @@ -package org.bouncycastle.jce.provider; - -import java.security.AlgorithmParameters; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.PrivateKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.CipherSpi; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.PBEParameterSpec; -// BEGIN android-removed -// import javax.crypto.spec.RC2ParameterSpec; -// import javax.crypto.spec.RC5ParameterSpec; -// END android-removed -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.crypto.BlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.StreamBlockCipher; -import org.bouncycastle.crypto.StreamCipher; -// BEGIN android-removed -// import org.bouncycastle.crypto.engines.BlowfishEngine; -// import org.bouncycastle.crypto.engines.DESEngine; -// import org.bouncycastle.crypto.engines.DESedeEngine; -// END android-removed -import org.bouncycastle.crypto.engines.RC4Engine; -// BEGIN android-removed -// import org.bouncycastle.crypto.engines.SkipjackEngine; -// import org.bouncycastle.crypto.engines.TwofishEngine; -// END android-removed -import org.bouncycastle.crypto.modes.CFBBlockCipher; -import org.bouncycastle.crypto.modes.OFBBlockCipher; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey; -import org.bouncycastle.jcajce.provider.symmetric.util.PBE; - -public class JCEStreamCipher - extends CipherSpi - implements PBE -{ - // - // specs we can handle. - // - private Class[] availableSpecs = - { - // BEGIN android-removed - // RC2ParameterSpec.class, - // RC5ParameterSpec.class, - // END android-removed - IvParameterSpec.class, - PBEParameterSpec.class - }; - - private StreamCipher cipher; - private ParametersWithIV ivParam; - - private int ivLength = 0; - - private PBEParameterSpec pbeSpec = null; - private String pbeAlgorithm = null; - - private AlgorithmParameters engineParams; - - protected JCEStreamCipher( - StreamCipher engine, - int ivLength) - { - cipher = engine; - this.ivLength = ivLength; - } - - protected JCEStreamCipher( - BlockCipher engine, - int ivLength) - { - this.ivLength = ivLength; - - cipher = new StreamBlockCipher(engine); - } - - protected int engineGetBlockSize() - { - return 0; - } - - protected byte[] engineGetIV() - { - return (ivParam != null) ? ivParam.getIV() : null; - } - - protected int engineGetKeySize( - Key key) - { - return key.getEncoded().length * 8; - } - - protected int engineGetOutputSize( - int inputLen) - { - return inputLen; - } - - protected AlgorithmParameters engineGetParameters() - { - if (engineParams == null) - { - if (pbeSpec != null) - { - try - { - AlgorithmParameters engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME); - engineParams.init(pbeSpec); - - return engineParams; - } - catch (Exception e) - { - return null; - } - } - } - - return engineParams; - } - - /** - * should never be called. - */ - protected void engineSetMode( - String mode) - { - if (!mode.equalsIgnoreCase("ECB")) - { - throw new IllegalArgumentException("can't support mode " + mode); - } - } - - /** - * should never be called. - */ - protected void engineSetPadding( - String padding) - throws NoSuchPaddingException - { - if (!padding.equalsIgnoreCase("NoPadding")) - { - throw new NoSuchPaddingException("Padding " + padding + " unknown."); - } - } - - protected void engineInit( - int opmode, - Key key, - AlgorithmParameterSpec params, - SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException - { - CipherParameters param; - - this.pbeSpec = null; - this.pbeAlgorithm = null; - - this.engineParams = null; - - // - // basic key check - // - if (!(key instanceof SecretKey)) - { - throw new InvalidKeyException("Key for algorithm " + key.getAlgorithm() + " not suitable for symmetric enryption."); - } - - if (key instanceof BCPBEKey) - { - BCPBEKey k = (BCPBEKey)key; - - if (k.getOID() != null) - { - pbeAlgorithm = k.getOID().getId(); - } - else - { - pbeAlgorithm = k.getAlgorithm(); - } - - if (k.getParam() != null) - { - param = k.getParam(); - pbeSpec = new PBEParameterSpec(k.getSalt(), k.getIterationCount()); - } - else if (params instanceof PBEParameterSpec) - { - param = PBE.Util.makePBEParameters(k, params, cipher.getAlgorithmName()); - pbeSpec = (PBEParameterSpec)params; - } - else - { - throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set."); - } - - if (k.getIvSize() != 0) - { - ivParam = (ParametersWithIV)param; - } - } - else if (params == null) - { - param = new KeyParameter(key.getEncoded()); - } - else if (params instanceof IvParameterSpec) - { - param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV()); - ivParam = (ParametersWithIV)param; - } - else - { - throw new IllegalArgumentException("unknown parameter type."); - } - - if ((ivLength != 0) && !(param instanceof ParametersWithIV)) - { - SecureRandom ivRandom = random; - - if (ivRandom == null) - { - ivRandom = new SecureRandom(); - } - - if ((opmode == Cipher.ENCRYPT_MODE) || (opmode == Cipher.WRAP_MODE)) - { - byte[] iv = new byte[ivLength]; - - ivRandom.nextBytes(iv); - param = new ParametersWithIV(param, iv); - ivParam = (ParametersWithIV)param; - } - else - { - throw new InvalidAlgorithmParameterException("no IV set when one expected"); - } - } - - 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: - System.out.println("eeek!"); - } - } - - protected void engineInit( - int opmode, - Key key, - AlgorithmParameters params, - SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException - { - AlgorithmParameterSpec paramSpec = null; - - if (params != null) - { - for (int i = 0; i != availableSpecs.length; i++) - { - try - { - paramSpec = params.getParameterSpec(availableSpecs[i]); - break; - } - catch (Exception e) - { - continue; - } - } - - if (paramSpec == null) - { - throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString()); - } - } - - engineInit(opmode, key, paramSpec, random); - engineParams = params; - } - - protected void engineInit( - int opmode, - Key key, - SecureRandom random) - throws InvalidKeyException - { - try - { - engineInit(opmode, key, (AlgorithmParameterSpec)null, random); - } - catch (InvalidAlgorithmParameterException e) - { - throw new InvalidKeyException(e.getMessage()); - } - } - - protected byte[] engineUpdate( - byte[] input, - int inputOffset, - int inputLen) - { - byte[] out = new byte[inputLen]; - - cipher.processBytes(input, inputOffset, inputLen, out, 0); - - return out; - } - - protected int engineUpdate( - byte[] input, - int inputOffset, - int inputLen, - byte[] output, - int outputOffset) - throws ShortBufferException - { - try - { - cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); - - return inputLen; - } - catch (DataLengthException e) - { - throw new ShortBufferException(e.getMessage()); - } - } - - protected byte[] engineDoFinal( - byte[] input, - int inputOffset, - int inputLen) - throws BadPaddingException, IllegalBlockSizeException - { - if (inputLen != 0) - { - byte[] out = engineUpdate(input, inputOffset, inputLen); - - cipher.reset(); - - return out; - } - - cipher.reset(); - - return new byte[0]; - } - - protected int engineDoFinal( - byte[] input, - int inputOffset, - int inputLen, - byte[] output, - int outputOffset) - throws BadPaddingException - { - if (inputLen != 0) - { - cipher.processBytes(input, inputOffset, inputLen, output, outputOffset); - } - - cipher.reset(); - - return inputLen; - } - - protected byte[] engineWrap( - Key key) - throws IllegalBlockSizeException, InvalidKeyException - { - byte[] encoded = key.getEncoded(); - if (encoded == null) - { - throw new InvalidKeyException("Cannot wrap key, null encoding."); - } - - try - { - return engineDoFinal(encoded, 0, encoded.length); - } - catch (BadPaddingException e) - { - throw new IllegalBlockSizeException(e.getMessage()); - } - } - - protected Key engineUnwrap( - byte[] wrappedKey, - String wrappedKeyAlgorithm, - int wrappedKeyType) - throws InvalidKeyException - { - byte[] encoded; - try - { - encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length); - } - catch (BadPaddingException e) - { - throw new InvalidKeyException(e.getMessage()); - } - catch (IllegalBlockSizeException e2) - { - throw new InvalidKeyException(e2.getMessage()); - } - - if (wrappedKeyType == Cipher.SECRET_KEY) - { - return new SecretKeySpec(encoded, wrappedKeyAlgorithm); - } - else if (wrappedKeyAlgorithm.equals("") && wrappedKeyType == Cipher.PRIVATE_KEY) - { - /* - * The caller doesn't know the algorithm as it is part of - * the encrypted data. - */ - try - { - PrivateKeyInfo in = PrivateKeyInfo.getInstance(encoded); - - PrivateKey privKey = BouncyCastleProvider.getPrivateKey(in); - - if (privKey != null) - { - return privKey; - } - else - { - throw new InvalidKeyException("algorithm " + in.getPrivateKeyAlgorithm().getAlgorithm() + " not supported"); - } - } - catch (Exception e) - { - throw new InvalidKeyException("Invalid key encoding."); - } - } - else - { - try - { - KeyFactory kf = KeyFactory.getInstance(wrappedKeyAlgorithm, BouncyCastleProvider.PROVIDER_NAME); - - if (wrappedKeyType == Cipher.PUBLIC_KEY) - { - return kf.generatePublic(new X509EncodedKeySpec(encoded)); - } - else if (wrappedKeyType == Cipher.PRIVATE_KEY) - { - return kf.generatePrivate(new PKCS8EncodedKeySpec(encoded)); - } - } - catch (NoSuchProviderException e) - { - throw new InvalidKeyException("Unknown key type " + e.getMessage()); - } - catch (NoSuchAlgorithmException e) - { - throw new InvalidKeyException("Unknown key type " + e.getMessage()); - } - catch (InvalidKeySpecException e2) - { - throw new InvalidKeyException("Unknown key type " + e2.getMessage()); - } - - throw new InvalidKeyException("Unknown key type " + wrappedKeyType); - } - } - - /* - * The ciphers that inherit from us. - */ - - // BEGIN android-removed - // /** - // * DES - // */ - // static public class DES_CFB8 - // extends JCEStreamCipher - // { - // public DES_CFB8() - // { - // super(new CFBBlockCipher(new DESEngine(), 8), 64); - // } - // } - // - // /** - // * DESede - // */ - // static public class DESede_CFB8 - // extends JCEStreamCipher - // { - // public DESede_CFB8() - // { - // super(new CFBBlockCipher(new DESedeEngine(), 8), 64); - // } - // } - // - // /** - // * SKIPJACK - // */ - // static public class Skipjack_CFB8 - // extends JCEStreamCipher - // { - // public Skipjack_CFB8() - // { - // super(new CFBBlockCipher(new SkipjackEngine(), 8), 64); - // } - // } - // - // /** - // * Blowfish - // */ - // static public class Blowfish_CFB8 - // extends JCEStreamCipher - // { - // public Blowfish_CFB8() - // { - // super(new CFBBlockCipher(new BlowfishEngine(), 8), 64); - // } - // } - // - // /** - // * Twofish - // */ - // static public class Twofish_CFB8 - // extends JCEStreamCipher - // { - // public Twofish_CFB8() - // { - // super(new CFBBlockCipher(new TwofishEngine(), 8), 128); - // } - // } - // - // /** - // * DES - // */ - // static public class DES_OFB8 - // extends JCEStreamCipher - // { - // public DES_OFB8() - // { - // super(new OFBBlockCipher(new DESEngine(), 8), 64); - // } - // } - // - // /** - // * DESede - // */ - // static public class DESede_OFB8 - // extends JCEStreamCipher - // { - // public DESede_OFB8() - // { - // super(new OFBBlockCipher(new DESedeEngine(), 8), 64); - // } - // } - // - // /** - // * SKIPJACK - // */ - // static public class Skipjack_OFB8 - // extends JCEStreamCipher - // { - // public Skipjack_OFB8() - // { - // super(new OFBBlockCipher(new SkipjackEngine(), 8), 64); - // } - // } - // - // /** - // * Blowfish - // */ - // static public class Blowfish_OFB8 - // extends JCEStreamCipher - // { - // public Blowfish_OFB8() - // { - // super(new OFBBlockCipher(new BlowfishEngine(), 8), 64); - // } - // } - // - // /** - // * Twofish - // */ - // static public class Twofish_OFB8 - // extends JCEStreamCipher - // { - // public Twofish_OFB8() - // { - // super(new OFBBlockCipher(new TwofishEngine(), 8), 128); - // } - // } - // END android-removed -} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java index 50a714c..3bd6d30 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java @@ -14,8 +14,6 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DSAParameter; @@ -57,7 +55,7 @@ public class JDKDSAPrivateKey throws IOException { DSAParameter params = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters()); - DERInteger derX = ASN1Integer.getInstance(info.parsePrivateKey()); + ASN1Integer derX = ASN1Integer.getInstance(info.parsePrivateKey()); this.x = derX.getValue(); this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG()); @@ -95,7 +93,7 @@ public class JDKDSAPrivateKey { try { - PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new DERInteger(getX())); + PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new ASN1Integer(getX())); return info.getEncoded(ASN1Encoding.DER); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java index 85a39a4..95a1ad7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java @@ -11,14 +11,14 @@ import java.security.spec.DSAPublicKeySpec; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DSAParameter; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import org.bouncycastle.util.Strings; public class JDKDSAPublicKey implements DSAPublicKey @@ -61,11 +61,11 @@ public class JDKDSAPublicKey SubjectPublicKeyInfo info) { - DERInteger derY; + ASN1Integer derY; try { - derY = (DERInteger)info.parsePublicKey(); + derY = (ASN1Integer)info.parsePublicKey(); } catch (IOException e) { @@ -103,10 +103,10 @@ public class JDKDSAPublicKey { if (dsaSpec == null) { - return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new DERInteger(y)).getEncoded(ASN1Encoding.DER); + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(y)).getEncoded(ASN1Encoding.DER); } - return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new DERInteger(y)).getEncoded(ASN1Encoding.DER); + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new ASN1Integer(y)).getEncoded(ASN1Encoding.DER); } catch (IOException e) { @@ -127,7 +127,7 @@ public class JDKDSAPublicKey public String toString() { StringBuffer buf = new StringBuffer(); - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); buf.append("DSA Public Key").append(nl); buf.append(" y: ").append(this.getY().toString(16)).append(nl); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java index ebd2f2a..b53b7aa 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java @@ -2,7 +2,6 @@ package org.bouncycastle.jce.provider; import java.security.cert.CertStore; import java.security.cert.CertStoreException; -import java.security.cert.PKIXParameters; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.util.Collection; @@ -12,16 +11,14 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import org.bouncycastle.jcajce.PKIXCRLStore; +import org.bouncycastle.jcajce.PKIXCRLStoreSelector; +import org.bouncycastle.util.Store; import org.bouncycastle.util.StoreException; -import org.bouncycastle.x509.ExtendedPKIXParameters; -import org.bouncycastle.x509.X509CRLStoreSelector; -// BEGIN android-removed -// import org.bouncycastle.x509.X509Store; -// END android-removed -public class PKIXCRLUtil +class PKIXCRLUtil { - public Set findCRLs(X509CRLStoreSelector crlselect, ExtendedPKIXParameters paramsPKIX, Date currentDate) + public Set findCRLs(PKIXCRLStoreSelector crlselect, Date validityDate, List certStores, List pkixCrlStores) throws AnnotatedException { Set initialSet = new HashSet(); @@ -29,9 +26,8 @@ public class PKIXCRLUtil // get complete CRL(s) try { - initialSet.addAll(findCRLs(crlselect, paramsPKIX.getAdditionalStores())); - initialSet.addAll(findCRLs(crlselect, paramsPKIX.getStores())); - initialSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores())); + initialSet.addAll(findCRLs(crlselect, pkixCrlStores)); + initialSet.addAll(findCRLs(crlselect, certStores)); } catch (AnnotatedException e) { @@ -39,12 +35,6 @@ public class PKIXCRLUtil } Set finalSet = new HashSet(); - Date validityDate = currentDate; - - if (paramsPKIX.getDate() != null) - { - validityDate = paramsPKIX.getDate(); - } // based on RFC 5280 6.3.3 for (Iterator it = initialSet.iterator(); it.hasNext();) @@ -72,38 +62,20 @@ public class PKIXCRLUtil return finalSet; } - public Set findCRLs(X509CRLStoreSelector crlselect, PKIXParameters paramsPKIX) - throws AnnotatedException - { - Set completeSet = new HashSet(); - - // get complete CRL(s) - try - { - completeSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores())); - } - catch (AnnotatedException e) - { - throw new AnnotatedException("Exception obtaining complete CRLs.", e); - } - - return completeSet; - } - -/** + /** * Return a Collection of all CRLs found in the X509Store's that are * matching the crlSelect criteriums. * - * @param crlSelect a {@link X509CRLStoreSelector} object that will be used + * @param crlSelect a {@link org.bouncycastle.jcajce.PKIXCRLStoreSelector} object that will be used * to select the CRLs * @param crlStores a List containing only - * {@link org.bouncycastle.x509.X509Store X509Store} objects. + * {@link Store} objects. * These are used to search for CRLs * * @return a Collection of all found {@link java.security.cert.X509CRL X509CRL} objects. May be * empty but never null. */ - private final Collection findCRLs(X509CRLStoreSelector crlSelect, + private final Collection findCRLs(PKIXCRLStoreSelector crlSelect, List crlStores) throws AnnotatedException { Set crls = new HashSet(); @@ -117,10 +89,10 @@ public class PKIXCRLUtil Object obj = iter.next(); // BEGIN android-removed - // if (obj instanceof X509Store) + // if (obj instanceof Store) // { - // X509Store store = (X509Store)obj; - // + // Store store = (Store)obj; + // try // { // crls.addAll(store.getMatches(crlSelect)); @@ -139,7 +111,7 @@ public class PKIXCRLUtil try { - crls.addAll(store.getCRLs(crlSelect)); + crls.addAll(PKIXCRLStoreSelector.getCRLs(crlSelect, store)); foundValidStore = true; } catch (CertStoreException e) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java index 384eb86..dfe9cef 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java @@ -6,8 +6,6 @@ import java.security.cert.CertPathBuilderException; import java.security.cert.CertPathBuilderResult; import java.security.cert.CertPathBuilderSpi; import java.security.cert.CertPathParameters; -import java.security.cert.CertPathValidator; -import java.security.cert.CertificateFactory; import java.security.cert.CertificateParsingException; import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXCertPathBuilderResult; @@ -19,10 +17,15 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.jcajce.PKIXCertStore; +import org.bouncycastle.jcajce.PKIXCertStoreSelector; +import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters; +import org.bouncycastle.jcajce.PKIXExtendedParameters; +import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory; import org.bouncycastle.jce.exception.ExtCertPathBuilderException; -import org.bouncycastle.util.Selector; import org.bouncycastle.x509.ExtendedPKIXBuilderParameters; -import org.bouncycastle.x509.X509CertStoreSelector; +import org.bouncycastle.x509.ExtendedPKIXParameters; /** * Implements the PKIX CertPathBuilding algorithm for BouncyCastle. @@ -41,24 +44,43 @@ public class PKIXCertPathBuilderSpi public CertPathBuilderResult engineBuild(CertPathParameters params) throws CertPathBuilderException, InvalidAlgorithmParameterException { - if (!(params instanceof PKIXBuilderParameters) - && !(params instanceof ExtendedPKIXBuilderParameters)) + PKIXExtendedBuilderParameters paramsPKIX; + if (params instanceof PKIXBuilderParameters) { - throw new InvalidAlgorithmParameterException( - "Parameters must be an instance of " - + PKIXBuilderParameters.class.getName() + " or " - + ExtendedPKIXBuilderParameters.class.getName() + "."); - } + PKIXExtendedParameters.Builder paramsPKIXBldr = new PKIXExtendedParameters.Builder((PKIXBuilderParameters)params); + PKIXExtendedBuilderParameters.Builder paramsBldrPKIXBldr; + + if (params instanceof ExtendedPKIXParameters) + { + ExtendedPKIXBuilderParameters extPKIX = (ExtendedPKIXBuilderParameters)params; + + ; + for (Iterator it = extPKIX.getAdditionalStores().iterator(); it.hasNext();) + { + paramsPKIXBldr.addCertificateStore((PKIXCertStore)it.next()); + } + paramsBldrPKIXBldr = new PKIXExtendedBuilderParameters.Builder(paramsPKIXBldr.build()); + + paramsBldrPKIXBldr.addExcludedCerts(extPKIX.getExcludedCerts()); + paramsBldrPKIXBldr.setMaxPathLength(extPKIX.getMaxPathLength()); + } + else + { + paramsBldrPKIXBldr = new PKIXExtendedBuilderParameters.Builder((PKIXBuilderParameters)params); + } - ExtendedPKIXBuilderParameters pkixParams = null; - if (params instanceof ExtendedPKIXBuilderParameters) + paramsPKIX = paramsBldrPKIXBldr.build(); + } + else if (params instanceof PKIXExtendedBuilderParameters) { - pkixParams = (ExtendedPKIXBuilderParameters) params; + paramsPKIX = (PKIXExtendedBuilderParameters)params; } else { - pkixParams = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters - .getInstance((PKIXBuilderParameters) params); + throw new InvalidAlgorithmParameterException( + "Parameters must be an instance of " + + PKIXBuilderParameters.class.getName() + " or " + + PKIXExtendedBuilderParameters.class.getName() + "."); } Collection targets; @@ -68,19 +90,12 @@ public class PKIXCertPathBuilderSpi // search target certificates - Selector certSelect = pkixParams.getTargetConstraints(); - if (!(certSelect instanceof X509CertStoreSelector)) - { - throw new CertPathBuilderException( - "TargetConstraints must be an instance of " - + X509CertStoreSelector.class.getName() + " for " - + this.getClass().getName() + " class."); - } + PKIXCertStoreSelector certSelect = paramsPKIX.getBaseParameters().getTargetConstraints(); try { - targets = CertPathValidatorUtilities.findCertificates((X509CertStoreSelector)certSelect, pkixParams.getStores()); - targets.addAll(CertPathValidatorUtilities.findCertificates((X509CertStoreSelector)certSelect, pkixParams.getCertStores())); + targets = CertPathValidatorUtilities.findCertificates(certSelect, paramsPKIX.getBaseParameters().getCertificateStores()); + targets.addAll(CertPathValidatorUtilities.findCertificates(certSelect, paramsPKIX.getBaseParameters().getCertStores())); } catch (AnnotatedException e) { @@ -102,7 +117,7 @@ public class PKIXCertPathBuilderSpi while (targetIter.hasNext() && result == null) { cert = (X509Certificate) targetIter.next(); - result = build(cert, pkixParams, certPathList); + result = build(cert, paramsPKIX, certPathList); } if (result == null && certPathException != null) @@ -128,7 +143,7 @@ public class PKIXCertPathBuilderSpi private Exception certPathException; protected CertPathBuilderResult build(X509Certificate tbvCert, - ExtendedPKIXBuilderParameters pkixParams, List tbvPath) + PKIXExtendedBuilderParameters pkixParams, List tbvPath) { // If tbvCert is readily present in tbvPath, it indicates having run // into a cycle in the @@ -155,13 +170,13 @@ public class PKIXCertPathBuilderSpi tbvPath.add(tbvCert); CertificateFactory cFact; - CertPathValidator validator; + PKIXCertPathValidatorSpi validator; CertPathBuilderResult builderResult = null; try { - cFact = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); - validator = CertPathValidator.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME); + cFact = new CertificateFactory(); + validator = new PKIXCertPathValidatorSpi(); } catch (Exception e) { @@ -172,8 +187,8 @@ public class PKIXCertPathBuilderSpi try { // check whether the issuer of is a TrustAnchor - if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getTrustAnchors(), - pkixParams.getSigProvider()) != null) + if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getBaseParameters().getTrustAnchors(), + pkixParams.getBaseParameters().getSigProvider()) != null) { // exception message from possibly later tried certification // chains @@ -181,7 +196,7 @@ public class PKIXCertPathBuilderSpi PKIXCertPathValidatorResult result = null; try { - certPath = cFact.generateCertPath(tbvPath); + certPath = cFact.engineGenerateCertPath(tbvPath); } catch (Exception e) { @@ -192,7 +207,7 @@ public class PKIXCertPathBuilderSpi try { - result = (PKIXCertPathValidatorResult) validator.validate( + result = (PKIXCertPathValidatorResult) validator.engineValidate( certPath, pkixParams); } catch (Exception e) @@ -208,16 +223,21 @@ public class PKIXCertPathBuilderSpi } else { + List stores = new ArrayList(); + + + stores.addAll(pkixParams.getBaseParameters().getCertificateStores()); + // add additional X.509 stores from locations in certificate try { - CertPathValidatorUtilities.addAdditionalStoresFromAltNames( - tbvCert, pkixParams); + stores.addAll(CertPathValidatorUtilities.getAdditionalStoresFromAltNames( + tbvCert.getExtensionValue(Extension.issuerAlternativeName.getId()), pkixParams.getBaseParameters().getNamedCertificateStoreMap())); } catch (CertificateParsingException e) { throw new AnnotatedException( - "No additiontal X.509 stores can be added from certificate locations.", + "No additional X.509 stores can be added from certificate locations.", e); } Collection issuers = new HashSet(); @@ -225,7 +245,7 @@ public class PKIXCertPathBuilderSpi // of the stores try { - issuers.addAll(CertPathValidatorUtilities.findIssuerCerts(tbvCert, pkixParams)); + issuers.addAll(CertPathValidatorUtilities.findIssuerCerts(tbvCert, pkixParams.getBaseParameters().getCertStores(), stores)); } catch (AnnotatedException e) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java index d8efa6a..5d49d88 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java @@ -21,11 +21,15 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -import javax.security.auth.x500.X500Principal; - import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters; +import org.bouncycastle.jcajce.PKIXExtendedParameters; +import org.bouncycastle.jcajce.util.BCJcaJceHelper; +import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.exception.ExtCertPathValidatorException; import org.bouncycastle.x509.ExtendedPKIXParameters; @@ -36,6 +40,11 @@ import org.bouncycastle.x509.ExtendedPKIXParameters; public class PKIXCertPathValidatorSpi extends CertPathValidatorSpi { + private final JcaJceHelper helper = new BCJcaJceHelper(); + + public PKIXCertPathValidatorSpi() + { + } // BEGIN android-added private static class NoPreloadHolder { private final static CertBlacklist blacklist = new CertBlacklist(); @@ -48,21 +57,34 @@ public class PKIXCertPathValidatorSpi throws CertPathValidatorException, InvalidAlgorithmParameterException { - if (!(params instanceof PKIXParameters)) + PKIXExtendedParameters paramsPKIX; + if (params instanceof PKIXParameters) { - throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName() - + " instance."); - } + PKIXExtendedParameters.Builder paramsPKIXBldr = new PKIXExtendedParameters.Builder((PKIXParameters)params); + + if (params instanceof ExtendedPKIXParameters) + { + ExtendedPKIXParameters extPKIX = (ExtendedPKIXParameters)params; - ExtendedPKIXParameters paramsPKIX; - if (params instanceof ExtendedPKIXParameters) + paramsPKIXBldr.setUseDeltasEnabled(extPKIX.isUseDeltasEnabled()); + paramsPKIXBldr.setValidityModel(extPKIX.getValidityModel()); + } + + paramsPKIX = paramsPKIXBldr.build(); + } + else if (params instanceof PKIXExtendedBuilderParameters) { - paramsPKIX = (ExtendedPKIXParameters)params; + paramsPKIX = ((PKIXExtendedBuilderParameters)params).getBaseParameters(); + } + else if (params instanceof PKIXExtendedParameters) + { + paramsPKIX = (PKIXExtendedParameters)params; } else { - paramsPKIX = ExtendedPKIXParameters.getInstance((PKIXParameters)params); + throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName() + " instance."); } + if (paramsPKIX.getTrustAnchors() == null) { throw new InvalidAlgorithmParameterException( @@ -81,7 +103,7 @@ public class PKIXCertPathValidatorSpi if (certs.isEmpty()) { - throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0); + throw new CertPathValidatorException("Certification path is empty.", null, certPath, -1); } // BEGIN android-added { @@ -129,6 +151,9 @@ public class PKIXCertPathValidatorSpi throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1); } + // RFC 5280 - CRLs must originate from the same trust anchor as the target certificate. + paramsPKIX = new PKIXExtendedParameters.Builder(paramsPKIX).setTrustAnchor(trust).build(); + // // (e), (f), (g) are part of the paramsPKIX object. // @@ -210,19 +235,19 @@ public class PKIXCertPathValidatorSpi // (g), (h), (i), (j) // PublicKey workingPublicKey; - X500Principal workingIssuerName; + X500Name workingIssuerName; X509Certificate sign = trust.getTrustedCert(); try { if (sign != null) { - workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign); + workingIssuerName = PrincipalUtils.getSubjectPrincipal(sign); workingPublicKey = sign.getPublicKey(); } else { - workingIssuerName = new X500Principal(trust.getCAName()); + workingIssuerName = PrincipalUtils.getCA(trust); workingPublicKey = trust.getCAPublicKey(); } } @@ -242,7 +267,7 @@ public class PKIXCertPathValidatorSpi throw new ExtCertPathValidatorException( "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1); } - DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId(); + ASN1ObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getAlgorithm(); ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters(); // @@ -305,7 +330,7 @@ public class PKIXCertPathValidatorSpi // RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey, - verificationAlreadyPerformed, workingIssuerName, sign); + verificationAlreadyPerformed, workingIssuerName, sign, helper); RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator); @@ -390,12 +415,12 @@ public class PKIXCertPathValidatorSpi sign = cert; // (c) - workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign); + workingIssuerName = PrincipalUtils.getSubjectPrincipal(sign); // (d) try { - workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index); + workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index, helper); } catch (CertPathValidatorException e) { @@ -404,7 +429,7 @@ public class PKIXCertPathValidatorSpi workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey); // (f) - workingPublicKeyAlgorithm = workingAlgId.getObjectId(); + workingPublicKeyAlgorithm = workingAlgId.getAlgorithm(); // (e) workingPublicKeyParameters = workingAlgId.getParameters(); } @@ -442,6 +467,7 @@ public class PKIXCertPathValidatorSpi criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME); criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS); criticalExtensions.remove(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS); + criticalExtensions.remove(Extension.extendedKeyUsage.getId()); } else { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java index 7ecc486..0742712 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java @@ -635,13 +635,17 @@ public class PKIXNameConstraintValidator private boolean emailIsConstrained(String email, String constraint) { String sub = email.substring(email.indexOf('@') + 1); - // a particular mailbox + // a particular mailbox or @domain if (constraint.indexOf('@') != -1) { if (email.equalsIgnoreCase(constraint)) { return true; } + if (sub.equalsIgnoreCase(constraint.substring(1))) + { + return true; + } } // on particular host else if (!(constraint.charAt(0) == '.')) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java index 3437605..d89e920 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java @@ -165,4 +165,9 @@ public class PKIXPolicyNode return _node; } + + public void setExpectedPolicies(Set expectedPolicies) + { + this.expectedPolicies = expectedPolicies; + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PrincipalUtils.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PrincipalUtils.java new file mode 100644 index 0000000..9059079 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/PrincipalUtils.java @@ -0,0 +1,53 @@ +package org.bouncycastle.jce.provider; + +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLEntry; +import java.security.cert.X509Certificate; + +import javax.security.auth.x500.X500Principal; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.x509.X509AttributeCertificate; + +class PrincipalUtils +{ + static X500Name getSubjectPrincipal(X509Certificate cert) + { + return X500Name.getInstance(cert.getSubjectX500Principal().getEncoded()); + } + + static X500Name getIssuerPrincipal(X509CRL crl) + { + return X500Name.getInstance(crl.getIssuerX500Principal().getEncoded()); + } + + static X500Name getIssuerPrincipal(X509Certificate cert) + { + return X500Name.getInstance(cert.getIssuerX500Principal().getEncoded()); + } + + static X500Name getCA(TrustAnchor trustAnchor) + { + return X500Name.getInstance(trustAnchor.getCA().getEncoded()); + } + + /** + * Returns the issuer of an attribute certificate or certificate. + * + * @param cert The attribute certificate or certificate. + * @return The issuer as X500Principal. + */ + static X500Name getEncodedIssuerPrincipal( + Object cert) + { + if (cert instanceof X509Certificate) + { + return getIssuerPrincipal((X509Certificate)cert); + } + else + { + return X500Name.getInstance(((X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0]).getEncoded()); + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java index 769edb8..d67a77e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java @@ -5,15 +5,17 @@ import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.PublicKey; import java.security.cert.CertPath; -import java.security.cert.CertPathBuilder; import java.security.cert.CertPathBuilderException; import java.security.cert.CertPathValidatorException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.PKIXCertPathChecker; import java.security.cert.X509CRL; +import java.security.cert.X509CRLSelector; +import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate; import java.security.cert.X509Extension; +import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -24,47 +26,51 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.Vector; - -import javax.security.auth.x500.X500Principal; +import java.util.TimeZone; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1String; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.style.BCStyle; import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.CRLDistPoint; import org.bouncycastle.asn1.x509.CRLReason; import org.bouncycastle.asn1.x509.DistributionPoint; import org.bouncycastle.asn1.x509.DistributionPointName; +import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.GeneralSubtree; import org.bouncycastle.asn1.x509.IssuingDistributionPoint; import org.bouncycastle.asn1.x509.NameConstraints; import org.bouncycastle.asn1.x509.PolicyInformation; -import org.bouncycastle.asn1.x509.X509Extensions; -import org.bouncycastle.asn1.x509.X509Name; +import org.bouncycastle.jcajce.PKIXCRLStore; +import org.bouncycastle.jcajce.PKIXCRLStoreSelector; +import org.bouncycastle.jcajce.PKIXCertStoreSelector; +import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters; +import org.bouncycastle.jcajce.PKIXExtendedParameters; +import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.jce.PrincipalUtil; import org.bouncycastle.jce.exception.ExtCertPathValidatorException; import org.bouncycastle.util.Arrays; -import org.bouncycastle.x509.ExtendedPKIXBuilderParameters; -import org.bouncycastle.x509.ExtendedPKIXParameters; -import org.bouncycastle.x509.X509CRLStoreSelector; -import org.bouncycastle.x509.X509CertStoreSelector; -public class RFC3280CertPathUtilities +class RFC3280CertPathUtilities { private static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil(); /** * If the complete CRL includes an issuing distribution point (IDP) CRL * extension check the following: - *

    + *

    * (i) If the distribution point name is present in the IDP CRL extension * and the distribution field is present in the DP, then verify that one of * the names in the IDP matches one of the names in the DP. If the @@ -73,17 +79,17 @@ public class RFC3280CertPathUtilities * names in the IDP matches one of the names in the cRLIssuer field of the * DP. *

    - *

    + *

    * (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL * extension, verify that the certificate does not include the basic * constraints extension with the cA boolean asserted. *

    - *

    + *

    * (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL * extension, verify that the certificate includes the basic constraints * extension with the cA boolean asserted. *

    - *

    + *

    * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted. *

    * @@ -131,20 +137,18 @@ public class RFC3280CertPathUtilities ASN1EncodableVector vec = new ASN1EncodableVector(); try { - Enumeration e = ASN1Sequence.getInstance( - ASN1Sequence.fromByteArray(CertPathValidatorUtilities.getIssuerPrincipal(crl) - .getEncoded())).getObjects(); + Enumeration e = ASN1Sequence.getInstance(PrincipalUtils.getIssuerPrincipal(crl)).getObjects(); while (e.hasMoreElements()) { vec.add((ASN1Encodable)e.nextElement()); } } - catch (IOException e) + catch (Exception e) { throw new AnnotatedException("Could not read CRL issuer.", e); } vec.add(dpName.getName()); - names.add(new GeneralName(X509Name.getInstance(new DERSequence(vec)))); + names.add(new GeneralName(X500Name.getInstance(new DERSequence(vec)))); } boolean matches = false; // verify that one of the names in the IDP matches one @@ -168,11 +172,10 @@ public class RFC3280CertPathUtilities genNames = new GeneralName[1]; try { - genNames[0] = new GeneralName(new X509Name( - (ASN1Sequence)ASN1Sequence.fromByteArray(CertPathValidatorUtilities - .getEncodedIssuerPrincipal(cert).getEncoded()))); + genNames[0] = new GeneralName(X500Name.getInstance(PrincipalUtils + .getEncodedIssuerPrincipal(cert).getEncoded())); } - catch (IOException e) + catch (Exception e) { throw new AnnotatedException("Could not read certificate issuer.", e); } @@ -186,7 +189,7 @@ public class RFC3280CertPathUtilities vec.add((ASN1Encodable)e.nextElement()); } vec.add(dpName.getName()); - genNames[j] = new GeneralName(new X509Name(new DERSequence(vec))); + genNames[j] = new GeneralName(X500Name.getInstance(new DERSequence(vec))); } } if (genNames != null) @@ -294,7 +297,16 @@ public class RFC3280CertPathUtilities isIndirect = true; } } - byte[] issuerBytes = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded(); + byte[] issuerBytes; + + try + { + issuerBytes = PrincipalUtils.getIssuerPrincipal(crl).getEncoded(); + } + catch (IOException e) + { + throw new AnnotatedException("Exception encoding CRL issuer: " + e.getMessage(), e); + } boolean matchIssuer = false; if (dp.getCRLIssuer() != null) @@ -329,8 +341,8 @@ public class RFC3280CertPathUtilities } else { - if (CertPathValidatorUtilities.getIssuerPrincipal(crl).equals( - CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert))) + if (PrincipalUtils.getIssuerPrincipal(crl).equals( + PrincipalUtils.getEncodedIssuerPrincipal(cert))) { matchIssuer = true; } @@ -375,33 +387,33 @@ public class RFC3280CertPathUtilities } - public static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId(); + public static final String CERTIFICATE_POLICIES = Extension.certificatePolicies.getId(); - public static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId(); + public static final String POLICY_MAPPINGS = Extension.policyMappings.getId(); - public static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId(); + public static final String INHIBIT_ANY_POLICY = Extension.inhibitAnyPolicy.getId(); - public static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId(); + public static final String ISSUING_DISTRIBUTION_POINT = Extension.issuingDistributionPoint.getId(); - public static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId(); + public static final String FRESHEST_CRL = Extension.freshestCRL.getId(); - public static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId(); + public static final String DELTA_CRL_INDICATOR = Extension.deltaCRLIndicator.getId(); - public static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId(); + public static final String POLICY_CONSTRAINTS = Extension.policyConstraints.getId(); - public static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId(); + public static final String BASIC_CONSTRAINTS = Extension.basicConstraints.getId(); - public static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId(); + public static final String CRL_DISTRIBUTION_POINTS = Extension.cRLDistributionPoints.getId(); - public static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId(); + public static final String SUBJECT_ALTERNATIVE_NAME = Extension.subjectAlternativeName.getId(); - public static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId(); + public static final String NAME_CONSTRAINTS = Extension.nameConstraints.getId(); - public static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId(); + public static final String AUTHORITY_KEY_IDENTIFIER = Extension.authorityKeyIdentifier.getId(); - public static final String KEY_USAGE = X509Extensions.KeyUsage.getId(); + public static final String KEY_USAGE = Extension.keyUsage.getId(); - public static final String CRL_NUMBER = X509Extensions.CRLNumber.getId(); + public static final String CRL_NUMBER = Extension.cRLNumber.getId(); public static final String ANY_POLICY = "2.5.29.32.0"; @@ -436,18 +448,19 @@ public class RFC3280CertPathUtilities Object cert, X509Certificate defaultCRLSignCert, PublicKey defaultCRLSignKey, - ExtendedPKIXParameters paramsPKIX, - List certPathCerts) + PKIXExtendedParameters paramsPKIX, + List certPathCerts, + JcaJceHelper helper) throws AnnotatedException { // (f) // get issuer from CRL - X509CertStoreSelector selector = new X509CertStoreSelector(); + X509CertSelector certSelector = new X509CertSelector(); try { - byte[] issuerPrincipal = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded(); - selector.setSubject(issuerPrincipal); + byte[] issuerPrincipal = PrincipalUtils.getIssuerPrincipal(crl).getEncoded(); + certSelector.setSubject(issuerPrincipal); } catch (IOException e) { @@ -455,12 +468,13 @@ public class RFC3280CertPathUtilities "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e); } + PKIXCertStoreSelector selector = new PKIXCertStoreSelector.Builder(certSelector).build(); + // get CRL signing certs Collection coll; try { - coll = CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getStores()); - coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getAdditionalStores())); + coll = CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertificateStores()); coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertStores())); } catch (AnnotatedException e) @@ -491,13 +505,13 @@ public class RFC3280CertPathUtilities } try { - CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME); - selector = new X509CertStoreSelector(); - selector.setCertificate(signingCert); - ExtendedPKIXParameters temp = (ExtendedPKIXParameters)paramsPKIX.clone(); - temp.setTargetCertConstraints(selector); - ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters)ExtendedPKIXBuilderParameters - .getInstance(temp); + PKIXCertPathBuilderSpi builder = new PKIXCertPathBuilderSpi(); + X509CertSelector tmpCertSelector = new X509CertSelector(); + tmpCertSelector.setCertificate(signingCert); + + PKIXExtendedParameters.Builder paramsBuilder = new PKIXExtendedParameters.Builder(paramsPKIX) + .setTargetConstraints(new PKIXCertStoreSelector.Builder(tmpCertSelector).build()); + /* * if signingCert is placed not higher on the cert path a * dependency loop results. CRL for cert is checked, but @@ -509,19 +523,22 @@ public class RFC3280CertPathUtilities */ if (certPathCerts.contains(signingCert)) { - params.setRevocationEnabled(false); + paramsBuilder.setRevocationEnabled(false); } else { - params.setRevocationEnabled(true); + paramsBuilder.setRevocationEnabled(true); } - List certs = builder.build(params).getCertPath().getCertificates(); + + PKIXExtendedBuilderParameters extParams = new PKIXExtendedBuilderParameters.Builder(paramsBuilder.build()).build(); + + List certs = builder.engineBuild(extParams).getCertPath().getCertificates(); validCerts.add(signingCert); - validKeys.add(CertPathValidatorUtilities.getNextWorkingKey(certs, 0)); + validKeys.add(CertPathValidatorUtilities.getNextWorkingKey(certs, 0, helper)); } catch (CertPathBuilderException e) { - throw new AnnotatedException("Internal error.", e); + throw new AnnotatedException("CertPath for CRL signer failed to validate.", e); } catch (CertPathValidatorException e) { @@ -529,7 +546,7 @@ public class RFC3280CertPathUtilities } catch (Exception e) { - throw new RuntimeException(e.getMessage()); + throw new AnnotatedException(e.getMessage()); } } @@ -616,7 +633,7 @@ public class RFC3280CertPathUtilities protected static Set processCRLA1i( Date currentDate, - ExtendedPKIXParameters paramsPKIX, + PKIXExtendedParameters paramsPKIX, X509Certificate cert, X509CRL crl) throws AnnotatedException @@ -648,19 +665,24 @@ public class RFC3280CertPathUtilities } if (freshestCRL != null) { + List crlStores = new ArrayList(); + + crlStores.addAll(paramsPKIX.getCRLStores()); + try { - CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX); + crlStores.addAll(CertPathValidatorUtilities.getAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX.getNamedCRLStoreMap())); } catch (AnnotatedException e) { throw new AnnotatedException( "No new delta CRL locations could be added from Freshest CRL extension.", e); } + // get delta CRL(s) try { - set.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl)); + set.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, crl, paramsPKIX.getCertStores(), crlStores)); } catch (AnnotatedException e) { @@ -673,33 +695,41 @@ public class RFC3280CertPathUtilities protected static Set[] processCRLA1ii( Date currentDate, - ExtendedPKIXParameters paramsPKIX, + PKIXExtendedParameters paramsPKIX, X509Certificate cert, X509CRL crl) throws AnnotatedException { Set deltaSet = new HashSet(); - X509CRLStoreSelector crlselect = new X509CRLStoreSelector(); + X509CRLSelector crlselect = new X509CRLSelector(); crlselect.setCertificateChecking(cert); try { - crlselect.addIssuerName(crl.getIssuerX500Principal().getEncoded()); + crlselect.addIssuerName(PrincipalUtils.getIssuerPrincipal(crl).getEncoded()); } catch (IOException e) { throw new AnnotatedException("Cannot extract issuer from CRL." + e, e); } - crlselect.setCompleteCRLEnabled(true); - Set completeSet = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate); + PKIXCRLStoreSelector extSelect = new PKIXCRLStoreSelector.Builder(crlselect).setCompleteCRLEnabled(true).build(); + + Date validityDate = currentDate; + + if (paramsPKIX.getDate() != null) + { + validityDate = paramsPKIX.getDate(); + } + + Set completeSet = CRL_UTIL.findCRLs(extSelect, validityDate, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores()); if (paramsPKIX.isUseDeltasEnabled()) { // get delta CRL(s) try { - deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl)); + deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs(validityDate, crl, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores())); } catch (AnnotatedException e) { @@ -725,7 +755,7 @@ public class RFC3280CertPathUtilities protected static void processCRLC( X509CRL deltaCRL, X509CRL completeCRL, - ExtendedPKIXParameters pkixParams) + PKIXExtendedParameters pkixParams) throws AnnotatedException { if (deltaCRL == null) @@ -746,7 +776,7 @@ public class RFC3280CertPathUtilities if (pkixParams.isUseDeltasEnabled()) { // (c) (1) - if (!deltaCRL.getIssuerX500Principal().equals(completeCRL.getIssuerX500Principal())) + if (!PrincipalUtils.getIssuerPrincipal(deltaCRL).equals(PrincipalUtils.getIssuerPrincipal(completeCRL))) { throw new AnnotatedException("Complete CRL issuer does not match delta CRL issuer."); } @@ -833,7 +863,7 @@ public class RFC3280CertPathUtilities X509CRL deltacrl, Object cert, CertStatus certStatus, - ExtendedPKIXParameters pkixParams) + PKIXExtendedParameters pkixParams) throws AnnotatedException { if (pkixParams.isUseDeltasEnabled() && deltacrl != null) @@ -891,8 +921,8 @@ public class RFC3280CertPathUtilities for (int j = 0; j < mappings.size(); j++) { ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j); - String id_p = ((DERObjectIdentifier)mapping.getObjectAt(0)).getId(); - String sd_p = ((DERObjectIdentifier)mapping.getObjectAt(1)).getId(); + String id_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(0)).getId(); + String sd_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(1)).getId(); Set tmp; if (!m_idp.containsKey(id_p)) @@ -1070,14 +1100,14 @@ public class RFC3280CertPathUtilities for (int j = 0; j < mappings.size(); j++) { - DERObjectIdentifier issuerDomainPolicy = null; - DERObjectIdentifier subjectDomainPolicy = null; + ASN1ObjectIdentifier issuerDomainPolicy = null; + ASN1ObjectIdentifier subjectDomainPolicy = null; try { ASN1Sequence mapping = DERSequence.getInstance(mappings.getObjectAt(j)); - issuerDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(0)); - subjectDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(1)); + issuerDomainPolicy = ASN1ObjectIdentifier.getInstance(mapping.getObjectAt(0)); + subjectDomainPolicy = ASN1ObjectIdentifier.getInstance(mapping.getObjectAt(1)); } catch (Exception e) { @@ -1162,13 +1192,12 @@ public class RFC3280CertPathUtilities // if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n))) { - X500Principal principal = CertPathValidatorUtilities.getSubjectPrincipal(cert); - ASN1InputStream aIn = new ASN1InputStream(principal.getEncoded()); + X500Name principal = PrincipalUtils.getSubjectPrincipal(cert); ASN1Sequence dns; try { - dns = DERSequence.getInstance(aIn.readObject()); + dns = DERSequence.getInstance(principal.getEncoded()); } catch (Exception e) { @@ -1198,10 +1227,11 @@ public class RFC3280CertPathUtilities throw new CertPathValidatorException("Subject alternative name extension could not be decoded.", e, certPath, index); } - Vector emails = new X509Name(dns).getValues(X509Name.EmailAddress); - for (Enumeration e = emails.elements(); e.hasMoreElements();) + RDN[] emails = X500Name.getInstance(dns).getRDNs(BCStyle.EmailAddress); + for (int eI = 0; eI != emails.length; eI++) { - String email = (String)e.nextElement(); + // TODO: this should take into account multi-valued RDNs + String email = ((ASN1String)emails[eI].getFirst().getValue()).getString(); GeneralName emailAsGeneralName = new GeneralName(GeneralName.rfc822Name, email); try { @@ -1284,7 +1314,7 @@ public class RFC3280CertPathUtilities while (e.hasMoreElements()) { PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement()); - DERObjectIdentifier pOid = pInfo.getPolicyIdentifier(); + ASN1ObjectIdentifier pOid = pInfo.getPolicyIdentifier(); pols.add(pOid.getId()); @@ -1363,9 +1393,9 @@ public class RFC3280CertPathUtilities { _policy = (String)_tmp; } - else if (_tmp instanceof DERObjectIdentifier) + else if (_tmp instanceof ASN1ObjectIdentifier) { - _policy = ((DERObjectIdentifier)_tmp).getId(); + _policy = ((ASN1ObjectIdentifier)_tmp).getId(); } else { @@ -1448,12 +1478,13 @@ public class RFC3280CertPathUtilities protected static void processCertA( CertPath certPath, - ExtendedPKIXParameters paramsPKIX, + PKIXExtendedParameters paramsPKIX, int index, PublicKey workingPublicKey, boolean verificationAlreadyPerformed, - X500Principal workingIssuerName, - X509Certificate sign) + X500Name workingIssuerName, + X509Certificate sign, + JcaJceHelper helper) throws ExtCertPathValidatorException { List certs = certPath.getCertificates(); @@ -1504,7 +1535,7 @@ public class RFC3280CertPathUtilities try { checkCRLs(paramsPKIX, cert, CertPathValidatorUtilities.getValidCertDateFromValidityModel(paramsPKIX, - certPath, index), sign, workingPublicKey, certs); + certPath, index), sign, workingPublicKey, certs, helper); } catch (AnnotatedException e) { @@ -1520,9 +1551,9 @@ public class RFC3280CertPathUtilities // // (a) (4) name chaining // - if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName)) + if (!PrincipalUtils.getEncodedIssuerPrincipal(cert).equals(workingIssuerName)) { - throw new ExtCertPathValidatorException("IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert) + throw new ExtCertPathValidatorException("IssuerName(" + PrincipalUtils.getEncodedIssuerPrincipal(cert) + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null, certPath, index); } @@ -1565,7 +1596,7 @@ public class RFC3280CertPathUtilities ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement()); if (constraint.getTagNo() == 0) { - tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue(); + tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); if (tmpInt < explicitPolicy) { return tmpInt; @@ -1619,7 +1650,7 @@ public class RFC3280CertPathUtilities ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement()); if (constraint.getTagNo() == 1) { - tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue(); + tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); if (tmpInt < policyMapping) { return tmpInt; @@ -1723,14 +1754,15 @@ public class RFC3280CertPathUtilities */ private static void checkCRL( DistributionPoint dp, - ExtendedPKIXParameters paramsPKIX, + PKIXExtendedParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate defaultCRLSignCert, PublicKey defaultCRLSignKey, CertStatus certStatus, ReasonsMask reasonMask, - List certPathCerts) + List certPathCerts, + JcaJceHelper helper) throws AnnotatedException { Date currentDate = new Date(System.currentTimeMillis()); @@ -1774,16 +1806,23 @@ public class RFC3280CertPathUtilities // (f) Set keys = RFC3280CertPathUtilities.processCRLF(crl, cert, defaultCRLSignCert, defaultCRLSignKey, - paramsPKIX, certPathCerts); + paramsPKIX, certPathCerts, helper); // (g) PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys); X509CRL deltaCRL = null; + Date validityDate = currentDate; + + if (paramsPKIX.getDate() != null) + { + validityDate = paramsPKIX.getDate(); + } + if (paramsPKIX.isUseDeltasEnabled()) { // get delta CRLs - Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl); + Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(validityDate, crl, paramsPKIX.getCertStores(), paramsPKIX.getCRLStores()); // we only want one valid delta CRL // (h) deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs, key); @@ -1802,7 +1841,7 @@ public class RFC3280CertPathUtilities * the CRL validity time */ - if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL) + if (paramsPKIX.getValidityModel() != PKIXExtendedParameters.CHAIN_VALIDITY_MODEL) { /* * if a certificate has expired, but was revoked, it is not @@ -1842,8 +1881,8 @@ public class RFC3280CertPathUtilities if (criticalExtensions != null) { criticalExtensions = new HashSet(criticalExtensions); - criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId()); - criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId()); + criticalExtensions.remove(Extension.issuingDistributionPoint.getId()); + criticalExtensions.remove(Extension.deltaCRLIndicator.getId()); if (!criticalExtensions.isEmpty()) { @@ -1857,8 +1896,8 @@ public class RFC3280CertPathUtilities if (criticalExtensions != null) { criticalExtensions = new HashSet(criticalExtensions); - criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId()); - criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId()); + criticalExtensions.remove(Extension.issuingDistributionPoint.getId()); + criticalExtensions.remove(Extension.deltaCRLIndicator.getId()); if (!criticalExtensions.isEmpty()) { throw new AnnotatedException("Delta CRL contains unsupported critical extension."); @@ -1893,12 +1932,13 @@ public class RFC3280CertPathUtilities * or some error occurs. */ protected static void checkCRLs( - ExtendedPKIXParameters paramsPKIX, + PKIXExtendedParameters paramsPKIX, X509Certificate cert, Date validDate, X509Certificate sign, PublicKey workingPublicKey, - List certPathCerts) + List certPathCerts, + JcaJceHelper helper) throws AnnotatedException { AnnotatedException lastException = null; @@ -1912,9 +1952,15 @@ public class RFC3280CertPathUtilities { throw new AnnotatedException("CRL distribution point extension could not be read.", e); } + + PKIXExtendedParameters.Builder paramsBldr = new PKIXExtendedParameters.Builder(paramsPKIX); try { - CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX); + List extras = CertPathValidatorUtilities.getAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX.getNamedCRLStoreMap()); + for (Iterator it = extras.iterator(); it.hasNext();) + { + paramsBldr.addCRLStore((PKIXCRLStore)it.next()); + } } catch (AnnotatedException e) { @@ -1923,6 +1969,7 @@ public class RFC3280CertPathUtilities } CertStatus certStatus = new CertStatus(); ReasonsMask reasonsMask = new ReasonsMask(); + PKIXExtendedParameters finalParams = paramsBldr.build(); boolean validCrlFound = false; // for each distribution point @@ -1941,10 +1988,9 @@ public class RFC3280CertPathUtilities { for (int i = 0; i < dps.length && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons(); i++) { - ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone(); try { - checkCRL(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts); + checkCRL(dps[i], finalParams, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts, helper); validCrlFound = true; } catch (AnnotatedException e) @@ -1973,7 +2019,7 @@ public class RFC3280CertPathUtilities ASN1Primitive issuer = null; try { - issuer = new ASN1InputStream(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded()) + issuer = new ASN1InputStream(PrincipalUtils.getEncodedIssuerPrincipal(cert).getEncoded()) .readObject(); } catch (Exception e) @@ -1982,9 +2028,9 @@ public class RFC3280CertPathUtilities } DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames( new GeneralName(GeneralName.directoryName, issuer))), null, null); - ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone(); + PKIXExtendedParameters paramsPKIXClone = (PKIXExtendedParameters)paramsPKIX.clone(); checkCRL(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, - certPathCerts); + certPathCerts, helper); validCrlFound = true; } catch (AnnotatedException e) @@ -2004,7 +2050,9 @@ public class RFC3280CertPathUtilities } if (certStatus.getCertStatus() != CertStatus.UNREVOKED) { - String message = "Certificate revocation after " + certStatus.getRevocationDate(); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); + df.setTimeZone(TimeZone.getTimeZone("UTC")); + String message = "Certificate revocation after " + df.format(certStatus.getRevocationDate()); message += ", reason: " + crlReasons[certStatus.getCertStatus()]; throw new AnnotatedException(message); } @@ -2029,10 +2077,10 @@ public class RFC3280CertPathUtilities // // (j) // - DERInteger iap = null; + ASN1Integer iap = null; try { - iap = DERInteger.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, + iap = ASN1Integer.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, RFC3280CertPathUtilities.INHIBIT_ANY_POLICY)); } catch (Exception e) @@ -2335,7 +2383,7 @@ public class RFC3280CertPathUtilities case 0: try { - tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue(); + tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); } catch (Exception e) { @@ -2387,7 +2435,7 @@ public class RFC3280CertPathUtilities protected static PKIXPolicyNode wrapupCertG( CertPath certPath, - ExtendedPKIXParameters paramsPKIX, + PKIXExtendedParameters paramsPKIX, Set userInitialPolicySet, int index, List[] policyNodes, diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java index 7e76a89..d5e2338 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java @@ -24,6 +24,7 @@ import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.TBSCertList; import org.bouncycastle.asn1.x509.X509Extension; +import org.bouncycastle.util.Strings; /** * The following extensions are listed in RFC 2459 as relevant to CRL Entries @@ -259,7 +260,7 @@ public class X509CRLEntryObject extends X509CRLEntry public String toString() { StringBuffer buf = new StringBuffer(); - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl); buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java index b5b4f13..b6885ac 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java @@ -6,6 +6,7 @@ import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Principal; +import java.security.Provider; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; @@ -41,6 +42,7 @@ import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.IssuingDistributionPoint; import org.bouncycastle.asn1.x509.TBSCertList; import org.bouncycastle.jce.X509Principal; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; /** @@ -62,7 +64,7 @@ public class X509CRLObject private boolean isHashCodeSet = false; private int hashCodeValue; - static boolean isIndirectCRL(X509CRL crl) + public static boolean isIndirectCRL(X509CRL crl) throws CRLException { try @@ -201,21 +203,45 @@ public class X509CRLObject } public void verify(PublicKey key) - throws CRLException, NoSuchAlgorithmException, - InvalidKeyException, NoSuchProviderException, SignatureException + throws CRLException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException { - verify(key, BouncyCastleProvider.PROVIDER_NAME); + Signature sig; + + try + { + sig = Signature.getInstance(getSigAlgName(), BouncyCastleProvider.PROVIDER_NAME); + } + catch (Exception e) + { + sig = Signature.getInstance(getSigAlgName()); + } + + doVerify(key, sig); } public void verify(PublicKey key, String sigProvider) throws CRLException, NoSuchAlgorithmException, - InvalidKeyException, NoSuchProviderException, SignatureException + InvalidKeyException, NoSuchProviderException, SignatureException { - if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature())) + Signature sig; + + if (sigProvider != null) { - throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList."); + sig = Signature.getInstance(getSigAlgName(), sigProvider); + } + else + { + sig = Signature.getInstance(getSigAlgName()); } + doVerify(key, sig); + } + + public void verify(PublicKey key, Provider sigProvider) + throws CRLException, NoSuchAlgorithmException, + InvalidKeyException, SignatureException + { Signature sig; if (sigProvider != null) @@ -227,6 +253,18 @@ public class X509CRLObject sig = Signature.getInstance(getSigAlgName()); } + doVerify(key, sig); + } + + private void doVerify(PublicKey key, Signature sig) + throws CRLException, NoSuchAlgorithmException, + InvalidKeyException, SignatureException + { + if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature())) + { + throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList."); + } + sig.initVerify(key); sig.update(this.getTBSCertList()); @@ -353,7 +391,7 @@ public class X509CRLObject public byte[] getSignature() { - return c.getSignature().getBytes(); + return c.getSignature().getOctets(); } public String getSigAlgName() @@ -388,7 +426,7 @@ public class X509CRLObject public String toString() { StringBuffer buf = new StringBuffer(); - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); buf.append(" Version: ").append(this.getVersion()).append( nl); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java index 0ae61d2..09703f4 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java @@ -32,6 +32,7 @@ import java.util.Set; import javax.security.auth.x500.X500Principal; +import org.bouncycastle.asn1.ASN1BitString; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1InputStream; @@ -65,6 +66,7 @@ import org.bouncycastle.jce.X509Principal; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Integers; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; public class X509CertificateObject @@ -104,7 +106,7 @@ public class X509CertificateObject byte[] bytes = this.getExtensionBytes("2.5.29.15"); if (bytes != null) { - DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes)); + ASN1BitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes)); bytes = bits.getBytes(); int length = (bytes.length * 8) - bits.getPadBits(); @@ -234,7 +236,7 @@ public class X509CertificateObject public byte[] getSignature() { - return c.getSignature().getBytes(); + return c.getSignature().getOctets(); } /** @@ -664,7 +666,7 @@ public class X509CertificateObject public String toString() { StringBuffer buf = new StringBuffer(); - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); buf.append(" [0] Version: ").append(this.getVersion()).append(nl); buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl); @@ -783,12 +785,42 @@ public class X509CertificateObject throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { - String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); - Signature signature = Signature.getInstance(sigName, sigProvider); + String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); + Signature signature; + + if (sigProvider != null) + { + signature = Signature.getInstance(sigName, sigProvider); + } + else + { + signature = Signature.getInstance(sigName); + } checkSignature(key, signature); } + public final void verify( + PublicKey key, + Provider sigProvider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, SignatureException + { + String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); + Signature signature; + + if (sigProvider != null) + { + signature = Signature.getInstance(sigName, sigProvider); + } + else + { + signature = Signature.getInstance(sigName); + } + + checkSignature(key, signature); + } + private void checkSignature( PublicKey key, Signature signature) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java index b8b0097..b12b1df 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java @@ -11,9 +11,9 @@ import java.security.spec.PSSParameterSpec; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Null; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERObjectIdentifier; // BEGIN android-removed // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; // END android-removed @@ -69,22 +69,22 @@ class X509SignatureUtil if (params != null && !derNull.equals(params)) { // BEGIN android-removed - // if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + // if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) // { // RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); - // - // return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1"; + // + // return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1"; // } // END android-removed - if (sigAlgId.getObjectId().equals(X9ObjectIdentifiers.ecdsa_with_SHA2)) + if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2)) { ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params); - return getDigestAlgName((DERObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA"; + return getDigestAlgName(ASN1ObjectIdentifier.getInstance(ecDsaParams.getObjectAt(0))) + "withECDSA"; } } - return sigAlgId.getObjectId().getId(); + return sigAlgId.getAlgorithm().getId(); } /** @@ -92,7 +92,7 @@ class X509SignatureUtil * representations rather the the algorithm identifier (if possible). */ private static String getDigestAlgName( - DERObjectIdentifier digestAlgOID) + ASN1ObjectIdentifier digestAlgOID) { if (PKCSObjectIdentifiers.md5.equals(digestAlgOID)) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java index 47416a2..4e749a5 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java @@ -7,9 +7,9 @@ import org.bouncycastle.math.ec.ECPoint; /** * specification signifying that the curve parameters can also be - * refered to by name. + * referred to by name. *

    - * If you are using JDK 1.5 you should be looking at ECNamedCurveSpec. + * If you are using JDK 1.5 you should be looking at {@link ECNamedCurveSpec}. */ public class ECNamedCurveParameterSpec extends ECParameterSpec diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java index b3d239e..36aa595 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java @@ -1,12 +1,18 @@ package org.bouncycastle.jce.spec; import java.math.BigInteger; +import java.security.spec.ECField; import java.security.spec.ECFieldF2m; import java.security.spec.ECFieldFp; import java.security.spec.ECPoint; import java.security.spec.EllipticCurve; +import org.bouncycastle.math.ec.ECAlgorithms; import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.field.FiniteField; +import org.bouncycastle.math.field.Polynomial; +import org.bouncycastle.math.field.PolynomialExtensionField; +import org.bouncycastle.util.Arrays; /** * specification signifying that the curve parameters can also be @@ -21,29 +27,24 @@ public class ECNamedCurveSpec ECCurve curve, byte[] seed) { - if (curve instanceof ECCurve.Fp) + ECField field = convertField(curve.getField()); + BigInteger a = curve.getA().toBigInteger(), b = curve.getB().toBigInteger(); + return new EllipticCurve(field, a, b, seed); + } + + private static ECField convertField(FiniteField field) + { + if (ECAlgorithms.isFpField(field)) { - return new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed); + return new ECFieldFp(field.getCharacteristic()); } - else + else //if (ECAlgorithms.isF2mField(curveField)) { - ECCurve.F2m curveF2m = (ECCurve.F2m)curve; - int ks[]; - - if (curveF2m.isTrinomial()) - { - ks = new int[] { curveF2m.getK1() }; - - return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed); - } - else - { - ks = new int[] { curveF2m.getK3(), curveF2m.getK2(), curveF2m.getK1() }; - - return new EllipticCurve(new ECFieldF2m(curveF2m.getM(), ks), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed); - } + Polynomial poly = ((PolynomialExtensionField)field).getMinimalPolynomial(); + int[] exponents = poly.getExponentsPresent(); + int[] ks = Arrays.reverse(Arrays.copyOfRange(exponents, 1, exponents.length - 1)); + return new ECFieldF2m(poly.getDegree(), ks); } - } private static ECPoint convertPoint( diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/Primes.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/Primes.java new file mode 100644 index 0000000..dc4c017 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/Primes.java @@ -0,0 +1,674 @@ +package org.bouncycastle.math; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + +/** + * Utility methods for generating primes and testing for primality. + */ +public abstract class Primes +{ + public static final int SMALL_FACTOR_LIMIT = 211; + + private static final BigInteger ONE = BigInteger.valueOf(1); + private static final BigInteger TWO = BigInteger.valueOf(2); + private static final BigInteger THREE = BigInteger.valueOf(3); + + /** + * Used to return the output from the + * {@linkplain Primes#enhancedMRProbablePrimeTest(BigInteger, SecureRandom, int) Enhanced + * Miller-Rabin Probabilistic Primality Test} + */ + public static class MROutput + { + private static MROutput probablyPrime() + { + return new MROutput(false, null); + } + + private static MROutput provablyCompositeWithFactor(BigInteger factor) + { + return new MROutput(true, factor); + } + + private static MROutput provablyCompositeNotPrimePower() + { + return new MROutput(true, null); + } + + private boolean provablyComposite; + private BigInteger factor; + + private MROutput(boolean provablyComposite, BigInteger factor) + { + this.provablyComposite = provablyComposite; + this.factor = factor; + } + + public BigInteger getFactor() + { + return factor; + } + + public boolean isProvablyComposite() + { + return provablyComposite; + } + + public boolean isNotPrimePower() + { + return provablyComposite && factor == null; + } + } + + /** + * Used to return the output from the + * {@linkplain Primes#generateSTRandomPrime(Digest, int, byte[]) Shawe-Taylor Random_Prime + * Routine} + */ + public static class STOutput + { + private BigInteger prime; + private byte[] primeSeed; + private int primeGenCounter; + + private STOutput(BigInteger prime, byte[] primeSeed, int primeGenCounter) + { + this.prime = prime; + this.primeSeed = primeSeed; + this.primeGenCounter = primeGenCounter; + } + + public BigInteger getPrime() + { + return prime; + } + + public byte[] getPrimeSeed() + { + return primeSeed; + } + + public int getPrimeGenCounter() + { + return primeGenCounter; + } + } + + /** + * FIPS 186-4 C.6 Shawe-Taylor Random_Prime Routine + * + * Construct a provable prime number using a hash function. + * + * @param hash + * the {@link Digest} instance to use (as "Hash()"). Cannot be null. + * @param length + * the length (in bits) of the prime to be generated. Must be at least 2. + * @param inputSeed + * the seed to be used for the generation of the requested prime. Cannot be null or + * empty. + * @return an {@link STOutput} instance containing the requested prime. + */ + public static STOutput generateSTRandomPrime(Digest hash, int length, byte[] inputSeed) + { + if (hash == null) + { + throw new IllegalArgumentException("'hash' cannot be null"); + } + if (length < 2) + { + throw new IllegalArgumentException("'length' must be >= 2"); + } + if (inputSeed == null || inputSeed.length == 0) + { + throw new IllegalArgumentException("'inputSeed' cannot be null or empty"); + } + + return implSTRandomPrime(hash, length, Arrays.clone(inputSeed)); + } + + /** + * FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test + * + * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an + * alternative to {@link #isMRProbablePrime(BigInteger, SecureRandom, int)} that provides more + * information about a composite candidate, which may be useful when generating or validating + * RSA moduli. + * + * @param candidate + * the {@link BigInteger} instance to test for primality. + * @param random + * the source of randomness to use to choose bases. + * @param iterations + * the number of randomly-chosen bases to perform the test for. + * @return an {@link MROutput} instance that can be further queried for details. + */ + public static MROutput enhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations) + { + checkCandidate(candidate, "candidate"); + + if (random == null) + { + throw new IllegalArgumentException("'random' cannot be null"); + } + if (iterations < 1) + { + throw new IllegalArgumentException("'iterations' must be > 0"); + } + + if (candidate.bitLength() == 2) + { + return MROutput.probablyPrime(); + } + if (!candidate.testBit(0)) + { + return MROutput.provablyCompositeWithFactor(TWO); + } + + BigInteger w = candidate; + BigInteger wSubOne = candidate.subtract(ONE); + BigInteger wSubTwo = candidate.subtract(TWO); + + int a = wSubOne.getLowestSetBit(); + BigInteger m = wSubOne.shiftRight(a); + + for (int i = 0; i < iterations; ++i) + { + BigInteger b = BigIntegers.createRandomInRange(TWO, wSubTwo, random); + BigInteger g = b.gcd(w); + + if (g.compareTo(ONE) > 0) + { + return MROutput.provablyCompositeWithFactor(g); + } + + BigInteger z = b.modPow(m, w); + + if (z.equals(ONE) || z.equals(wSubOne)) + { + continue; + } + + boolean primeToBase = false; + + BigInteger x = z; + for (int j = 1; j < a; ++j) + { + z = z.modPow(TWO, w); + + if (z.equals(wSubOne)) + { + primeToBase = true; + break; + } + + if (z.equals(ONE)) + { + break; + } + + x = z; + } + + if (!primeToBase) + { + if (!z.equals(ONE)) + { + x = z; + z = z.modPow(TWO, w); + + if (!z.equals(ONE)) + { + x = z; + } + } + + g = x.subtract(ONE).gcd(w); + + if (g.compareTo(ONE) > 0) + { + return MROutput.provablyCompositeWithFactor(g); + } + + return MROutput.provablyCompositeNotPrimePower(); + } + } + + return MROutput.probablyPrime(); + } + + /** + * A fast check for small divisors, up to some implementation-specific limit. + * + * @param candidate + * the {@link BigInteger} instance to test for division by small factors. + * + * @return true if the candidate is found to have any small factors, + * false otherwise. + */ + public static boolean hasAnySmallFactors(BigInteger candidate) + { + checkCandidate(candidate, "candidate"); + + return implHasAnySmallFactors(candidate); + } + + /** + * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test + * + * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. + * + * @param candidate + * the {@link BigInteger} instance to test for primality. + * @param random + * the source of randomness to use to choose bases. + * @param iterations + * the number of randomly-chosen bases to perform the test for. + * @return false if any witness to compositeness is found amongst the chosen bases + * (so candidate is definitely NOT prime), or else true + * (indicating primality with some probability dependent on the number of iterations + * that were performed). + */ + public static boolean isMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations) + { + checkCandidate(candidate, "candidate"); + + if (random == null) + { + throw new IllegalArgumentException("'random' cannot be null"); + } + if (iterations < 1) + { + throw new IllegalArgumentException("'iterations' must be > 0"); + } + + if (candidate.bitLength() == 2) + { + return true; + } + if (!candidate.testBit(0)) + { + return false; + } + + BigInteger w = candidate; + BigInteger wSubOne = candidate.subtract(ONE); + BigInteger wSubTwo = candidate.subtract(TWO); + + int a = wSubOne.getLowestSetBit(); + BigInteger m = wSubOne.shiftRight(a); + + for (int i = 0; i < iterations; ++i) + { + BigInteger b = BigIntegers.createRandomInRange(TWO, wSubTwo, random); + + if (!implMRProbablePrimeToBase(w, wSubOne, m, a, b)) + { + return false; + } + } + + return true; + } + + /** + * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base). + * + * Run a single iteration of the Miller-Rabin algorithm against the specified base. + * + * @param candidate + * the {@link BigInteger} instance to test for primality. + * @param base + * the base value to use for this iteration. + * @return false if the specified base is a witness to compositeness (so + * candidate is definitely NOT prime), or else true. + */ + public static boolean isMRProbablePrimeToBase(BigInteger candidate, BigInteger base) + { + checkCandidate(candidate, "candidate"); + checkCandidate(base, "base"); + + if (base.compareTo(candidate.subtract(ONE)) >= 0) + { + throw new IllegalArgumentException("'base' must be < ('candidate' - 1)"); + } + + if (candidate.bitLength() == 2) + { + return true; + } + + BigInteger w = candidate; + BigInteger wSubOne = candidate.subtract(ONE); + + int a = wSubOne.getLowestSetBit(); + BigInteger m = wSubOne.shiftRight(a); + + return implMRProbablePrimeToBase(w, wSubOne, m, a, base); + } + + private static void checkCandidate(BigInteger n, String name) + { + if (n == null || n.signum() < 1 || n.bitLength() < 2) + { + throw new IllegalArgumentException("'" + name + "' must be non-null and >= 2"); + } + } + + private static boolean implHasAnySmallFactors(BigInteger x) + { + /* + * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders. + */ + int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23; + int r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 2) == 0 || (r % 3) == 0 || (r % 5) == 0 || (r % 7) == 0 || (r % 11) == 0 || (r % 13) == 0 + || (r % 17) == 0 || (r % 19) == 0 || (r % 23) == 0) + { + return true; + } + + m = 29 * 31 * 37 * 41 * 43; + r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 29) == 0 || (r % 31) == 0 || (r % 37) == 0 || (r % 41) == 0 || (r % 43) == 0) + { + return true; + } + + m = 47 * 53 * 59 * 61 * 67; + r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 47) == 0 || (r % 53) == 0 || (r % 59) == 0 || (r % 61) == 0 || (r % 67) == 0) + { + return true; + } + + m = 71 * 73 * 79 * 83; + r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 71) == 0 || (r % 73) == 0 || (r % 79) == 0 || (r % 83) == 0) + { + return true; + } + + m = 89 * 97 * 101 * 103; + r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 89) == 0 || (r % 97) == 0 || (r % 101) == 0 || (r % 103) == 0) + { + return true; + } + + m = 107 * 109 * 113 * 127; + r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 107) == 0 || (r % 109) == 0 || (r % 113) == 0 || (r % 127) == 0) + { + return true; + } + + m = 131 * 137 * 139 * 149; + r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 131) == 0 || (r % 137) == 0 || (r % 139) == 0 || (r % 149) == 0) + { + return true; + } + + m = 151 * 157 * 163 * 167; + r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 151) == 0 || (r % 157) == 0 || (r % 163) == 0 || (r % 167) == 0) + { + return true; + } + + m = 173 * 179 * 181 * 191; + r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 173) == 0 || (r % 179) == 0 || (r % 181) == 0 || (r % 191) == 0) + { + return true; + } + + m = 193 * 197 * 199 * 211; + r = x.mod(BigInteger.valueOf(m)).intValue(); + if ((r % 193) == 0 || (r % 197) == 0 || (r % 199) == 0 || (r % 211) == 0) + { + return true; + } + + /* + * NOTE: Unit tests depend on SMALL_FACTOR_LIMIT matching the + * highest small factor tested here. + */ + return false; + } + + private static boolean implMRProbablePrimeToBase(BigInteger w, BigInteger wSubOne, BigInteger m, int a, BigInteger b) + { + BigInteger z = b.modPow(m, w); + + if (z.equals(ONE) || z.equals(wSubOne)) + { + return true; + } + + boolean result = false; + + for (int j = 1; j < a; ++j) + { + z = z.modPow(TWO, w); + + if (z.equals(wSubOne)) + { + result = true; + break; + } + + if (z.equals(ONE)) + { + return false; + } + } + + return result; + } + + private static STOutput implSTRandomPrime(Digest d, int length, byte[] primeSeed) + { + int dLen = d.getDigestSize(); + + if (length < 33) + { + int primeGenCounter = 0; + + byte[] c0 = new byte[dLen]; + byte[] c1 = new byte[dLen]; + + for (;;) + { + hash(d, primeSeed, c0, 0); + inc(primeSeed, 1); + + hash(d, primeSeed, c1, 0); + inc(primeSeed, 1); + + int c = extract32(c0) ^ extract32(c1); + c &= (-1 >>> (32 - length)); + c |= (1 << (length - 1)) | 1; + + ++primeGenCounter; + + long c64 = c & 0xFFFFFFFFL; + if (isPrime32(c64)) + { + return new STOutput(BigInteger.valueOf(c64), primeSeed, primeGenCounter); + } + + if (primeGenCounter > (4 * length)) + { + throw new IllegalStateException("Too many iterations in Shawe-Taylor Random_Prime Routine"); + } + } + } + + STOutput rec = implSTRandomPrime(d, (length + 3) / 2, primeSeed); + + BigInteger c0 = rec.getPrime(); + primeSeed = rec.getPrimeSeed(); + int primeGenCounter = rec.getPrimeGenCounter(); + + int outlen = 8 * dLen; + int iterations = (length - 1) / outlen; + + int oldCounter = primeGenCounter; + + BigInteger x = hashGen(d, primeSeed, iterations + 1); + x = x.mod(ONE.shiftLeft(length - 1)).setBit(length - 1); + + BigInteger c0x2 = c0.shiftLeft(1); + BigInteger tx2 = x.subtract(ONE).divide(c0x2).add(ONE).shiftLeft(1); + int dt = 0; + + BigInteger c = tx2.multiply(c0).add(ONE); + + /* + * TODO Since the candidate primes are generated by constant steps ('c0x2'), sieving could + * be used here in place of the 'hasAnySmallFactors' approach. + */ + for (;;) + { + if (c.bitLength() > length) + { + tx2 = ONE.shiftLeft(length - 1).subtract(ONE).divide(c0x2).add(ONE).shiftLeft(1); + c = tx2.multiply(c0).add(ONE); + } + + ++primeGenCounter; + + /* + * This is an optimization of the original algorithm, using trial division to screen out + * many non-primes quickly. + * + * NOTE: 'primeSeed' is still incremented as if we performed the full check! + */ + if (!implHasAnySmallFactors(c)) + { + BigInteger a = hashGen(d, primeSeed, iterations + 1); + a = a.mod(c.subtract(THREE)).add(TWO); + + tx2 = tx2.add(BigInteger.valueOf(dt)); + dt = 0; + + BigInteger z = a.modPow(tx2, c); + + if (c.gcd(z.subtract(ONE)).equals(ONE) && z.modPow(c0, c).equals(ONE)) + { + return new STOutput(c, primeSeed, primeGenCounter); + } + } + else + { + inc(primeSeed, iterations + 1); + } + + if (primeGenCounter >= ((4 * length) + oldCounter)) + { + throw new IllegalStateException("Too many iterations in Shawe-Taylor Random_Prime Routine"); + } + + dt += 2; + c = c.add(c0x2); + } + } + + private static int extract32(byte[] bs) + { + int result = 0; + + int count = Math.min(4, bs.length); + for (int i = 0; i < count; ++i) + { + int b = bs[bs.length - (i + 1)] & 0xFF; + result |= (b << (8 * i)); + } + + return result; + } + + private static void hash(Digest d, byte[] input, byte[] output, int outPos) + { + d.update(input, 0, input.length); + d.doFinal(output, outPos); + } + + private static BigInteger hashGen(Digest d, byte[] seed, int count) + { + int dLen = d.getDigestSize(); + int pos = count * dLen; + byte[] buf = new byte[pos]; + for (int i = 0; i < count; ++i) + { + pos -= dLen; + hash(d, seed, buf, pos); + inc(seed, 1); + } + return new BigInteger(1, buf); + } + + private static void inc(byte[] seed, int c) + { + int pos = seed.length; + while (c > 0 && --pos >= 0) + { + c += (seed[pos] & 0xFF); + seed[pos] = (byte)c; + c >>>= 8; + } + } + + private static boolean isPrime32(long x) + { + if (x >>> 32 != 0L) + { + throw new IllegalArgumentException("Size limit exceeded"); + } + + /* + * Use wheel factorization with 2, 3, 5 to select trial divisors. + */ + + if (x <= 5L) + { + return x == 2L || x == 3L || x == 5L; + } + + if ((x & 1L) == 0L || (x % 3L) == 0L || (x % 5L) == 0L) + { + return false; + } + + long[] ds = new long[]{ 1L, 7L, 11L, 13L, 17L, 19L, 23L, 29L }; + long base = 0L; + for (int pos = 1;; pos = 0) + { + /* + * Trial division by wheel-selected divisors + */ + while (pos < ds.length) + { + long d = base + ds[pos]; + if (x % d == 0L) + { + return x < 30L; + } + ++pos; + } + + base += 30L; + + if (base * base >= x) + { + return true; + } + } + } +} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java index 69ab797..d1f35c5 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/AbstractECMultiplier.java @@ -13,7 +13,13 @@ public abstract class AbstractECMultiplier implements ECMultiplier } ECPoint positive = multiplyPositive(p, k.abs()); - return sign > 0 ? positive : positive.negate(); + ECPoint result = sign > 0 ? positive : positive.negate(); + + /* + * Although the various multipliers ought not to produce invalid output under normal + * circumstances, a final check here is advised to guard against fault attacks. + */ + return ECAlgorithms.validatePoint(result); } protected abstract ECPoint multiplyPositive(ECPoint p, BigInteger k); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java index d640b5f..f8bf1eb 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java @@ -2,8 +2,71 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; +import org.bouncycastle.math.ec.endo.ECEndomorphism; +import org.bouncycastle.math.ec.endo.GLVEndomorphism; +import org.bouncycastle.math.field.FiniteField; +import org.bouncycastle.math.field.PolynomialExtensionField; + public class ECAlgorithms { + public static boolean isF2mCurve(ECCurve c) + { + return isF2mField(c.getField()); + } + + public static boolean isF2mField(FiniteField field) + { + return field.getDimension() > 1 && field.getCharacteristic().equals(ECConstants.TWO) + && field instanceof PolynomialExtensionField; + } + + public static boolean isFpCurve(ECCurve c) + { + return isFpField(c.getField()); + } + + public static boolean isFpField(FiniteField field) + { + return field.getDimension() == 1; + } + + public static ECPoint sumOfMultiplies(ECPoint[] ps, BigInteger[] ks) + { + if (ps == null || ks == null || ps.length != ks.length || ps.length < 1) + { + throw new IllegalArgumentException("point and scalar arrays should be non-null, and of equal, non-zero, length"); + } + + int count = ps.length; + switch (count) + { + case 1: + return ps[0].multiply(ks[0]); + case 2: + return sumOfTwoMultiplies(ps[0], ks[0], ps[1], ks[1]); + default: + break; + } + + ECPoint p = ps[0]; + ECCurve c = p.getCurve(); + + ECPoint[] imported = new ECPoint[count]; + imported[0] = p; + for (int i = 1; i < count; ++i) + { + imported[i] = importPoint(c, ps[i]); + } + + ECEndomorphism endomorphism = c.getEndomorphism(); + if (endomorphism instanceof GLVEndomorphism) + { + return validatePoint(implSumOfMultipliesGLV(imported, ks, (GLVEndomorphism)endomorphism)); + } + + return validatePoint(implSumOfMultiplies(imported, ks)); + } + public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a, ECPoint Q, BigInteger b) { @@ -11,16 +74,23 @@ public class ECAlgorithms Q = importPoint(cp, Q); // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick - if (cp instanceof ECCurve.F2m) + if (cp instanceof ECCurve.AbstractF2m) { - ECCurve.F2m f2mCurve = (ECCurve.F2m)cp; + ECCurve.AbstractF2m f2mCurve = (ECCurve.AbstractF2m)cp; if (f2mCurve.isKoblitz()) { - return P.multiply(a).add(Q.multiply(b)); + return validatePoint(P.multiply(a).add(Q.multiply(b))); } } - return implShamirsTrick(P, a, Q, b); + ECEndomorphism endomorphism = cp.getEndomorphism(); + if (endomorphism instanceof GLVEndomorphism) + { + return validatePoint( + implSumOfMultipliesGLV(new ECPoint[]{ P, Q }, new BigInteger[]{ a, b }, (GLVEndomorphism)endomorphism)); + } + + return validatePoint(implShamirsTrickWNaf(P, a, Q, b)); } /* @@ -48,7 +118,7 @@ public class ECAlgorithms ECCurve cp = P.getCurve(); Q = importPoint(cp, Q); - return implShamirsTrick(P, k, Q, l); + return validatePoint(implShamirsTrickJsf(P, k, Q, l)); } public static ECPoint importPoint(ECCurve c, ECPoint p) @@ -61,7 +131,12 @@ public class ECAlgorithms return c.importPoint(p); } - static void implMontgomeryTrick(ECFieldElement[] zs, int off, int len) + public static void montgomeryTrick(ECFieldElement[] zs, int off, int len) + { + montgomeryTrick(zs, off, len, null); + } + + public static void montgomeryTrick(ECFieldElement[] zs, int off, int len, ECFieldElement scale) { /* * Uses the "Montgomery Trick" to invert many field elements, with only a single actual @@ -79,7 +154,14 @@ public class ECAlgorithms c[i] = c[i - 1].multiply(zs[off + i]); } - ECFieldElement u = c[--i].invert(); + --i; + + if (scale != null) + { + c[i] = c[i].multiply(scale); + } + + ECFieldElement u = c[i].invert(); while (i > 0) { @@ -92,7 +174,50 @@ public class ECAlgorithms zs[off] = u; } - static ECPoint implShamirsTrick(ECPoint P, BigInteger k, + /** + * Simple shift-and-add multiplication. Serves as reference implementation + * to verify (possibly faster) implementations, and for very small scalars. + * + * @param p + * The point to multiply. + * @param k + * The multiplier. + * @return The result of the point multiplication kP. + */ + public static ECPoint referenceMultiply(ECPoint p, BigInteger k) + { + BigInteger x = k.abs(); + ECPoint q = p.getCurve().getInfinity(); + int t = x.bitLength(); + if (t > 0) + { + if (x.testBit(0)) + { + q = p; + } + for (int i = 1; i < t; i++) + { + p = p.twice(); + if (x.testBit(i)) + { + q = q.add(p); + } + } + } + return k.signum() < 0 ? q.negate() : q; + } + + public static ECPoint validatePoint(ECPoint p) + { + if (!p.isValid()) + { + throw new IllegalArgumentException("Invalid point"); + } + + return p; + } + + static ECPoint implShamirsTrickJsf(ECPoint P, BigInteger k, ECPoint Q, BigInteger l) { ECCurve curve = P.getCurve(); @@ -118,7 +243,9 @@ public class ECAlgorithms while (--i >= 0) { int jsfi = jsf[i]; - int kDigit = (jsfi >> 4), lDigit = ((jsfi << 28) >> 28); + + // NOTE: The shifting ensures the sign is extended correctly + int kDigit = ((jsfi << 24) >> 28), lDigit = ((jsfi << 28) >> 28); int index = 4 + (kDigit * 3) + lDigit; R = R.twicePlus(table[index]); @@ -126,4 +253,238 @@ public class ECAlgorithms return R; } + + static ECPoint implShamirsTrickWNaf(ECPoint P, BigInteger k, + ECPoint Q, BigInteger l) + { + boolean negK = k.signum() < 0, negL = l.signum() < 0; + + k = k.abs(); + l = l.abs(); + + int widthP = Math.max(2, Math.min(16, WNafUtil.getWindowSize(k.bitLength()))); + int widthQ = Math.max(2, Math.min(16, WNafUtil.getWindowSize(l.bitLength()))); + + WNafPreCompInfo infoP = WNafUtil.precompute(P, widthP, true); + WNafPreCompInfo infoQ = WNafUtil.precompute(Q, widthQ, true); + + ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp(); + ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp(); + ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg(); + ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg(); + + byte[] wnafP = WNafUtil.generateWindowNaf(widthP, k); + byte[] wnafQ = WNafUtil.generateWindowNaf(widthQ, l); + + return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ); + } + + static ECPoint implShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l) + { + boolean negK = k.signum() < 0, negL = l.signum() < 0; + + k = k.abs(); + l = l.abs(); + + int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(k.bitLength(), l.bitLength())))); + + ECPoint Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMapQ); + WNafPreCompInfo infoP = WNafUtil.getWNafPreCompInfo(P); + WNafPreCompInfo infoQ = WNafUtil.getWNafPreCompInfo(Q); + + ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp(); + ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp(); + ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg(); + ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg(); + + byte[] wnafP = WNafUtil.generateWindowNaf(width, k); + byte[] wnafQ = WNafUtil.generateWindowNaf(width, l); + + return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ); + } + + private static ECPoint implShamirsTrickWNaf(ECPoint[] preCompP, ECPoint[] preCompNegP, byte[] wnafP, + ECPoint[] preCompQ, ECPoint[] preCompNegQ, byte[] wnafQ) + { + int len = Math.max(wnafP.length, wnafQ.length); + + ECCurve curve = preCompP[0].getCurve(); + ECPoint infinity = curve.getInfinity(); + + ECPoint R = infinity; + int zeroes = 0; + + for (int i = len - 1; i >= 0; --i) + { + int wiP = i < wnafP.length ? wnafP[i] : 0; + int wiQ = i < wnafQ.length ? wnafQ[i] : 0; + + if ((wiP | wiQ) == 0) + { + ++zeroes; + continue; + } + + ECPoint r = infinity; + if (wiP != 0) + { + int nP = Math.abs(wiP); + ECPoint[] tableP = wiP < 0 ? preCompNegP : preCompP; + r = r.add(tableP[nP >>> 1]); + } + if (wiQ != 0) + { + int nQ = Math.abs(wiQ); + ECPoint[] tableQ = wiQ < 0 ? preCompNegQ : preCompQ; + r = r.add(tableQ[nQ >>> 1]); + } + + if (zeroes > 0) + { + R = R.timesPow2(zeroes); + zeroes = 0; + } + + R = R.twicePlus(r); + } + + if (zeroes > 0) + { + R = R.timesPow2(zeroes); + } + + return R; + } + + static ECPoint implSumOfMultiplies(ECPoint[] ps, BigInteger[] ks) + { + int count = ps.length; + boolean[] negs = new boolean[count]; + WNafPreCompInfo[] infos = new WNafPreCompInfo[count]; + byte[][] wnafs = new byte[count][]; + + for (int i = 0; i < count; ++i) + { + BigInteger ki = ks[i]; negs[i] = ki.signum() < 0; ki = ki.abs(); + + int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(ki.bitLength()))); + infos[i] = WNafUtil.precompute(ps[i], width, true); + wnafs[i] = WNafUtil.generateWindowNaf(width, ki); + } + + return implSumOfMultiplies(negs, infos, wnafs); + } + + static ECPoint implSumOfMultipliesGLV(ECPoint[] ps, BigInteger[] ks, GLVEndomorphism glvEndomorphism) + { + BigInteger n = ps[0].getCurve().getOrder(); + + int len = ps.length; + + BigInteger[] abs = new BigInteger[len << 1]; + for (int i = 0, j = 0; i < len; ++i) + { + BigInteger[] ab = glvEndomorphism.decomposeScalar(ks[i].mod(n)); + abs[j++] = ab[0]; + abs[j++] = ab[1]; + } + + ECPointMap pointMap = glvEndomorphism.getPointMap(); + if (glvEndomorphism.hasEfficientPointMap()) + { + return ECAlgorithms.implSumOfMultiplies(ps, pointMap, abs); + } + + ECPoint[] pqs = new ECPoint[len << 1]; + for (int i = 0, j = 0; i < len; ++i) + { + ECPoint p = ps[i], q = pointMap.map(p); + pqs[j++] = p; + pqs[j++] = q; + } + + return ECAlgorithms.implSumOfMultiplies(pqs, abs); + + } + + static ECPoint implSumOfMultiplies(ECPoint[] ps, ECPointMap pointMap, BigInteger[] ks) + { + int halfCount = ps.length, fullCount = halfCount << 1; + + boolean[] negs = new boolean[fullCount]; + WNafPreCompInfo[] infos = new WNafPreCompInfo[fullCount]; + byte[][] wnafs = new byte[fullCount][]; + + for (int i = 0; i < halfCount; ++i) + { + int j0 = i << 1, j1 = j0 + 1; + + BigInteger kj0 = ks[j0]; negs[j0] = kj0.signum() < 0; kj0 = kj0.abs(); + BigInteger kj1 = ks[j1]; negs[j1] = kj1.signum() < 0; kj1 = kj1.abs(); + + int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(kj0.bitLength(), kj1.bitLength())))); + + ECPoint P = ps[i], Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMap); + infos[j0] = WNafUtil.getWNafPreCompInfo(P); + infos[j1] = WNafUtil.getWNafPreCompInfo(Q); + wnafs[j0] = WNafUtil.generateWindowNaf(width, kj0); + wnafs[j1] = WNafUtil.generateWindowNaf(width, kj1); + } + + return implSumOfMultiplies(negs, infos, wnafs); + } + + private static ECPoint implSumOfMultiplies(boolean[] negs, WNafPreCompInfo[] infos, byte[][] wnafs) + { + int len = 0, count = wnafs.length; + for (int i = 0; i < count; ++i) + { + len = Math.max(len, wnafs[i].length); + } + + ECCurve curve = infos[0].getPreComp()[0].getCurve(); + ECPoint infinity = curve.getInfinity(); + + ECPoint R = infinity; + int zeroes = 0; + + for (int i = len - 1; i >= 0; --i) + { + ECPoint r = infinity; + + for (int j = 0; j < count; ++j) + { + byte[] wnaf = wnafs[j]; + int wi = i < wnaf.length ? wnaf[i] : 0; + if (wi != 0) + { + int n = Math.abs(wi); + WNafPreCompInfo info = infos[j]; + ECPoint[] table = (wi < 0 == negs[j]) ? info.getPreComp() : info.getPreCompNeg(); + r = r.add(table[n >>> 1]); + } + } + + if (r == infinity) + { + ++zeroes; + continue; + } + + if (zeroes > 0) + { + R = R.timesPow2(zeroes); + zeroes = 0; + } + + R = R.twicePlus(r); + } + + if (zeroes > 0) + { + R = R.timesPow2(zeroes); + } + + return R; + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECConstants.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECConstants.java index 864f746..53e60f7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECConstants.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECConstants.java @@ -9,4 +9,5 @@ public interface ECConstants public static final BigInteger TWO = BigInteger.valueOf(2); public static final BigInteger THREE = BigInteger.valueOf(3); public static final BigInteger FOUR = BigInteger.valueOf(4); + public static final BigInteger EIGHT = BigInteger.valueOf(8); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java index 19f0062..7f3197b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java @@ -1,9 +1,15 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; +import java.util.Hashtable; import java.util.Random; +import org.bouncycastle.math.ec.endo.ECEndomorphism; +import org.bouncycastle.math.ec.endo.GLVEndomorphism; +import org.bouncycastle.math.field.FiniteField; +import org.bouncycastle.math.field.FiniteFields; import org.bouncycastle.util.BigIntegers; +import org.bouncycastle.util.Integers; /** * base class for an elliptic curve @@ -28,11 +34,13 @@ public abstract class ECCurve public class Config { protected int coord; + protected ECEndomorphism endomorphism; protected ECMultiplier multiplier; - Config(int coord, ECMultiplier multiplier) + Config(int coord, ECEndomorphism endomorphism, ECMultiplier multiplier) { this.coord = coord; + this.endomorphism = endomorphism; this.multiplier = multiplier; } @@ -42,6 +50,12 @@ public abstract class ECCurve return this; } + public Config setEndomorphism(ECEndomorphism endomorphism) + { + this.endomorphism = endomorphism; + return this; + } + public Config setMultiplier(ECMultiplier multiplier) { this.multiplier = multiplier; @@ -61,24 +75,64 @@ public abstract class ECCurve throw new IllegalStateException("implementation returned current curve"); } - c.coord = coord; - c.multiplier = multiplier; + // NOTE: Synchronization added to keep FindBugsâ„¢ happy + synchronized (c) + { + c.coord = coord; + c.endomorphism = endomorphism; + c.multiplier = multiplier; + } return c; } } + protected FiniteField field; protected ECFieldElement a, b; + protected BigInteger order, cofactor; + protected int coord = COORD_AFFINE; + protected ECEndomorphism endomorphism = null; protected ECMultiplier multiplier = null; + protected ECCurve(FiniteField field) + { + this.field = field; + } + public abstract int getFieldSize(); public abstract ECFieldElement fromBigInteger(BigInteger x); - public Config configure() + public abstract boolean isValidFieldElement(BigInteger x); + + public synchronized Config configure() + { + return new Config(this.coord, this.endomorphism, this.multiplier); + } + + public ECPoint validatePoint(BigInteger x, BigInteger y) { - return new Config(this.coord, this.multiplier); + ECPoint p = createPoint(x, y); + if (!p.isValid()) + { + throw new IllegalArgumentException("Invalid point coordinates"); + } + return p; + } + + /** + * @deprecated per-point compression property will be removed, use {@link #validatePoint(BigInteger, BigInteger)} + * and refer {@link ECPoint#getEncoded(boolean)} + */ + public ECPoint validatePoint(BigInteger x, BigInteger y, boolean withCompression) + { + ECPoint p = createPoint(x, y, withCompression); + if (!p.isValid()) + { + throw new IllegalArgumentException("Invalid point coordinates"); + } + return p; } public ECPoint createPoint(BigInteger x, BigInteger y) @@ -99,8 +153,15 @@ public abstract class ECCurve protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression); + protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression); + protected ECMultiplier createDefaultMultiplier() { + if (endomorphism instanceof GLVEndomorphism) + { + return new GLVMultiplier(this, (GLVEndomorphism)endomorphism); + } + return new WNafL2RMultiplier(); } @@ -109,26 +170,40 @@ public abstract class ECCurve return coord == COORD_AFFINE; } - public PreCompInfo getPreCompInfo(ECPoint p) + public PreCompInfo getPreCompInfo(ECPoint point, String name) { - checkPoint(p); - return p.preCompInfo; + checkPoint(point); + synchronized (point) + { + Hashtable table = point.preCompTable; + return table == null ? null : (PreCompInfo)table.get(name); + } } /** - * Sets the PreCompInfo for a point on this curve. Used by + * Adds PreCompInfo for a point on this curve, under a given name. Used by * ECMultipliers to save the precomputation for this ECPoint for use * by subsequent multiplication. * * @param point * The ECPoint to store precomputations for. + * @param name + * A String used to index precomputations of different types. * @param preCompInfo * The values precomputed by the ECMultiplier. */ - public void setPreCompInfo(ECPoint point, PreCompInfo preCompInfo) + public void setPreCompInfo(ECPoint point, String name, PreCompInfo preCompInfo) { checkPoint(point); - point.preCompInfo = preCompInfo; + synchronized (point) + { + Hashtable table = point.preCompTable; + if (null == table) + { + point.preCompTable = table = new Hashtable(4); + } + table.put(name, preCompInfo); + } } public ECPoint importPoint(ECPoint p) @@ -145,7 +220,7 @@ public abstract class ECCurve // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates. p = p.normalize(); - return createPoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression); + return validatePoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression); } /** @@ -160,26 +235,57 @@ public abstract class ECCurve */ public void normalizeAll(ECPoint[] points) { - checkPoints(points); + normalizeAll(points, 0, points.length, null); + } + + /** + * Normalization ensures that any projective coordinate is 1, and therefore that the x, y + * coordinates reflect those of the equivalent point in an affine coordinate system. Where more + * than one point is to be normalized, this method will generally be more efficient than + * normalizing each point separately. An (optional) z-scaling factor can be applied; effectively + * each z coordinate is scaled by this value prior to normalization (but only one + * actual multiplication is needed). + * + * @param points + * An array of points that will be updated in place with their normalized versions, + * where necessary + * @param off + * The start of the range of points to normalize + * @param len + * The length of the range of points to normalize + * @param iso + * The (optional) z-scaling factor - can be null + */ + public void normalizeAll(ECPoint[] points, int off, int len, ECFieldElement iso) + { + checkPoints(points, off, len); - if (this.getCoordinateSystem() == ECCurve.COORD_AFFINE) + switch (this.getCoordinateSystem()) { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + { + if (iso != null) + { + throw new IllegalArgumentException("'iso' not valid for affine coordinates"); + } return; } + } /* * Figure out which of the points actually need to be normalized */ - ECFieldElement[] zs = new ECFieldElement[points.length]; - int[] indices = new int[points.length]; + ECFieldElement[] zs = new ECFieldElement[len]; + int[] indices = new int[len]; int count = 0; - for (int i = 0; i < points.length; ++i) + for (int i = 0; i < len; ++i) { - ECPoint p = points[i]; - if (null != p && !p.isNormalized()) + ECPoint p = points[off + i]; + if (null != p && (iso != null || !p.isNormalized())) { zs[count] = p.getZCoord(0); - indices[count++] = i; + indices[count++] = off + i; } } @@ -188,7 +294,7 @@ public abstract class ECCurve return; } - ECAlgorithms.implMontgomeryTrick(zs, 0, count); + ECAlgorithms.montgomeryTrick(zs, 0, count, iso); for (int j = 0; j < count; ++j) { @@ -199,6 +305,11 @@ public abstract class ECCurve public abstract ECPoint getInfinity(); + public FiniteField getField() + { + return field; + } + public ECFieldElement getA() { return a; @@ -209,6 +320,16 @@ public abstract class ECCurve return b; } + public BigInteger getOrder() + { + return order; + } + + public BigInteger getCofactor() + { + return cofactor; + } + public int getCoordinateSystem() { return coord; @@ -216,10 +337,15 @@ public abstract class ECCurve protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1); + public ECEndomorphism getEndomorphism() + { + return endomorphism; + } + /** * Sets the default ECMultiplier, unless already set. */ - public ECMultiplier getMultiplier() + public synchronized ECMultiplier getMultiplier() { if (this.multiplier == null) { @@ -239,7 +365,8 @@ public abstract class ECCurve ECPoint p = null; int expectedLength = (getFieldSize() + 7) / 8; - switch (encoded[0]) + byte type = encoded[0]; + switch (type) { case 0x00: // infinity { @@ -259,29 +386,56 @@ public abstract class ECCurve throw new IllegalArgumentException("Incorrect length for compressed encoding"); } - int yTilde = encoded[0] & 1; + int yTilde = type & 1; BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); p = decompressPoint(yTilde, X); + if (!p.satisfiesCofactor()) + { + throw new IllegalArgumentException("Invalid point"); + } + break; } case 0x04: // uncompressed + { + if (encoded.length != (2 * expectedLength + 1)) + { + throw new IllegalArgumentException("Incorrect length for uncompressed encoding"); + } + + BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); + BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength); + + p = validatePoint(X, Y); + break; + } case 0x06: // hybrid case 0x07: // hybrid { if (encoded.length != (2 * expectedLength + 1)) { - throw new IllegalArgumentException("Incorrect length for uncompressed/hybrid encoding"); + throw new IllegalArgumentException("Incorrect length for hybrid encoding"); } BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); BigInteger Y = BigIntegers.fromUnsignedByteArray(encoded, 1 + expectedLength, expectedLength); - p = createPoint(X, Y); + if (Y.testBit(0) != (type == 0x07)) + { + throw new IllegalArgumentException("Inconsistent Y coordinate in hybrid encoding"); + } + + p = validatePoint(X, Y); break; } default: - throw new IllegalArgumentException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16)); + throw new IllegalArgumentException("Invalid point encoding 0x" + Integer.toString(type, 16)); + } + + if (type != 0x00 && p.isInfinity()) + { + throw new IllegalArgumentException("Invalid infinity encoding"); } return p; @@ -296,15 +450,24 @@ public abstract class ECCurve } protected void checkPoints(ECPoint[] points) + { + checkPoints(points, 0, points.length); + } + + protected void checkPoints(ECPoint[] points, int off, int len) { if (points == null) { throw new IllegalArgumentException("'points' cannot be null"); } + if (off < 0 || len < 0 || (off > (points.length - len))) + { + throw new IllegalArgumentException("invalid range specified for 'points'"); + } - for (int i = 0; i < points.length; ++i) + for (int i = 0; i < len; ++i) { - ECPoint point = points[i]; + ECPoint point = points[off + i]; if (null != point && this != point.getCurve()) { throw new IllegalArgumentException("'points' entries must be null or on this curve"); @@ -312,51 +475,126 @@ public abstract class ECCurve } } + public boolean equals(ECCurve other) + { + return this == other + || (null != other + && getField().equals(other.getField()) + && getA().toBigInteger().equals(other.getA().toBigInteger()) + && getB().toBigInteger().equals(other.getB().toBigInteger())); + } + + public boolean equals(Object obj) + { + return this == obj || (obj instanceof ECCurve && equals((ECCurve)obj)); + } + + public int hashCode() + { + return getField().hashCode() + ^ Integers.rotateLeft(getA().toBigInteger().hashCode(), 8) + ^ Integers.rotateLeft(getB().toBigInteger().hashCode(), 16); + } + + public static abstract class AbstractFp extends ECCurve + { + protected AbstractFp(BigInteger q) + { + super(FiniteFields.getPrimeField(q)); + } + + public boolean isValidFieldElement(BigInteger x) + { + return x != null && x.signum() >= 0 && x.compareTo(this.getField().getCharacteristic()) < 0; + } + + protected ECPoint decompressPoint(int yTilde, BigInteger X1) + { + ECFieldElement x = this.fromBigInteger(X1); + ECFieldElement rhs = x.square().add(this.a).multiply(x).add(this.b); + ECFieldElement y = rhs.sqrt(); + + /* + * If y is not a square, then we haven't got a point on the curve + */ + if (y == null) + { + throw new IllegalArgumentException("Invalid point compression"); + } + + if (y.testBitZero() != (yTilde == 1)) + { + // Use the other root + y = y.negate(); + } + + return this.createRawPoint(x, y, true); + } + } + /** * Elliptic curve over Fp */ - public static class Fp extends ECCurve + public static class Fp extends AbstractFp { - private static final int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED; + private static final int FP_DEFAULT_COORDS = ECCurve.COORD_JACOBIAN_MODIFIED; BigInteger q, r; ECPoint.Fp infinity; public Fp(BigInteger q, BigInteger a, BigInteger b) { + this(q, a, b, null, null); + } + + public Fp(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor) + { + super(q); + this.q = q; this.r = ECFieldElement.Fp.calculateResidue(q); this.infinity = new ECPoint.Fp(this, null, null); this.a = fromBigInteger(a); this.b = fromBigInteger(b); + this.order = order; + this.cofactor = cofactor; this.coord = FP_DEFAULT_COORDS; } protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b) { + this(q, r, a, b, null, null); + } + + protected Fp(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor) + { + super(q); + this.q = q; this.r = r; this.infinity = new ECPoint.Fp(this, null, null); this.a = a; this.b = b; + this.order = order; + this.cofactor = cofactor; this.coord = FP_DEFAULT_COORDS; } protected ECCurve cloneCurve() { - return new Fp(q, r, a, b); + return new Fp(this.q, this.r, this.a, this.b, this.order, this.cofactor); } public boolean supportsCoordinateSystem(int coord) { switch (coord) { - case COORD_AFFINE: - case COORD_HOMOGENEOUS: - case COORD_JACOBIAN: - case COORD_JACOBIAN_MODIFIED: + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_MODIFIED: return true; default: return false; @@ -383,15 +621,20 @@ public abstract class ECCurve return new ECPoint.Fp(this, x, y, withCompression); } + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new ECPoint.Fp(this, x, y, zs, withCompression); + } + public ECPoint importPoint(ECPoint p) { - if (this != p.getCurve() && this.getCoordinateSystem() == COORD_JACOBIAN && !p.isInfinity()) + if (this != p.getCurve() && this.getCoordinateSystem() == ECCurve.COORD_JACOBIAN && !p.isInfinity()) { switch (p.getCurve().getCoordinateSystem()) { - case COORD_JACOBIAN: - case COORD_JACOBIAN_CHUDNOVSKY: - case COORD_JACOBIAN_MODIFIED: + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: return new ECPoint.Fp(this, fromBigInteger(p.x.toBigInteger()), fromBigInteger(p.y.toBigInteger()), @@ -405,58 +648,226 @@ public abstract class ECCurve return super.importPoint(p); } - protected ECPoint decompressPoint(int yTilde, BigInteger X1) + public ECPoint getInfinity() + { + return infinity; + } + } + + public static abstract class AbstractF2m extends ECCurve + { + public static BigInteger inverse(int m, int[] ks, BigInteger x) + { + return new LongArray(x).modInverse(m, ks).toBigInteger(); + } + + /** + * The auxiliary values s0 and + * s1 used for partial modular reduction for + * Koblitz curves. + */ + private BigInteger[] si = null; + + private static FiniteField buildField(int m, int k1, int k2, int k3) { - ECFieldElement x = fromBigInteger(X1); - ECFieldElement alpha = x.multiply(x.square().add(a)).add(b); - ECFieldElement beta = alpha.sqrt(); + if (k1 == 0) + { + throw new IllegalArgumentException("k1 must be > 0"); + } + + if (k2 == 0) + { + if (k3 != 0) + { + throw new IllegalArgumentException("k3 must be 0 if k2 == 0"); + } - // - // if we can't find a sqrt we haven't got a point on the - // curve - run! - // - if (beta == null) + return FiniteFields.getBinaryExtensionField(new int[]{ 0, k1, m }); + } + + if (k2 <= k1) { - throw new RuntimeException("Invalid point compression"); + throw new IllegalArgumentException("k2 must be > k1"); } - BigInteger betaValue = beta.toBigInteger(); - if (betaValue.testBit(0) != (yTilde == 1)) + if (k3 <= k2) { - // Use the other root - beta = fromBigInteger(q.subtract(betaValue)); + throw new IllegalArgumentException("k3 must be > k2"); } - return new ECPoint.Fp(this, x, beta, true); + return FiniteFields.getBinaryExtensionField(new int[]{ 0, k1, k2, k3, m }); } - public ECPoint getInfinity() + protected AbstractF2m(int m, int k1, int k2, int k3) { - return infinity; + super(buildField(m, k1, k2, k3)); } - public boolean equals( - Object anObject) + public boolean isValidFieldElement(BigInteger x) { - if (anObject == this) + return x != null && x.signum() >= 0 && x.bitLength() <= this.getFieldSize(); + } + + public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) + { + ECFieldElement X = this.fromBigInteger(x), Y = this.fromBigInteger(y); + + int coord = this.getCoordinateSystem(); + + switch (coord) { - return true; + case ECCurve.COORD_LAMBDA_AFFINE: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + if (X.isZero()) + { + if (!Y.square().equals(this.getB())) + { + throw new IllegalArgumentException(); + } + } + /* + * NOTE: A division could be avoided using a projective result, except at present + * callers will expect that the result is already normalized. + */ +// else if (coord == COORD_LAMBDA_PROJECTIVE) +// { +// ECFieldElement Z = X; +// X = X.square(); +// Y = Y.add(X); +// return createRawPoint(X, Y, new ECFieldElement[]{ Z }, withCompression); +// } + else + { + // Y becomes Lambda (X + Y/X) here + Y = Y.divide(X).add(X); + } + break; + } + default: + { + break; } + } + + return this.createRawPoint(X, Y, withCompression); + } - if (!(anObject instanceof ECCurve.Fp)) + /** + * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). + * + * @param yTilde + * ~yp, an indication bit for the decompression of yp. + * @param X1 + * The field element xp. + * @return the decompressed point. + */ + protected ECPoint decompressPoint(int yTilde, BigInteger X1) + { + ECFieldElement x = this.fromBigInteger(X1), y = null; + if (x.isZero()) { - return false; + y = this.getB().sqrt(); + } + else + { + ECFieldElement beta = x.square().invert().multiply(this.getB()).add(this.getA()).add(x); + ECFieldElement z = solveQuadraticEquation(beta); + if (z != null) + { + if (z.testBitZero() != (yTilde == 1)) + { + z = z.addOne(); + } + + switch (this.getCoordinateSystem()) + { + case ECCurve.COORD_LAMBDA_AFFINE: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + y = z.add(x); + break; + } + default: + { + y = z.multiply(x); + break; + } + } + } } - ECCurve.Fp other = (ECCurve.Fp) anObject; + if (y == null) + { + throw new IllegalArgumentException("Invalid point compression"); + } - return this.q.equals(other.q) - && a.equals(other.a) && b.equals(other.b); + return this.createRawPoint(x, y, true); } - public int hashCode() + /** + * Solves a quadratic equation z2 + z = beta(X9.62 + * D.1.6) The other solution is z + 1. + * + * @param beta + * The value to solve the quadratic equation for. + * @return the solution for z2 + z = beta or + * null if no solution exists. + */ + private ECFieldElement solveQuadraticEquation(ECFieldElement beta) { - return a.hashCode() ^ b.hashCode() ^ q.hashCode(); + if (beta.isZero()) + { + return beta; + } + + ECFieldElement gamma, z, zeroElement = this.fromBigInteger(ECConstants.ZERO); + + int m = this.getFieldSize(); + Random rand = new Random(); + do + { + ECFieldElement t = this.fromBigInteger(new BigInteger(m, rand)); + z = zeroElement; + ECFieldElement w = beta; + for (int i = 1; i < m; i++) + { + ECFieldElement w2 = w.square(); + z = z.square().add(w2.multiply(t)); + w = w2.add(beta); + } + if (!w.isZero()) + { + return null; + } + gamma = z.square().add(z); + } + while (gamma.isZero()); + + return z; + } + + /** + * @return the auxiliary values s0 and + * s1 used for partial modular reduction for + * Koblitz curves. + */ + synchronized BigInteger[] getSi() + { + if (si == null) + { + si = Tnaf.getSi(this); + } + return si; + } + + /** + * Returns true if this is a Koblitz curve (ABC curve). + * @return true if this is a Koblitz curve (ABC curve), false otherwise + */ + public boolean isKoblitz() + { + return this.order != null && this.cofactor != null && this.b.isOne() && (this.a.isZero() || this.a.isOne()); } } @@ -464,9 +875,9 @@ public abstract class ECCurve * Elliptic curves over F2m. The Weierstrass equation is given by * y2 + xy = x3 + ax2 + b. */ - public static class F2m extends ECCurve + public static class F2m extends AbstractF2m { - private static final int F2M_DEFAULT_COORDS = COORD_AFFINE; + private static final int F2M_DEFAULT_COORDS = ECCurve.COORD_LAMBDA_PROJECTIVE; /** * The exponent m of F2m. @@ -498,35 +909,12 @@ public abstract class ECCurve * represents the reduction polynomial f(z).
    */ private int k3; // can't be final - JDK 1.1 - - /** - * The order of the base point of the curve. - */ - private BigInteger n; // can't be final - JDK 1.1 - - /** - * The cofactor of the curve. - */ - private BigInteger h; // can't be final - JDK 1.1 /** * The point at infinity on this curve. */ private ECPoint.F2m infinity; // can't be final - JDK 1.1 - /** - * The parameter μ of the elliptic curve if this is - * a Koblitz curve. - */ - private byte mu = 0; - - /** - * The auxiliary values s0 and - * s1 used for partial modular reduction for - * Koblitz curves. - */ - private BigInteger[] si = null; - /** * Constructor for Trinomial Polynomial Basis (TPB). * @param m The exponent m of @@ -563,8 +951,8 @@ public abstract class ECCurve * @param b The coefficient b in the Weierstrass equation * for non-supersingular elliptic curves over * F2m. - * @param n The order of the main subgroup of the elliptic curve. - * @param h The cofactor of the elliptic curve, i.e. + * @param order The order of the main subgroup of the elliptic curve. + * @param cofactor The cofactor of the elliptic curve, i.e. * #Ea(F2m) = h * n. */ public F2m( @@ -572,10 +960,10 @@ public abstract class ECCurve int k, BigInteger a, BigInteger b, - BigInteger n, - BigInteger h) + BigInteger order, + BigInteger cofactor) { - this(m, k, 0, 0, a, b, n, h); + this(m, k, 0, 0, a, b, order, cofactor); } /** @@ -628,8 +1016,8 @@ public abstract class ECCurve * @param b The coefficient b in the Weierstrass equation * for non-supersingular elliptic curves over * F2m. - * @param n The order of the main subgroup of the elliptic curve. - * @param h The cofactor of the elliptic curve, i.e. + * @param order The order of the main subgroup of the elliptic curve. + * @param cofactor The cofactor of the elliptic curve, i.e. * #Ea(F2m) = h * n. */ public F2m( @@ -639,40 +1027,17 @@ public abstract class ECCurve int k3, BigInteger a, BigInteger b, - BigInteger n, - BigInteger h) + BigInteger order, + BigInteger cofactor) { + super(m, k1, k2, k3); + this.m = m; this.k1 = k1; this.k2 = k2; this.k3 = k3; - this.n = n; - this.h = h; - - if (k1 == 0) - { - throw new IllegalArgumentException("k1 must be > 0"); - } - - if (k2 == 0) - { - if (k3 != 0) - { - throw new IllegalArgumentException("k3 must be 0 if k2 == 0"); - } - } - else - { - if (k2 <= k1) - { - throw new IllegalArgumentException("k2 must be > k1"); - } - - if (k3 <= k2) - { - throw new IllegalArgumentException("k3 must be > k2"); - } - } + this.order = order; + this.cofactor = cofactor; this.infinity = new ECPoint.F2m(this, null, null); this.a = fromBigInteger(a); @@ -680,14 +1045,16 @@ public abstract class ECCurve this.coord = F2M_DEFAULT_COORDS; } - protected F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger n, BigInteger h) + protected F2m(int m, int k1, int k2, int k3, ECFieldElement a, ECFieldElement b, BigInteger order, BigInteger cofactor) { + super(m, k1, k2, k3); + this.m = m; this.k1 = k1; this.k2 = k2; this.k3 = k3; - this.n = n; - this.h = h; + this.order = order; + this.cofactor = cofactor; this.infinity = new ECPoint.F2m(this, null, null); this.a = a; @@ -697,16 +1064,16 @@ public abstract class ECCurve protected ECCurve cloneCurve() { - return new F2m(m, k1, k2, k3, a, b, n, h); + return new F2m(this.m, this.k1, this.k2, this.k3, this.a, this.b, this.order, this.cofactor); } public boolean supportsCoordinateSystem(int coord) { switch (coord) { - case COORD_AFFINE: - case COORD_HOMOGENEOUS: - case COORD_LAMBDA_PROJECTIVE: + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: return true; default: return false; @@ -733,200 +1100,19 @@ public abstract class ECCurve return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x); } - public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) - { - ECFieldElement X = fromBigInteger(x), Y = fromBigInteger(y); - - switch (this.getCoordinateSystem()) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - if (!X.isZero()) - { - // Y becomes Lambda (X + Y/X) here - Y = Y.divide(X).add(X); - } - break; - } - default: - { - break; - } - } - - return createRawPoint(X, Y, withCompression); - } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) { return new ECPoint.F2m(this, x, y, withCompression); } - public ECPoint getInfinity() - { - return infinity; - } - - /** - * Returns true if this is a Koblitz curve (ABC curve). - * @return true if this is a Koblitz curve (ABC curve), false otherwise - */ - public boolean isKoblitz() - { - return n != null && h != null && a.bitLength() <= 1 && b.bitLength() == 1; - } - - /** - * Returns the parameter μ of the elliptic curve. - * @return μ of the elliptic curve. - * @throws IllegalArgumentException if the given ECCurve is not a - * Koblitz curve. - */ - synchronized byte getMu() - { - if (mu == 0) - { - mu = Tnaf.getMu(this); - } - return mu; - } - - /** - * @return the auxiliary values s0 and - * s1 used for partial modular reduction for - * Koblitz curves. - */ - synchronized BigInteger[] getSi() + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) { - if (si == null) - { - si = Tnaf.getSi(this); - } - return si; + return new ECPoint.F2m(this, x, y, zs, withCompression); } - /** - * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2). - * - * @param yTilde - * ~yp, an indication bit for the decompression of yp. - * @param X1 - * The field element xp. - * @return the decompressed point. - */ - protected ECPoint decompressPoint(int yTilde, BigInteger X1) - { - ECFieldElement xp = fromBigInteger(X1); - ECFieldElement yp = null; - if (xp.isZero()) - { - yp = (ECFieldElement.F2m)b; - for (int i = 0; i < m - 1; i++) - { - yp = yp.square(); - } - } - else - { - ECFieldElement beta = xp.add(a).add(b.multiply(xp.square().invert())); - ECFieldElement z = solveQuadraticEquation(beta); - if (z == null) - { - throw new IllegalArgumentException("Invalid point compression"); - } - if (z.testBitZero() != (yTilde == 1)) - { - z = z.addOne(); - } - - yp = xp.multiply(z); - - switch (this.getCoordinateSystem()) - { - case COORD_LAMBDA_AFFINE: - case COORD_LAMBDA_PROJECTIVE: - { - yp = yp.divide(xp).add(xp); - break; - } - default: - { - break; - } - } - } - - return new ECPoint.F2m(this, xp, yp, true); - } - - /** - * Solves a quadratic equation z2 + z = beta(X9.62 - * D.1.6) The other solution is z + 1. - * - * @param beta - * The value to solve the quadratic equation for. - * @return the solution for z2 + z = beta or - * null if no solution exists. - */ - private ECFieldElement solveQuadraticEquation(ECFieldElement beta) - { - if (beta.isZero()) - { - return beta; - } - - ECFieldElement zeroElement = fromBigInteger(ECConstants.ZERO); - - ECFieldElement z = null; - ECFieldElement gamma = null; - - Random rand = new Random(); - do - { - ECFieldElement t = fromBigInteger(new BigInteger(m, rand)); - z = zeroElement; - ECFieldElement w = beta; - for (int i = 1; i <= m - 1; i++) - { - ECFieldElement w2 = w.square(); - z = z.square().add(w2.multiply(t)); - w = w2.add(beta); - } - if (!w.isZero()) - { - return null; - } - gamma = z.square().add(z); - } - while (gamma.isZero()); - - return z; - } - - public boolean equals( - Object anObject) - { - if (anObject == this) - { - return true; - } - - if (!(anObject instanceof ECCurve.F2m)) - { - return false; - } - - ECCurve.F2m other = (ECCurve.F2m)anObject; - - return (this.m == other.m) && (this.k1 == other.k1) - && (this.k2 == other.k2) && (this.k3 == other.k3) - && a.equals(other.a) && b.equals(other.b); - } - - public int hashCode() + public ECPoint getInfinity() { - return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3; + return infinity; } public int getM() @@ -959,14 +1145,20 @@ public abstract class ECCurve return k3; } + /** + * @deprecated use {@link #getOrder()} instead + */ public BigInteger getN() { - return n; + return this.order; } + /** + * @deprecated use {@link #getCofactor()} instead + */ public BigInteger getH() { - return h; + return this.cofactor; } } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java index 87608eb..18409c0 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java @@ -3,6 +3,8 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; import java.util.Random; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; @@ -27,11 +29,46 @@ public abstract class ECFieldElement return toBigInteger().bitLength(); } + public boolean isOne() + { + return bitLength() == 1; + } + public boolean isZero() { return 0 == toBigInteger().signum(); } + public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + return multiply(b).subtract(x.multiply(y)); + } + + public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + return multiply(b).add(x.multiply(y)); + } + + public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y) + { + return square().subtract(x.multiply(y)); + } + + public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y) + { + return square().add(x.multiply(y)); + } + + public ECFieldElement squarePow(int pow) + { + ECFieldElement r = this; + for (int i = 0; i < pow; ++i) + { + r = r.square(); + } + return r; + } + public boolean testBitZero() { return toBigInteger().testBit(0); @@ -51,42 +88,10 @@ public abstract class ECFieldElement { BigInteger q, r, x; -// static int[] calculateNaf(BigInteger p) -// { -// int[] naf = WNafUtil.generateCompactNaf(p); -// -// int bit = 0; -// for (int i = 0; i < naf.length; ++i) -// { -// int ni = naf[i]; -// int digit = ni >> 16, zeroes = ni & 0xFFFF; -// -// bit += zeroes; -// naf[i] = digit < 0 ? ~bit : bit; -// ++bit; -// } -// -// int last = naf.length - 1; -// if (last > 0 && last <= 16) -// { -// int top = naf[last], top2 = naf[last - 1]; -// if (top2 < 0) -// { -// top2 = ~top2; -// } -// if (top - top2 >= 64) -// { -// return naf; -// } -// } -// -// return null; -// } - static BigInteger calculateResidue(BigInteger p) { int bitLength = p.bitLength(); - if (bitLength > 128) + if (bitLength >= 96) { BigInteger firstWord = p.shiftRight(bitLength - 64); if (firstWord.longValue() == -1L) @@ -159,13 +164,7 @@ public abstract class ECFieldElement public ECFieldElement subtract(ECFieldElement b) { - BigInteger x2 = b.toBigInteger(); - BigInteger x3 = x.subtract(x2); - if (x3.signum() < 0) - { - x3 = x3.add(q); - } - return new Fp(q, r, x3); + return new Fp(q, r, modSubtract(x, b.toBigInteger())); } public ECFieldElement multiply(ECFieldElement b) @@ -173,27 +172,30 @@ public abstract class ECFieldElement return new Fp(q, r, modMult(x, b.toBigInteger())); } + public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, bx = b.toBigInteger(), xx = x.toBigInteger(), yx = y.toBigInteger(); + BigInteger ab = ax.multiply(bx); + BigInteger xy = xx.multiply(yx); + return new Fp(q, r, modReduce(ab.subtract(xy))); + } + + public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, bx = b.toBigInteger(), xx = x.toBigInteger(), yx = y.toBigInteger(); + BigInteger ab = ax.multiply(bx); + BigInteger xy = xx.multiply(yx); + return new Fp(q, r, modReduce(ab.add(xy))); + } + public ECFieldElement divide(ECFieldElement b) { - return new Fp(q, modMult(x, b.toBigInteger().modInverse(q))); + return new Fp(q, r, modMult(x, modInverse(b.toBigInteger()))); } public ECFieldElement negate() { - BigInteger x2; - if (x.signum() == 0) - { - x2 = x; - } - else if (ONE.equals(r)) - { - x2 = q.xor(x); - } - else - { - x2 = q.subtract(x); - } - return new Fp(q, r, x2); + return x.signum() == 0 ? this : new Fp(q, r, q.subtract(x)); } public ECFieldElement square() @@ -201,10 +203,26 @@ public abstract class ECFieldElement return new Fp(q, r, modMult(x, x)); } + public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, xx = x.toBigInteger(), yx = y.toBigInteger(); + BigInteger aa = ax.multiply(ax); + BigInteger xy = xx.multiply(yx); + return new Fp(q, r, modReduce(aa.subtract(xy))); + } + + public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y) + { + BigInteger ax = this.x, xx = x.toBigInteger(), yx = y.toBigInteger(); + BigInteger aa = ax.multiply(ax); + BigInteger xy = xx.multiply(yx); + return new Fp(q, r, modReduce(aa.add(xy))); + } + public ECFieldElement invert() { // TODO Modular inversion can be faster for a (Generalized) Mersenne Prime. - return new Fp(q, r, x.modInverse(q)); + return new Fp(q, r, modInverse(x)); } // D.1.4 91 @@ -214,6 +232,11 @@ public abstract class ECFieldElement */ public ECFieldElement sqrt() { + if (this.isZero() || this.isOne()) // earlier JDK compatibility + { + return this; + } + if (!q.testBit(0)) { throw new RuntimeException("not done yet"); @@ -221,29 +244,44 @@ public abstract class ECFieldElement // note: even though this class implements ECConstants don't be tempted to // remove the explicit declaration, some J2ME environments don't cope. - // p mod 4 == 3 - if (q.testBit(1)) + + if (q.testBit(1)) // q == 4m + 3 + { + BigInteger e = q.shiftRight(2).add(ECConstants.ONE); + return checkSqrt(new Fp(q, r, x.modPow(e, q))); + } + + if (q.testBit(2)) // q == 8m + 5 { - // z = g^(u+1) + p, p = 4u + 3 - ECFieldElement z = new Fp(q, r, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q)); + BigInteger t1 = x.modPow(q.shiftRight(3), q); + BigInteger t2 = modMult(t1, x); + BigInteger t3 = modMult(t2, t1); + + if (t3.equals(ECConstants.ONE)) + { + return checkSqrt(new Fp(q, r, t2)); + } + + // TODO This is constant and could be precomputed + BigInteger t4 = ECConstants.TWO.modPow(q.shiftRight(2), q); - return z.square().equals(this) ? z : null; + BigInteger y = modMult(t2, t4); + + return checkSqrt(new Fp(q, r, y)); } - // p mod 4 == 1 - BigInteger qMinusOne = q.subtract(ECConstants.ONE); + // q == 8m + 1 - BigInteger legendreExponent = qMinusOne.shiftRight(1); + BigInteger legendreExponent = q.shiftRight(1); if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE))) { return null; } - BigInteger u = qMinusOne.shiftRight(2); - BigInteger k = u.shiftLeft(1).add(ECConstants.ONE); + BigInteger X = this.x; + BigInteger fourX = modDouble(modDouble(X)); - BigInteger Q = this.x; - BigInteger fourQ = modDouble(modDouble(Q)); + BigInteger k = legendreExponent.add(ECConstants.ONE), qMinusOne = q.subtract(ECConstants.ONE); BigInteger U, V; Random rand = new Random(); @@ -255,94 +293,39 @@ public abstract class ECFieldElement P = new BigInteger(q.bitLength(), rand); } while (P.compareTo(q) >= 0 - || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, q).equals(qMinusOne))); + || !modReduce(P.multiply(P).subtract(fourX)).modPow(legendreExponent, q).equals(qMinusOne)); - BigInteger[] result = lucasSequence(P, Q, k); + BigInteger[] result = lucasSequence(P, X, k); U = result[0]; V = result[1]; - if (modMult(V, V).equals(fourQ)) + if (modMult(V, V).equals(fourX)) { - // Integer division by 2, mod q - if (V.testBit(0)) - { - V = V.add(q); - } - - V = V.shiftRight(1); - - //assert V.multiply(V).mod(q).equals(x); - - return new ECFieldElement.Fp(q, r, V); + return new ECFieldElement.Fp(q, r, modHalfAbs(V)); } } while (U.equals(ECConstants.ONE) || U.equals(qMinusOne)); return null; + } -// BigInteger qMinusOne = q.subtract(ECConstants.ONE); -// BigInteger legendreExponent = qMinusOne.shiftRight(1); //divide(ECConstants.TWO); -// if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE))) -// { -// return null; -// } -// -// Random rand = new Random(); -// BigInteger fourX = x.shiftLeft(2); -// -// BigInteger r; -// do -// { -// r = new BigInteger(q.bitLength(), rand); -// } -// while (r.compareTo(q) >= 0 -// || !(r.multiply(r).subtract(fourX).modPow(legendreExponent, q).equals(qMinusOne))); -// -// BigInteger n1 = qMinusOne.shiftRight(2); //.divide(ECConstants.FOUR); -// BigInteger n2 = n1.add(ECConstants.ONE); //q.add(ECConstants.THREE).divide(ECConstants.FOUR); -// -// BigInteger wOne = WOne(r, x, q); -// BigInteger wSum = W(n1, wOne, q).add(W(n2, wOne, q)).mod(q); -// BigInteger twoR = r.shiftLeft(1); //ECConstants.TWO.multiply(r); -// -// BigInteger root = twoR.modPow(q.subtract(ECConstants.TWO), q) -// .multiply(x).mod(q) -// .multiply(wSum).mod(q); -// -// return new Fp(q, root); - } - -// private static BigInteger W(BigInteger n, BigInteger wOne, BigInteger p) -// { -// if (n.equals(ECConstants.ONE)) -// { -// return wOne; -// } -// boolean isEven = !n.testBit(0); -// n = n.shiftRight(1);//divide(ECConstants.TWO); -// if (isEven) -// { -// BigInteger w = W(n, wOne, p); -// return w.multiply(w).subtract(ECConstants.TWO).mod(p); -// } -// BigInteger w1 = W(n.add(ECConstants.ONE), wOne, p); -// BigInteger w2 = W(n, wOne, p); -// return w1.multiply(w2).subtract(wOne).mod(p); -// } -// -// private BigInteger WOne(BigInteger r, BigInteger x, BigInteger p) -// { -// return r.multiply(r).multiply(x.modPow(q.subtract(ECConstants.TWO), q)).subtract(ECConstants.TWO).mod(p); -// } + private ECFieldElement checkSqrt(ECFieldElement z) + { + return z.square().equals(this) ? z : null; + } private BigInteger[] lucasSequence( BigInteger P, BigInteger Q, BigInteger k) { + // TODO Research and apply "common-multiplicand multiplication here" + int n = k.bitLength(); int s = k.getLowestSetBit(); + // assert k.testBit(s); + BigInteger Uh = ECConstants.ONE; BigInteger Vl = ECConstants.TWO; BigInteger Vh = P; @@ -405,6 +388,35 @@ public abstract class ECFieldElement return _2x; } + protected BigInteger modHalf(BigInteger x) + { + if (x.testBit(0)) + { + x = q.add(x); + } + return x.shiftRight(1); + } + + protected BigInteger modHalfAbs(BigInteger x) + { + if (x.testBit(0)) + { + x = q.subtract(x); + } + return x.shiftRight(1); + } + + protected BigInteger modInverse(BigInteger x) + { + int bits = getFieldSize(); + int len = (bits + 31) >> 5; + int[] p = Nat.fromBigInteger(bits, q); + int[] n = Nat.fromBigInteger(bits, x); + int[] z = Nat.create(len); + Mod.invert(p, n, z); + return Nat.toBigInteger(len, z); + } + protected BigInteger modMult(BigInteger x1, BigInteger x2) { return modReduce(x1.multiply(x2)); @@ -412,44 +424,20 @@ public abstract class ECFieldElement protected BigInteger modReduce(BigInteger x) { -// if (naf != null) -// { -// int last = naf.length - 1; -// int bits = naf[last]; -// while (x.bitLength() > (bits + 1)) -// { -// BigInteger u = x.shiftRight(bits); -// BigInteger v = x.subtract(u.shiftLeft(bits)); -// -// x = v; -// -// for (int i = 0; i < last; ++i) -// { -// int ni = naf[i]; -// if (ni < 0) -// { -// x = x.add(u.shiftLeft(~ni)); -// } -// else -// { -// x = x.subtract(u.shiftLeft(ni)); -// } -// } -// } -// while (x.compareTo(q) >= 0) -// { -// x = x.subtract(q); -// } -// } -// else if (r != null) { + boolean negative = x.signum() < 0; + if (negative) + { + x = x.abs(); + } int qLen = q.bitLength(); + boolean rIsOne = r.equals(ECConstants.ONE); while (x.bitLength() > (qLen + 1)) { BigInteger u = x.shiftRight(qLen); BigInteger v = x.subtract(u.shiftLeft(qLen)); - if (!r.equals(ONE)) + if (!rIsOne) { u = u.multiply(r); } @@ -459,6 +447,10 @@ public abstract class ECFieldElement { x = x.subtract(q); } + if (negative && x.signum() != 0) + { + x = q.subtract(x); + } } else { @@ -467,6 +459,16 @@ public abstract class ECFieldElement return x; } + protected BigInteger modSubtract(BigInteger x1, BigInteger x2) + { + BigInteger x3 = x1.subtract(x2); + if (x3.signum() < 0) + { + x3 = x3.add(q); + } + return x3; + } + public boolean equals(Object other) { if (other == this) @@ -489,467 +491,6 @@ public abstract class ECFieldElement } } -// /** -// * Class representing the Elements of the finite field -// * F2m in polynomial basis (PB) -// * representation. Both trinomial (TPB) and pentanomial (PPB) polynomial -// * basis representations are supported. Gaussian normal basis (GNB) -// * representation is not supported. -// */ -// public static class F2m extends ECFieldElement -// { -// BigInteger x; -// -// /** -// * Indicates gaussian normal basis representation (GNB). Number chosen -// * according to X9.62. GNB is not implemented at present. -// */ -// public static final int GNB = 1; -// -// /** -// * Indicates trinomial basis representation (TPB). Number chosen -// * according to X9.62. -// */ -// public static final int TPB = 2; -// -// /** -// * Indicates pentanomial basis representation (PPB). Number chosen -// * according to X9.62. -// */ -// public static final int PPB = 3; -// -// /** -// * TPB or PPB. -// */ -// private int representation; -// -// /** -// * The exponent m of F2m. -// */ -// private int m; -// -// /** -// * TPB: The integer k where xm + -// * xk + 1 represents the reduction polynomial -// * f(z).
    -// * PPB: The integer k1 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z).
    -// */ -// private int k1; -// -// /** -// * TPB: Always set to 0
    -// * PPB: The integer k2 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z).
    -// */ -// private int k2; -// -// /** -// * TPB: Always set to 0
    -// * PPB: The integer k3 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z).
    -// */ -// private int k3; -// -// /** -// * Constructor for PPB. -// * @param m The exponent m of -// * F2m. -// * @param k1 The integer k1 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z). -// * @param k2 The integer k2 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z). -// * @param k3 The integer k3 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z). -// * @param x The BigInteger representing the value of the field element. -// */ -// public F2m( -// int m, -// int k1, -// int k2, -// int k3, -// BigInteger x) -// { -//// super(x); -// this.x = x; -// -// if ((k2 == 0) && (k3 == 0)) -// { -// this.representation = TPB; -// } -// else -// { -// if (k2 >= k3) -// { -// throw new IllegalArgumentException( -// "k2 must be smaller than k3"); -// } -// if (k2 <= 0) -// { -// throw new IllegalArgumentException( -// "k2 must be larger than 0"); -// } -// this.representation = PPB; -// } -// -// if (x.signum() < 0) -// { -// throw new IllegalArgumentException("x value cannot be negative"); -// } -// -// this.m = m; -// this.k1 = k1; -// this.k2 = k2; -// this.k3 = k3; -// } -// -// /** -// * Constructor for TPB. -// * @param m The exponent m of -// * F2m. -// * @param k The integer k where xm + -// * xk + 1 represents the reduction -// * polynomial f(z). -// * @param x The BigInteger representing the value of the field element. -// */ -// public F2m(int m, int k, BigInteger x) -// { -// // Set k1 to k, and set k2 and k3 to 0 -// this(m, k, 0, 0, x); -// } -// -// public BigInteger toBigInteger() -// { -// return x; -// } -// -// public String getFieldName() -// { -// return "F2m"; -// } -// -// public int getFieldSize() -// { -// return m; -// } -// -// /** -// * Checks, if the ECFieldElements a and b -// * are elements of the same field F2m -// * (having the same representation). -// * @param a field element. -// * @param b field element to be compared. -// * @throws IllegalArgumentException if a and b -// * are not elements of the same field -// * F2m (having the same -// * representation). -// */ -// public static void checkFieldElements( -// ECFieldElement a, -// ECFieldElement b) -// { -// if ((!(a instanceof F2m)) || (!(b instanceof F2m))) -// { -// throw new IllegalArgumentException("Field elements are not " -// + "both instances of ECFieldElement.F2m"); -// } -// -// if ((a.toBigInteger().signum() < 0) || (b.toBigInteger().signum() < 0)) -// { -// throw new IllegalArgumentException( -// "x value may not be negative"); -// } -// -// ECFieldElement.F2m aF2m = (ECFieldElement.F2m)a; -// ECFieldElement.F2m bF2m = (ECFieldElement.F2m)b; -// -// if ((aF2m.m != bF2m.m) || (aF2m.k1 != bF2m.k1) -// || (aF2m.k2 != bF2m.k2) || (aF2m.k3 != bF2m.k3)) -// { -// throw new IllegalArgumentException("Field elements are not " -// + "elements of the same field F2m"); -// } -// -// if (aF2m.representation != bF2m.representation) -// { -// // Should never occur -// throw new IllegalArgumentException( -// "One of the field " -// + "elements are not elements has incorrect representation"); -// } -// } -// -// /** -// * Computes z * a(z) mod f(z), where f(z) is -// * the reduction polynomial of this. -// * @param a The polynomial a(z) to be multiplied by -// * z mod f(z). -// * @return z * a(z) mod f(z) -// */ -// private BigInteger multZModF(final BigInteger a) -// { -// // Left-shift of a(z) -// BigInteger az = a.shiftLeft(1); -// if (az.testBit(this.m)) -// { -// // If the coefficient of z^m in a(z) equals 1, reduction -// // modulo f(z) is performed: Add f(z) to to a(z): -// // Step 1: Unset mth coeffient of a(z) -// az = az.clearBit(this.m); -// -// // Step 2: Add r(z) to a(z), where r(z) is defined as -// // f(z) = z^m + r(z), and k1, k2, k3 are the positions of -// // the non-zero coefficients in r(z) -// az = az.flipBit(0); -// az = az.flipBit(this.k1); -// if (this.representation == PPB) -// { -// az = az.flipBit(this.k2); -// az = az.flipBit(this.k3); -// } -// } -// return az; -// } -// -// public ECFieldElement add(final ECFieldElement b) -// { -// // No check performed here for performance reasons. Instead the -// // elements involved are checked in ECPoint.F2m -// // checkFieldElements(this, b); -// if (b.toBigInteger().signum() == 0) -// { -// return this; -// } -// -// return new F2m(this.m, this.k1, this.k2, this.k3, this.x.xor(b.toBigInteger())); -// } -// -// public ECFieldElement subtract(final ECFieldElement b) -// { -// // Addition and subtraction are the same in F2m -// return add(b); -// } -// -// -// public ECFieldElement multiply(final ECFieldElement b) -// { -// // Left-to-right shift-and-add field multiplication in F2m -// // Input: Binary polynomials a(z) and b(z) of degree at most m-1 -// // Output: c(z) = a(z) * b(z) mod f(z) -// -// // No check performed here for performance reasons. Instead the -// // elements involved are checked in ECPoint.F2m -// // checkFieldElements(this, b); -// final BigInteger az = this.x; -// BigInteger bz = b.toBigInteger(); -// BigInteger cz; -// -// // Compute c(z) = a(z) * b(z) mod f(z) -// if (az.testBit(0)) -// { -// cz = bz; -// } -// else -// { -// cz = ECConstants.ZERO; -// } -// -// for (int i = 1; i < this.m; i++) -// { -// // b(z) := z * b(z) mod f(z) -// bz = multZModF(bz); -// -// if (az.testBit(i)) -// { -// // If the coefficient of x^i in a(z) equals 1, b(z) is added -// // to c(z) -// cz = cz.xor(bz); -// } -// } -// return new ECFieldElement.F2m(m, this.k1, this.k2, this.k3, cz); -// } -// -// -// public ECFieldElement divide(final ECFieldElement b) -// { -// // There may be more efficient implementations -// ECFieldElement bInv = b.invert(); -// return multiply(bInv); -// } -// -// public ECFieldElement negate() -// { -// // -x == x holds for all x in F2m -// return this; -// } -// -// public ECFieldElement square() -// { -// // Naive implementation, can probably be speeded up using modular -// // reduction -// return multiply(this); -// } -// -// public ECFieldElement invert() -// { -// // Inversion in F2m using the extended Euclidean algorithm -// // Input: A nonzero polynomial a(z) of degree at most m-1 -// // Output: a(z)^(-1) mod f(z) -// -// // u(z) := a(z) -// BigInteger uz = this.x; -// if (uz.signum() <= 0) -// { -// throw new ArithmeticException("x is zero or negative, " + -// "inversion is impossible"); -// } -// -// // v(z) := f(z) -// BigInteger vz = ECConstants.ZERO.setBit(m); -// vz = vz.setBit(0); -// vz = vz.setBit(this.k1); -// if (this.representation == PPB) -// { -// vz = vz.setBit(this.k2); -// vz = vz.setBit(this.k3); -// } -// -// // g1(z) := 1, g2(z) := 0 -// BigInteger g1z = ECConstants.ONE; -// BigInteger g2z = ECConstants.ZERO; -// -// // while u != 1 -// while (!(uz.equals(ECConstants.ZERO))) -// { -// // j := deg(u(z)) - deg(v(z)) -// int j = uz.bitLength() - vz.bitLength(); -// -// // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j -// if (j < 0) -// { -// final BigInteger uzCopy = uz; -// uz = vz; -// vz = uzCopy; -// -// final BigInteger g1zCopy = g1z; -// g1z = g2z; -// g2z = g1zCopy; -// -// j = -j; -// } -// -// // u(z) := u(z) + z^j * v(z) -// // Note, that no reduction modulo f(z) is required, because -// // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z))) -// // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z)) -// // = deg(u(z)) -// uz = uz.xor(vz.shiftLeft(j)); -// -// // g1(z) := g1(z) + z^j * g2(z) -// g1z = g1z.xor(g2z.shiftLeft(j)); -//// if (g1z.bitLength() > this.m) { -//// throw new ArithmeticException( -//// "deg(g1z) >= m, g1z = " + g1z.toString(16)); -//// } -// } -// return new ECFieldElement.F2m( -// this.m, this.k1, this.k2, this.k3, g2z); -// } -// -// public ECFieldElement sqrt() -// { -// throw new RuntimeException("Not implemented"); -// } -// -// /** -// * @return the representation of the field -// * F2m, either of -// * TPB (trinomial -// * basis representation) or -// * PPB (pentanomial -// * basis representation). -// */ -// public int getRepresentation() -// { -// return this.representation; -// } -// -// /** -// * @return the degree m of the reduction polynomial -// * f(z). -// */ -// public int getM() -// { -// return this.m; -// } -// -// /** -// * @return TPB: The integer k where xm + -// * xk + 1 represents the reduction polynomial -// * f(z).
    -// * PPB: The integer k1 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z).
    -// */ -// public int getK1() -// { -// return this.k1; -// } -// -// /** -// * @return TPB: Always returns 0
    -// * PPB: The integer k2 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z).
    -// */ -// public int getK2() -// { -// return this.k2; -// } -// -// /** -// * @return TPB: Always set to 0
    -// * PPB: The integer k3 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z).
    -// */ -// public int getK3() -// { -// return this.k3; -// } -// -// public boolean equals(Object anObject) -// { -// if (anObject == this) -// { -// return true; -// } -// -// if (!(anObject instanceof ECFieldElement.F2m)) -// { -// return false; -// } -// -// ECFieldElement.F2m b = (ECFieldElement.F2m)anObject; -// -// return ((this.m == b.m) && (this.k1 == b.k1) && (this.k2 == b.k2) -// && (this.k3 == b.k3) -// && (this.representation == b.representation) -// && (this.x.equals(b.x))); -// } -// -// public int hashCode() -// { -// return x.hashCode() ^ m ^ k1 ^ k2 ^ k3; -// } -// } - /** * Class representing the Elements of the finite field * F2m in polynomial basis (PB) @@ -987,32 +528,6 @@ public abstract class ECFieldElement */ private int m; -// /** -// * TPB: The integer k where xm + -// * xk + 1 represents the reduction polynomial -// * f(z).
    -// * PPB: The integer k1 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z).
    -// */ -// private int k1; -// -// /** -// * TPB: Always set to 0
    -// * PPB: The integer k2 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z).
    -// */ -// private int k2; -// -// /** -// * TPB: Always set to 0
    -// * PPB: The integer k3 where xm + -// * xk3 + xk2 + xk1 + 1 -// * represents the reduction polynomial f(z).
    -// */ -// private int k3; - private int[] ks; /** @@ -1043,6 +558,11 @@ public abstract class ECFieldElement int k3, BigInteger x) { + if (x == null || x.signum() < 0 || x.bitLength() > m) + { + throw new IllegalArgumentException("x value invalid in F2m field element"); + } + if ((k2 == 0) && (k3 == 0)) { this.representation = TPB; @@ -1097,6 +617,11 @@ public abstract class ECFieldElement return x.degree(); } + public boolean isOne() + { + return x.isOne(); + } + public boolean isZero() { return x.isZero(); @@ -1192,6 +717,29 @@ public abstract class ECFieldElement return new F2m(m, ks, x.modMultiply(((F2m)b).x, m, ks)); } + public ECFieldElement multiplyMinusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + return multiplyPlusProduct(b, x, y); + } + + public ECFieldElement multiplyPlusProduct(ECFieldElement b, ECFieldElement x, ECFieldElement y) + { + LongArray ax = this.x, bx = ((F2m)b).x, xx = ((F2m)x).x, yx = ((F2m)y).x; + + LongArray ab = ax.multiply(bx, m, ks); + LongArray xy = xx.multiply(yx, m, ks); + + if (ab == ax || ab == bx) + { + ab = (LongArray)ab.clone(); + } + + ab.addShiftedByWords(xy, 0); + ab.reduce(m, ks); + + return new F2m(m, ks, ab); + } + public ECFieldElement divide(final ECFieldElement b) { // There may be more efficient implementations @@ -1210,6 +758,34 @@ public abstract class ECFieldElement return new F2m(m, ks, x.modSquare(m, ks)); } + public ECFieldElement squareMinusProduct(ECFieldElement x, ECFieldElement y) + { + return squarePlusProduct(x, y); + } + + public ECFieldElement squarePlusProduct(ECFieldElement x, ECFieldElement y) + { + LongArray ax = this.x, xx = ((F2m)x).x, yx = ((F2m)y).x; + + LongArray aa = ax.square(m, ks); + LongArray xy = xx.multiply(yx, m, ks); + + if (aa == ax) + { + aa = (LongArray)aa.clone(); + } + + aa.addShiftedByWords(xy, 0); + aa.reduce(m, ks); + + return new F2m(m, ks, aa); + } + + public ECFieldElement squarePow(int pow) + { + return pow < 1 ? this : new F2m(m, ks, x.modSquareN(pow, m, ks)); + } + public ECFieldElement invert() { return new ECFieldElement.F2m(this.m, this.ks, this.x.modInverse(m, ks)); @@ -1217,7 +793,7 @@ public abstract class ECFieldElement public ECFieldElement sqrt() { - throw new RuntimeException("Not implemented"); + return (x.isZero() || x.isOne()) ? this : squarePow(m - 1); } /** diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java index 7f740e4..0ea5026 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java @@ -1,6 +1,7 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; +import java.util.Hashtable; /** * base class for points on elliptic curves. @@ -47,7 +48,8 @@ public abstract class ECPoint protected boolean withCompression; - protected PreCompInfo preCompInfo = null; + // Hashtable is (String -> PreCompInfo) + protected Hashtable preCompTable = null; protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y) { @@ -62,11 +64,26 @@ public abstract class ECPoint this.zs = zs; } + protected boolean satisfiesCofactor() + { + BigInteger h = curve.getCofactor(); + return h == null || h.equals(ECConstants.ONE) || !ECAlgorithms.referenceMultiply(this, h).isInfinity(); + } + + protected abstract boolean satisfiesCurveEquation(); + + public final ECPoint getDetachedPoint() + { + return normalize().detach(); + } + public ECCurve getCurve() { return curve; } + protected abstract ECPoint detach(); + protected int getCurveCoordinateSystem() { // Cope with null curve, most commonly used by implicitlyCa @@ -79,7 +96,7 @@ public abstract class ECPoint * Note: normalization can be expensive, this method is deprecated in favour * of caller-controlled normalization. * - * @deprecated Use getAffineXCoord, or normalize() and getXCoord(), instead + * @deprecated Use getAffineXCoord(), or normalize() and getXCoord(), instead */ public ECFieldElement getX() { @@ -93,7 +110,7 @@ public abstract class ECPoint * Note: normalization can be expensive, this method is deprecated in favour * of caller-controlled normalization. * - * @deprecated Use getAffineYCoord, or normalize() and getYCoord(), instead + * @deprecated Use getAffineYCoord(), or normalize() and getYCoord(), instead */ public ECFieldElement getY() { @@ -129,7 +146,7 @@ public abstract class ECPoint * * Caution: depending on the curve's coordinate system, this may not be the same value as in an * affine coordinate system; use normalize() to get a point where the coordinates have their - * affine values, or use getAffineXCoord if you expect the point to already have been + * affine values, or use getAffineXCoord() if you expect the point to already have been * normalized. * * @return the x-coordinate of this point @@ -144,7 +161,7 @@ public abstract class ECPoint * * Caution: depending on the curve's coordinate system, this may not be the same value as in an * affine coordinate system; use normalize() to get a point where the coordinates have their - * affine values, or use getAffineYCoord if you expect the point to already have been + * affine values, or use getAffineYCoord() if you expect the point to already have been * normalized. * * @return the y-coordinate of this point @@ -164,23 +181,28 @@ public abstract class ECPoint int zsLen = zs.length; if (zsLen == 0) { - return zs; + return EMPTY_ZS; } ECFieldElement[] copy = new ECFieldElement[zsLen]; System.arraycopy(zs, 0, copy, 0, zsLen); return copy; } - protected ECFieldElement getRawXCoord() + public final ECFieldElement getRawXCoord() { return x; } - protected ECFieldElement getRawYCoord() + public final ECFieldElement getRawYCoord() { return y; } + protected final ECFieldElement[] getRawZCoords() + { + return zs; + } + protected void checkNormalized() { if (!isNormalized()) @@ -196,7 +218,7 @@ public abstract class ECPoint return coord == ECCurve.COORD_AFFINE || coord == ECCurve.COORD_LAMBDA_AFFINE || isInfinity() - || zs[0].bitLength() == 1; + || zs[0].isOne(); } /** @@ -222,7 +244,7 @@ public abstract class ECPoint default: { ECFieldElement Z1 = getZCoord(0); - if (Z1.bitLength() == 1) + if (Z1.isOne()) { return this; } @@ -265,11 +287,54 @@ public abstract class ECPoint return x == null || y == null || (zs.length > 0 && zs[0].isZero()); } + /** + * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} + */ public boolean isCompressed() { return this.withCompression; } + public boolean isValid() + { + if (isInfinity()) + { + return true; + } + + // TODO Sanity-check the field elements + + ECCurve curve = getCurve(); + if (curve != null) + { + if (!satisfiesCurveEquation()) + { + return false; + } + + if (!satisfiesCofactor()) + { + return false; + } + } + + return true; + } + + public ECPoint scaleX(ECFieldElement scale) + { + return isInfinity() + ? this + : getCurve().createRawPoint(getRawXCoord().multiply(scale), getRawYCoord(), getRawZCoords(), this.withCompression); + } + + public ECPoint scaleY(ECFieldElement scale) + { + return isInfinity() + ? this + : getCurve().createRawPoint(getRawXCoord(), getRawYCoord().multiply(scale), getRawZCoords(), this.withCompression); + } + public boolean equals(ECPoint other) { if (null == other) @@ -373,13 +438,19 @@ public abstract class ECPoint return sb.toString(); } + /** + * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} + */ public byte[] getEncoded() { return getEncoded(this.withCompression); } /** - * return the field element encoded with point compression. (S 4.3.6) + * Get an encoding of the point value, optionally in compressed format. + * + * @param compressed whether to generate a compressed point encoding. + * @return the point encoding */ public byte[] getEncoded(boolean compressed) { @@ -454,13 +525,84 @@ public abstract class ECPoint return this.getCurve().getMultiplier().multiply(this, k); } + public static abstract class AbstractFp extends ECPoint + { + protected AbstractFp(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + super(curve, x, y); + } + + protected AbstractFp(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) + { + super(curve, x, y, zs); + } + + protected boolean getCompressionYTilde() + { + return this.getAffineYCoord().testBitZero(); + } + + protected boolean satisfiesCurveEquation() + { + ECFieldElement X = this.x, Y = this.y, A = curve.getA(), B = curve.getB(); + ECFieldElement lhs = Y.square(); + + switch (this.getCurveCoordinateSystem()) + { + case ECCurve.COORD_AFFINE: + break; + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Z = this.zs[0]; + if (!Z.isOne()) + { + ECFieldElement Z2 = Z.square(), Z3 = Z.multiply(Z2); + lhs = lhs.multiply(Z); + A = A.multiply(Z2); + B = B.multiply(Z3); + } + break; + } + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + ECFieldElement Z = this.zs[0]; + if (!Z.isOne()) + { + ECFieldElement Z2 = Z.square(), Z4 = Z2.square(), Z6 = Z2.multiply(Z4); + A = A.multiply(Z4); + B = B.multiply(Z6); + } + break; + } + default: + throw new IllegalStateException("unsupported coordinate system"); + } + + ECFieldElement rhs = X.square().add(A).multiply(X).add(B); + return lhs.equals(rhs); + } + + public ECPoint subtract(ECPoint b) + { + if (b.isInfinity()) + { + return this; + } + + // Add -b + return this.add(b.negate()); + } + } + /** * Elliptic curve points over Fp */ - public static class Fp extends ECPoint + public static class Fp extends AbstractFp { /** - * Create a point which encodes with point compression. + * Create a point which encodes without point compression. * * @param curve the curve to use * @param x affine x co-ordinate @@ -474,7 +616,7 @@ public abstract class ECPoint } /** - * Create a point that encodes with or without point compresion. + * Create a point that encodes with or without point compression. * * @param curve the curve to use * @param x affine x co-ordinate @@ -487,7 +629,7 @@ public abstract class ECPoint { super(curve, x, y); - if ((x != null && y == null) || (x == null && y != null)) + if ((x == null) != (y == null)) { throw new IllegalArgumentException("Exactly one of the field elements is null"); } @@ -502,9 +644,9 @@ public abstract class ECPoint this.withCompression = withCompression; } - protected boolean getCompressionYTilde() + protected ECPoint detach() { - return this.getAffineYCoord().testBitZero(); + return new ECPoint.Fp(null, this.getAffineXCoord(), this.getAffineYCoord()); } public ECFieldElement getZCoord(int index) @@ -569,8 +711,8 @@ public abstract class ECPoint ECFieldElement Z1 = this.zs[0]; ECFieldElement Z2 = b.zs[0]; - boolean Z1IsOne = Z1.bitLength() == 1; - boolean Z2IsOne = Z2.bitLength() == 1; + boolean Z1IsOne = Z1.isOne(); + boolean Z2IsOne = Z2.isOne(); ECFieldElement u1 = Z1IsOne ? Y2 : Y2.multiply(Z1); ECFieldElement u2 = Z2IsOne ? Y1 : Y1.multiply(Z2); @@ -600,7 +742,7 @@ public abstract class ECPoint ECFieldElement A = u.square().multiply(w).subtract(vCubed).subtract(two(vSquaredV2)); ECFieldElement X3 = v.multiply(A); - ECFieldElement Y3 = vSquaredV2.subtract(A).multiply(u).subtract(vCubed.multiply(u2)); + ECFieldElement Y3 = vSquaredV2.subtract(A).multiplyMinusProduct(u, u2, vCubed); ECFieldElement Z3 = vCubed.multiply(w); return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); @@ -612,7 +754,7 @@ public abstract class ECPoint ECFieldElement Z1 = this.zs[0]; ECFieldElement Z2 = b.zs[0]; - boolean Z1IsOne = Z1.bitLength() == 1; + boolean Z1IsOne = Z1.isOne(); ECFieldElement X3, Y3, Z3, Z3Squared = null; @@ -638,14 +780,7 @@ public abstract class ECPoint Y3 = W1.subtract(X3).multiply(dy).subtract(A1); Z3 = dx; - if (Z1IsOne) - { - Z3Squared = C; - } - else - { - Z3 = Z3.multiply(Z1); - } + Z3 = Z3.multiply(Z1); } else { @@ -662,7 +797,7 @@ public abstract class ECPoint S2 = Z1Cubed.multiply(Y2); } - boolean Z2IsOne = Z2.bitLength() == 1; + boolean Z2IsOne = Z2.isOne(); ECFieldElement Z2Squared, U1, S1; if (Z2IsOne) { @@ -697,8 +832,8 @@ public abstract class ECPoint ECFieldElement V = HSquared.multiply(U1); X3 = R.square().add(G).subtract(two(V)); - Y3 = V.subtract(X3).multiply(R).subtract(S1.multiply(G)); - + Y3 = V.subtract(X3).multiplyMinusProduct(R, G, S1); + Z3 = H; if (!Z1IsOne) { @@ -735,6 +870,7 @@ public abstract class ECPoint return new ECPoint.Fp(curve, X3, Y3, zs, this.withCompression); } + default: { throw new IllegalStateException("unsupported coordinate system"); @@ -778,14 +914,13 @@ public abstract class ECPoint { ECFieldElement Z1 = this.zs[0]; - boolean Z1IsOne = Z1.bitLength() == 1; - ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.square(); + boolean Z1IsOne = Z1.isOne(); // TODO Optimize for small negative a4 and -3 ECFieldElement w = curve.getA(); - if (!Z1IsOne) + if (!w.isZero() && !Z1IsOne) { - w = w.multiply(Z1Squared); + w = w.multiply(Z1.square()); } w = w.add(three(X1.square())); @@ -795,9 +930,11 @@ public abstract class ECPoint ECFieldElement _4B = four(B); ECFieldElement h = w.square().subtract(two(_4B)); - ECFieldElement X3 = two(h.multiply(s)); - ECFieldElement Y3 = w.multiply(_4B.subtract(h)).subtract(two(two(t).square())); - ECFieldElement _4sSquared = Z1IsOne ? four(t) : two(s).square(); + ECFieldElement _2s = two(s); + ECFieldElement X3 = h.multiply(_2s); + ECFieldElement _2t = two(t); + ECFieldElement Y3 = _4B.subtract(h).multiply(w).subtract(two(_2t.square())); + ECFieldElement _4sSquared = Z1IsOne ? two(_2t) : _2s.square(); ECFieldElement Z3 = two(_4sSquared).multiply(s); return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); @@ -807,8 +944,7 @@ public abstract class ECPoint { ECFieldElement Z1 = this.zs[0]; - boolean Z1IsOne = Z1.bitLength() == 1; - ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.square(); + boolean Z1IsOne = Z1.isOne(); ECFieldElement Y1Squared = Y1.square(); ECFieldElement T = Y1Squared.square(); @@ -819,6 +955,7 @@ public abstract class ECPoint ECFieldElement M, S; if (a4Neg.toBigInteger().equals(BigInteger.valueOf(3))) { + ECFieldElement Z1Squared = Z1IsOne ? Z1 : Z1.square(); M = three(X1.add(Z1Squared).multiply(X1.subtract(Z1Squared))); S = four(Y1Squared.multiply(X1)); } @@ -830,8 +967,9 @@ public abstract class ECPoint { M = M.add(a4); } - else + else if (!a4.isZero()) { + ECFieldElement Z1Squared = Z1.square(); ECFieldElement Z1Pow4 = Z1Squared.square(); if (a4Neg.bitLength() < a4.bitLength()) { @@ -842,7 +980,8 @@ public abstract class ECPoint M = M.add(Z1Pow4.multiply(a4)); } } - S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T)); +// S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T)); + S = four(X1.multiply(Y1Squared)); } ECFieldElement X3 = M.square().subtract(two(S)); @@ -951,7 +1090,13 @@ public abstract class ECPoint public ECPoint threeTimes() { - if (this.isInfinity() || this.y.isZero()) + if (this.isInfinity()) + { + return this; + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) { return this; } @@ -963,7 +1108,7 @@ public abstract class ECPoint { case ECCurve.COORD_AFFINE: { - ECFieldElement X1 = this.x, Y1 = this.y; + ECFieldElement X1 = this.x; ECFieldElement _2Y1 = two(Y1); ECFieldElement X = _2Y1.square(); @@ -997,6 +1142,102 @@ public abstract class ECPoint } } + public ECPoint timesPow2(int e) + { + if (e < 0) + { + throw new IllegalArgumentException("'e' cannot be negative"); + } + if (e == 0 || this.isInfinity()) + { + return this; + } + if (e == 1) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + int coord = curve.getCoordinateSystem(); + + ECFieldElement W1 = curve.getA(); + ECFieldElement X1 = this.x; + ECFieldElement Z1 = this.zs.length < 1 ? curve.fromBigInteger(ECConstants.ONE) : this.zs[0]; + + if (!Z1.isOne()) + { + switch (coord) + { + case ECCurve.COORD_AFFINE: + break; + case ECCurve.COORD_HOMOGENEOUS: + ECFieldElement Z1Sq = Z1.square(); + X1 = X1.multiply(Z1); + Y1 = Y1.multiply(Z1Sq); + W1 = calculateJacobianModifiedW(Z1, Z1Sq); + break; + case ECCurve.COORD_JACOBIAN: + W1 = calculateJacobianModifiedW(Z1, null); + break; + case ECCurve.COORD_JACOBIAN_MODIFIED: + W1 = getJacobianModifiedW(); + break; + default: + throw new IllegalStateException("unsupported coordinate system"); + } + } + + for (int i = 0; i < e; ++i) + { + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + ECFieldElement X1Squared = X1.square(); + ECFieldElement M = three(X1Squared); + ECFieldElement _2Y1 = two(Y1); + ECFieldElement _2Y1Squared = _2Y1.multiply(Y1); + ECFieldElement S = two(X1.multiply(_2Y1Squared)); + ECFieldElement _4T = _2Y1Squared.square(); + ECFieldElement _8T = two(_4T); + + if (!W1.isZero()) + { + M = M.add(W1); + W1 = two(_8T.multiply(W1)); + } + + X1 = M.square().subtract(two(S)); + Y1 = M.multiply(S.subtract(X1)).subtract(_8T); + Z1 = Z1.isOne() ? _2Y1 : _2Y1.multiply(Z1); + } + + switch (coord) + { + case ECCurve.COORD_AFFINE: + ECFieldElement zInv = Z1.invert(), zInv2 = zInv.square(), zInv3 = zInv2.multiply(zInv); + return new Fp(curve, X1.multiply(zInv2), Y1.multiply(zInv3), this.withCompression); + case ECCurve.COORD_HOMOGENEOUS: + X1 = X1.multiply(Z1); + Z1 = Z1.multiply(Z1.square()); + return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1 }, this.withCompression); + case ECCurve.COORD_JACOBIAN: + return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1 }, this.withCompression); + case ECCurve.COORD_JACOBIAN_MODIFIED: + return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1, W1 }, this.withCompression); + default: + throw new IllegalStateException("unsupported coordinate system"); + } + } + protected ECFieldElement two(ECFieldElement x) { return x.add(x); @@ -1027,18 +1268,6 @@ public abstract class ECPoint return a.add(b).square().subtract(aSquared).subtract(bSquared); } - // D.3.2 pg 102 (see Note:) - public ECPoint subtract(ECPoint b) - { - if (b.isInfinity()) - { - return this; - } - - // Add -b - return add(b.negate()); - } - public ECPoint negate() { if (this.isInfinity()) @@ -1059,13 +1288,18 @@ public abstract class ECPoint protected ECFieldElement calculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared) { + ECFieldElement a4 = this.getCurve().getA(); + if (a4.isZero() || Z.isOne()) + { + return a4; + } + if (ZSquared == null) { ZSquared = Z.square(); } ECFieldElement W = ZSquared.square(); - ECFieldElement a4 = this.getCurve().getA(); ECFieldElement a4Neg = a4.negate(); if (a4Neg.bitLength() < a4.bitLength()) { @@ -1095,23 +1329,252 @@ public abstract class ECPoint ECFieldElement X1Squared = X1.square(); ECFieldElement M = three(X1Squared).add(W1); - ECFieldElement Y1Squared = Y1.square(); - ECFieldElement T = Y1Squared.square(); - ECFieldElement S = two(doubleProductFromSquares(X1, Y1Squared, X1Squared, T)); + ECFieldElement _2Y1 = two(Y1); + ECFieldElement _2Y1Squared = _2Y1.multiply(Y1); + ECFieldElement S = two(X1.multiply(_2Y1Squared)); ECFieldElement X3 = M.square().subtract(two(S)); - ECFieldElement _8T = eight(T); + ECFieldElement _4T = _2Y1Squared.square(); + ECFieldElement _8T = two(_4T); ECFieldElement Y3 = M.multiply(S.subtract(X3)).subtract(_8T); ECFieldElement W3 = calculateW ? two(_8T.multiply(W1)) : null; - ECFieldElement Z3 = two(Z1.bitLength() == 1 ? Y1 : Y1.multiply(Z1)); + ECFieldElement Z3 = Z1.isOne() ? _2Y1 : _2Y1.multiply(Z1); return new ECPoint.Fp(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }, this.withCompression); } } + public static abstract class AbstractF2m extends ECPoint + { + protected AbstractF2m(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + super(curve, x, y); + } + + protected AbstractF2m(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) + { + super(curve, x, y, zs); + } + + protected boolean satisfiesCurveEquation() + { + ECCurve curve = this.getCurve(); + ECFieldElement X = this.x, A = curve.getA(), B = curve.getB(); + + int coord = curve.getCoordinateSystem(); + if (coord == ECCurve.COORD_LAMBDA_PROJECTIVE) + { + ECFieldElement Z = this.zs[0]; + boolean ZIsOne = Z.isOne(); + + if (X.isZero()) + { + // NOTE: For x == 0, we expect the affine-y instead of the lambda-y + ECFieldElement Y = this.y; + ECFieldElement lhs = Y.square(), rhs = B; + if (!ZIsOne) + { + rhs = rhs.multiply(Z.square()); + } + return lhs.equals(rhs); + } + + ECFieldElement L = this.y, X2 = X.square(); + ECFieldElement lhs, rhs; + if (ZIsOne) + { + lhs = L.square().add(L).add(A); + rhs = X2.square().add(B); + } + else + { + ECFieldElement Z2 = Z.square(), Z4 = Z2.square(); + lhs = L.add(Z).multiplyPlusProduct(L, A, Z2); + // TODO If sqrt(b) is precomputed this can be simplified to a single square + rhs = X2.squarePlusProduct(B, Z4); + } + lhs = lhs.multiply(X2); + return lhs.equals(rhs); + } + + ECFieldElement Y = this.y; + ECFieldElement lhs = Y.add(X).multiply(Y); + + switch (coord) + { + case ECCurve.COORD_AFFINE: + break; + case ECCurve.COORD_HOMOGENEOUS: + { + ECFieldElement Z = this.zs[0]; + if (!Z.isOne()) + { + ECFieldElement Z2 = Z.square(), Z3 = Z.multiply(Z2); + lhs = lhs.multiply(Z); + A = A.multiply(Z); + B = B.multiply(Z3); + } + break; + } + default: + throw new IllegalStateException("unsupported coordinate system"); + } + + ECFieldElement rhs = X.add(A).multiply(X.square()).add(B); + return lhs.equals(rhs); + } + + public ECPoint scaleX(ECFieldElement scale) + { + if (this.isInfinity()) + { + return this; + } + + int coord = this.getCurveCoordinateSystem(); + + switch (coord) + { + case ECCurve.COORD_LAMBDA_AFFINE: + { + // Y is actually Lambda (X + Y/X) here + ECFieldElement X = this.getRawXCoord(), L = this.getRawYCoord(); // earlier JDK + + ECFieldElement X2 = X.multiply(scale); + ECFieldElement L2 = L.add(X).divide(scale).add(X2); + + return this.getCurve().createRawPoint(X, L2, this.getRawZCoords(), this.withCompression); // earlier JDK + } + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + // Y is actually Lambda (X + Y/X) here + ECFieldElement X = this.getRawXCoord(), L = this.getRawYCoord(), Z = this.getRawZCoords()[0]; // earlier JDK + + // We scale the Z coordinate also, to avoid an inversion + ECFieldElement X2 = X.multiply(scale.square()); + ECFieldElement L2 = L.add(X).add(X2); + ECFieldElement Z2 = Z.multiply(scale); + + return this.getCurve().createRawPoint(X2, L2, new ECFieldElement[]{ Z2 }, this.withCompression); // earlier JDK + } + default: + { + return super.scaleX(scale); + } + } + } + + public ECPoint scaleY(ECFieldElement scale) + { + if (this.isInfinity()) + { + return this; + } + + int coord = this.getCurveCoordinateSystem(); + + switch (coord) + { + case ECCurve.COORD_LAMBDA_AFFINE: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement X = this.getRawXCoord(), L = this.getRawYCoord(); // earlier JDK + + // Y is actually Lambda (X + Y/X) here + ECFieldElement L2 = L.add(X).multiply(scale).add(X); + + return this.getCurve().createRawPoint(X, L2, this.getRawZCoords(), this.withCompression); // earlier JDK + } + default: + { + return super.scaleY(scale); + } + } + } + + public ECPoint subtract(ECPoint b) + { + if (b.isInfinity()) + { + return this; + } + + // Add -b + return this.add(b.negate()); + } + + public ECPoint.AbstractF2m tau() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + int coord = curve.getCoordinateSystem(); + + ECFieldElement X1 = this.x; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + { + ECFieldElement Y1 = this.y; + return (ECPoint.AbstractF2m)curve.createRawPoint(X1.square(), Y1.square(), this.withCompression); + } + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement Y1 = this.y, Z1 = this.zs[0]; + return (ECPoint.AbstractF2m)curve.createRawPoint(X1.square(), Y1.square(), + new ECFieldElement[]{ Z1.square() }, this.withCompression); + } + default: + { + throw new IllegalStateException("unsupported coordinate system"); + } + } + } + + public ECPoint.AbstractF2m tauPow(int pow) + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + int coord = curve.getCoordinateSystem(); + + ECFieldElement X1 = this.x; + + switch (coord) + { + case ECCurve.COORD_AFFINE: + case ECCurve.COORD_LAMBDA_AFFINE: + { + ECFieldElement Y1 = this.y; + return (ECPoint.AbstractF2m)curve.createRawPoint(X1.squarePow(pow), Y1.squarePow(pow), this.withCompression); + } + case ECCurve.COORD_HOMOGENEOUS: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement Y1 = this.y, Z1 = this.zs[0]; + return (ECPoint.AbstractF2m)curve.createRawPoint(X1.squarePow(pow), Y1.squarePow(pow), + new ECFieldElement[]{ Z1.squarePow(pow) }, this.withCompression); + } + default: + { + throw new IllegalStateException("unsupported coordinate system"); + } + } + } + } + /** * Elliptic curve points over F2m */ - public static class F2m extends ECPoint + public static class F2m extends AbstractF2m { /** * @param curve base curve @@ -1137,7 +1600,7 @@ public abstract class ECPoint { super(curve, x, y); - if ((x != null && y == null) || (x == null && y != null)) + if ((x == null) != (y == null)) { throw new IllegalArgumentException("Exactly one of the field elements is null"); } @@ -1168,6 +1631,11 @@ public abstract class ECPoint // checkCurveEquation(); } + protected ECPoint detach() + { + return new ECPoint.F2m(null, this.getAffineXCoord(), this.getAffineYCoord()); // earlier JDK + } + public ECFieldElement getYCoord() { int coord = this.getCurveCoordinateSystem(); @@ -1177,19 +1645,19 @@ public abstract class ECPoint case ECCurve.COORD_LAMBDA_AFFINE: case ECCurve.COORD_LAMBDA_PROJECTIVE: { - // TODO The X == 0 stuff needs further thought - if (this.isInfinity() || x.isZero()) + ECFieldElement X = x, L = y; + + if (this.isInfinity() || X.isZero()) { - return y; + return L; } // Y is actually Lambda (X + Y/X) here; convert to affine value on the fly - ECFieldElement X = x, L = y; - ECFieldElement Y = L.subtract(X).multiply(X); + ECFieldElement Y = L.add(X).multiply(X); if (ECCurve.COORD_LAMBDA_PROJECTIVE == coord) { ECFieldElement Z = zs[0]; - if (Z.bitLength() != 1) + if (!Z.isOne()) { Y = Y.divide(Z); } @@ -1219,7 +1687,7 @@ public abstract class ECPoint case ECCurve.COORD_LAMBDA_PROJECTIVE: { // Y is actually Lambda (X + Y/X) here - return Y.subtract(X).testBitZero(); + return Y.testBitZero() != X.testBitZero(); } default: { @@ -1228,44 +1696,7 @@ public abstract class ECPoint } } - /** - * Check, if two ECPoints can be added or subtracted. - * @param a The first ECPoint to check. - * @param b The second ECPoint to check. - * @throws IllegalArgumentException if a and b - * cannot be added. - */ - private static void checkPoints(ECPoint a, ECPoint b) - { - // Check, if points are on the same curve - if (a.curve != b.curve) - { - throw new IllegalArgumentException("Only points on the same " - + "curve can be added or subtracted"); - } - -// ECFieldElement.F2m.checkFieldElements(a.x, b.x); - } - - /* (non-Javadoc) - * @see org.bouncycastle.math.ec.ECPoint#add(org.bouncycastle.math.ec.ECPoint) - */ public ECPoint add(ECPoint b) - { - checkPoints(this, b); - return addSimple((ECPoint.F2m)b); - } - - /** - * Adds another ECPoints.F2m to this without - * checking if both points are on the same curve. Used by multiplication - * algorithms, because there all points are a multiple of the same point - * and hence the checks can be omitted. - * @param b The other ECPoints.F2m to add to - * this. - * @return this + b - */ - public ECPoint.F2m addSimple(ECPoint.F2m b) { if (this.isInfinity()) { @@ -1289,20 +1720,20 @@ public abstract class ECPoint ECFieldElement Y1 = this.y; ECFieldElement Y2 = b.y; - if (X1.equals(X2)) + ECFieldElement dx = X1.add(X2), dy = Y1.add(Y2); + if (dx.isZero()) { - if (Y1.equals(Y2)) + if (dy.isZero()) { - return (ECPoint.F2m)twice(); + return twice(); } - return (ECPoint.F2m)curve.getInfinity(); + return curve.getInfinity(); } - ECFieldElement sumX = X1.add(X2); - ECFieldElement L = Y1.add(Y2).divide(sumX); + ECFieldElement L = dy.divide(dx); - ECFieldElement X3 = L.square().add(L).add(sumX).add(curve.getA()); + ECFieldElement X3 = L.square().add(L).add(dx).add(curve.getA()); ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); return new ECPoint.F2m(curve, X3, Y3, this.withCompression); @@ -1312,33 +1743,35 @@ public abstract class ECPoint ECFieldElement Y1 = this.y, Z1 = this.zs[0]; ECFieldElement Y2 = b.y, Z2 = b.zs[0]; - boolean Z2IsOne = Z2.bitLength() == 1; + boolean Z2IsOne = Z2.isOne(); - ECFieldElement U1 = Z1.multiply(Y2); + ECFieldElement U1 = Z1.multiply(Y2); ECFieldElement U2 = Z2IsOne ? Y1 : Y1.multiply(Z2); - ECFieldElement U = U1.subtract(U2); + ECFieldElement U = U1.add(U2); ECFieldElement V1 = Z1.multiply(X2); ECFieldElement V2 = Z2IsOne ? X1 : X1.multiply(Z2); - ECFieldElement V = V1.subtract(V2); + ECFieldElement V = V1.add(V2); - if (V1.equals(V2)) + if (V.isZero()) { - if (U1.equals(U2)) + if (U.isZero()) { - return (ECPoint.F2m)twice(); + return twice(); } - return (ECPoint.F2m)curve.getInfinity(); + return curve.getInfinity(); } - ECFieldElement VSq = V.square(); + ECFieldElement VSq = V.square(); + ECFieldElement VCu = VSq.multiply(V); ECFieldElement W = Z2IsOne ? Z1 : Z1.multiply(Z2); - ECFieldElement A = U.square().add(U.multiply(V).add(VSq.multiply(curve.getA()))).multiply(W).add(V.multiply(VSq)); + ECFieldElement uv = U.add(V); + ECFieldElement A = uv.multiplyPlusProduct(U, VSq, curve.getA()).multiply(W).add(VCu); ECFieldElement X3 = V.multiply(A); ECFieldElement VSqZ2 = Z2IsOne ? VSq : VSq.multiply(Z2); - ECFieldElement Y3 = VSqZ2.multiply(U.multiply(X1).add(Y1.multiply(V))).add(A.multiply(U.add(V))); - ECFieldElement Z3 = VSq.multiply(V).multiply(W); + ECFieldElement Y3 = U.multiplyPlusProduct(X1, V, Y1).multiplyPlusProduct(VSqZ2, uv, A); + ECFieldElement Z3 = VCu.multiply(W); return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); } @@ -1346,13 +1779,18 @@ public abstract class ECPoint { if (X1.isZero()) { - return b.addSimple(this); + if (X2.isZero()) + { + return curve.getInfinity(); + } + + return b.add(this); } ECFieldElement L1 = this.y, Z1 = this.zs[0]; ECFieldElement L2 = b.y, Z2 = b.zs[0]; - boolean Z1IsOne = Z1.bitLength() == 1; + boolean Z1IsOne = Z1.isOne(); ECFieldElement U2 = X2, S2 = L2; if (!Z1IsOne) { @@ -1360,7 +1798,7 @@ public abstract class ECPoint S2 = S2.multiply(Z1); } - boolean Z2IsOne = Z2.bitLength() == 1; + boolean Z2IsOne = Z2.isOne(); ECFieldElement U1 = X1, S1 = L1; if (!Z2IsOne) { @@ -1375,23 +1813,31 @@ public abstract class ECPoint { if (A.isZero()) { - return (ECPoint.F2m)twice(); + return twice(); } - return (ECPoint.F2m)curve.getInfinity(); + return curve.getInfinity(); } ECFieldElement X3, L3, Z3; if (X2.isZero()) { // TODO This can probably be optimized quite a bit + ECPoint p = this.normalize(); + X1 = p.getXCoord(); + ECFieldElement Y1 = p.getYCoord(); - ECFieldElement Y1 = getYCoord(), Y2 = L2; + ECFieldElement Y2 = L2; ECFieldElement L = Y1.add(Y2).divide(X1); X3 = L.square().add(L).add(X1).add(curve.getA()); + if (X3.isZero()) + { + return new ECPoint.F2m(curve, X3, curve.getB().sqrt(), this.withCompression); + } + ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); - L3 = X3.isZero() ? Y3 : Y3.divide(X3).add(X3); + L3 = Y3.divide(X3).add(X3); Z3 = curve.fromBigInteger(ECConstants.ONE); } else @@ -1400,14 +1846,20 @@ public abstract class ECPoint ECFieldElement AU1 = A.multiply(U1); ECFieldElement AU2 = A.multiply(U2); + + X3 = AU1.multiply(AU2); + if (X3.isZero()) + { + return new ECPoint.F2m(curve, X3, curve.getB().sqrt(), this.withCompression); + } + ECFieldElement ABZ2 = A.multiply(B); if (!Z2IsOne) { ABZ2 = ABZ2.multiply(Z2); } - X3 = AU1.multiply(AU2); - L3 = AU2.add(B).square().add(ABZ2.multiply(L1.add(Z1))); + L3 = AU2.add(B).squarePlusProduct(ABZ2, L1.add(Z1)); Z3 = ABZ2; if (!Z1IsOne) @@ -1425,68 +1877,6 @@ public abstract class ECPoint } } - /* (non-Javadoc) - * @see org.bouncycastle.math.ec.ECPoint#subtract(org.bouncycastle.math.ec.ECPoint) - */ - public ECPoint subtract(ECPoint b) - { - checkPoints(this, b); - return subtractSimple((ECPoint.F2m)b); - } - - /** - * Subtracts another ECPoints.F2m from this - * without checking if both points are on the same curve. Used by - * multiplication algorithms, because there all points are a multiple - * of the same point and hence the checks can be omitted. - * @param b The other ECPoints.F2m to subtract from - * this. - * @return this - b - */ - public ECPoint.F2m subtractSimple(ECPoint.F2m b) - { - if (b.isInfinity()) - { - return this; - } - - // Add -b - return addSimple((ECPoint.F2m)b.negate()); - } - - public ECPoint.F2m tau() - { - if (this.isInfinity()) - { - return this; - } - - ECCurve curve = this.getCurve(); - int coord = curve.getCoordinateSystem(); - - ECFieldElement X1 = this.x; - - switch (coord) - { - case ECCurve.COORD_AFFINE: - case ECCurve.COORD_LAMBDA_AFFINE: - { - ECFieldElement Y1 = this.y; - return new ECPoint.F2m(curve, X1.square(), Y1.square(), this.withCompression); - } - case ECCurve.COORD_HOMOGENEOUS: - case ECCurve.COORD_LAMBDA_PROJECTIVE: - { - ECFieldElement Y1 = this.y, Z1 = this.zs[0]; - return new ECPoint.F2m(curve, X1.square(), Y1.square(), new ECFieldElement[]{ Z1.square() }, this.withCompression); - } - default: - { - throw new IllegalStateException("unsupported coordinate system"); - } - } - } - public ECPoint twice() { if (this.isInfinity()) @@ -1514,7 +1904,7 @@ public abstract class ECPoint ECFieldElement L1 = Y1.divide(X1).add(X1); ECFieldElement X3 = L1.square().add(L1).add(curve.getA()); - ECFieldElement Y3 = X1.square().add(X3.multiply(L1.addOne())); + ECFieldElement Y3 = X1.squarePlusProduct(X3, L1.addOne()); return new ECPoint.F2m(curve, X3, Y3, this.withCompression); } @@ -1522,7 +1912,7 @@ public abstract class ECPoint { ECFieldElement Y1 = this.y, Z1 = this.zs[0]; - boolean Z1IsOne = Z1.bitLength() == 1; + boolean Z1IsOne = Z1.isOne(); ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement Y1Z1 = Z1IsOne ? Y1 : Y1.multiply(Z1); @@ -1530,10 +1920,11 @@ public abstract class ECPoint ECFieldElement S = X1Sq.add(Y1Z1); ECFieldElement V = X1Z1; ECFieldElement vSquared = V.square(); - ECFieldElement h = S.square().add(S.multiply(V)).add(curve.getA().multiply(vSquared)); + ECFieldElement sv = S.add(V); + ECFieldElement h = sv.multiplyPlusProduct(S, vSquared, curve.getA()); ECFieldElement X3 = V.multiply(h); - ECFieldElement Y3 = h.multiply(S.add(V)).add(X1Sq.square().multiply(V)); + ECFieldElement Y3 = X1Sq.square().multiplyPlusProduct(V, h, sv); ECFieldElement Z3 = V.multiply(vSquared); return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); @@ -1542,12 +1933,16 @@ public abstract class ECPoint { ECFieldElement L1 = this.y, Z1 = this.zs[0]; - boolean Z1IsOne = Z1.bitLength() == 1; + boolean Z1IsOne = Z1.isOne(); ECFieldElement L1Z1 = Z1IsOne ? L1 : L1.multiply(Z1); ECFieldElement Z1Sq = Z1IsOne ? Z1 : Z1.square(); ECFieldElement a = curve.getA(); ECFieldElement aZ1Sq = Z1IsOne ? a : a.multiply(Z1Sq); ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); + if (T.isZero()) + { + return new ECPoint.F2m(curve, T, curve.getB().sqrt(), withCompression); + } ECFieldElement X3 = T.square(); ECFieldElement Z3 = Z1IsOne ? T : T.multiply(Z1Sq); @@ -1557,14 +1952,30 @@ public abstract class ECPoint if (b.bitLength() < (curve.getFieldSize() >> 1)) { ECFieldElement t1 = L1.add(X1).square(); - ECFieldElement t2 = aZ1Sq.square(); - ECFieldElement t3 = curve.getB().multiply(Z1Sq.square()); - L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2.add(t3)).add(X3).add(a.addOne().multiply(Z3)); + ECFieldElement t2; + if (b.isOne()) + { + t2 = aZ1Sq.add(Z1Sq).square(); + } + else + { + // TODO Can be calculated with one square if we pre-compute sqrt(b) + t2 = aZ1Sq.squarePlusProduct(b, Z1Sq.square()); + } + L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2).add(X3); + if (a.isZero()) + { + L3 = L3.add(Z3); + } + else if (!a.isOne()) + { + L3 = L3.add(a.addOne().multiply(Z3)); + } } else { ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); - L3 = X1Z1.square().add(X3).add(T.multiply(L1Z1)).add(Z3); + L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); } return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); @@ -1604,7 +2015,7 @@ public abstract class ECPoint { // NOTE: twicePlus() only optimized for lambda-affine argument ECFieldElement X2 = b.x, Z2 = b.zs[0]; - if (X2.isZero() || Z2.bitLength() != 1) + if (X2.isZero() || !Z2.isOne()) { return twice().add(b); } @@ -1619,13 +2030,28 @@ public abstract class ECPoint ECFieldElement T = curve.getA().multiply(Z1Sq).add(L1Sq).add(L1Z1); ECFieldElement L2plus1 = L2.addOne(); - ECFieldElement A = curve.getA().add(L2plus1).multiply(Z1Sq).add(L1Sq).multiply(T).add(X1Sq.multiply(Z1Sq)); + ECFieldElement A = curve.getA().add(L2plus1).multiply(Z1Sq).add(L1Sq).multiplyPlusProduct(T, X1Sq, Z1Sq); ECFieldElement X2Z1Sq = X2.multiply(Z1Sq); ECFieldElement B = X2Z1Sq.add(T).square(); + if (B.isZero()) + { + if (A.isZero()) + { + return b.twice(); + } + + return curve.getInfinity(); + } + + if (A.isZero()) + { + return new ECPoint.F2m(curve, A, curve.getB().sqrt(), withCompression); + } + ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); - ECFieldElement L3 = A.add(B).square().multiply(T).add(L2plus1.multiply(Z3)); + ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); } @@ -1636,57 +2062,6 @@ public abstract class ECPoint } } - protected void checkCurveEquation() - { - if (this.isInfinity()) - { - return; - } - - ECFieldElement Z; - switch (this.getCurveCoordinateSystem()) - { - case ECCurve.COORD_LAMBDA_AFFINE: - Z = curve.fromBigInteger(ECConstants.ONE); - break; - case ECCurve.COORD_LAMBDA_PROJECTIVE: - Z = this.zs[0]; - break; - default: - return; - } - - if (Z.isZero()) - { - throw new IllegalStateException(); - } - - ECFieldElement X = this.x; - if (X.isZero()) - { - // NOTE: For x == 0, we expect the affine-y instead of the lambda-y - ECFieldElement Y = this.y; - if (!Y.square().equals(curve.getB().multiply(Z))) - { - throw new IllegalStateException(); - } - - return; - } - - ECFieldElement L = this.y; - ECFieldElement XSq = X.square(); - ECFieldElement ZSq = Z.square(); - - ECFieldElement lhs = L.square().add(L.multiply(Z)).add(this.getCurve().getA().multiply(ZSq)).multiply(XSq); - ECFieldElement rhs = ZSq.square().multiply(this.getCurve().getB()).add(XSq.square()); - - if (!lhs.equals(rhs)) - { - throw new IllegalStateException("F2m Lambda-Projective invariant broken"); - } - } - public ECPoint negate() { if (this.isInfinity()) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECPointMap.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECPointMap.java new file mode 100644 index 0000000..439e8da --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ECPointMap.java @@ -0,0 +1,6 @@ +package org.bouncycastle.math.ec; + +public interface ECPointMap +{ + ECPoint map(ECPoint p); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java new file mode 100644 index 0000000..9fe00b9 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java @@ -0,0 +1,57 @@ +package org.bouncycastle.math.ec; + +import java.math.BigInteger; + +public class FixedPointCombMultiplier extends AbstractECMultiplier +{ + protected ECPoint multiplyPositive(ECPoint p, BigInteger k) + { + ECCurve c = p.getCurve(); + int size = FixedPointUtil.getCombSize(c); + + if (k.bitLength() > size) + { + /* + * TODO The comb works best when the scalars are less than the (possibly unknown) order. + * Still, if we want to handle larger scalars, we could allow customization of the comb + * size, or alternatively we could deal with the 'extra' bits either by running the comb + * multiple times as necessary, or by using an alternative multiplier as prelude. + */ + throw new IllegalStateException("fixed-point comb doesn't support scalars larger than the curve order"); + } + + int minWidth = getWidthForCombSize(size); + + FixedPointPreCompInfo info = FixedPointUtil.precompute(p, minWidth); + ECPoint[] lookupTable = info.getPreComp(); + int width = info.getWidth(); + + int d = (size + width - 1) / width; + + ECPoint R = c.getInfinity(); + + int top = d * width - 1; + for (int i = 0; i < d; ++i) + { + int index = 0; + + for (int j = top - i; j >= 0; j -= d) + { + index <<= 1; + if (k.testBit(j)) + { + index |= 1; + } + } + + R = R.twicePlus(lookupTable[index]); + } + + return R; + } + + protected int getWidthForCombSize(int combSize) + { + return combSize > 257 ? 6 : 5; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointPreCompInfo.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointPreCompInfo.java new file mode 100644 index 0000000..b7569aa --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointPreCompInfo.java @@ -0,0 +1,40 @@ +package org.bouncycastle.math.ec; + +/** + * Class holding precomputation data for fixed-point multiplications. + */ +public class FixedPointPreCompInfo implements PreCompInfo +{ + /** + * Array holding the precomputed ECPoints used for a fixed + * point multiplication. + */ + protected ECPoint[] preComp = null; + + /** + * The width used for the precomputation. If a larger width precomputation + * is already available this may be larger than was requested, so calling + * code should refer to the actual width. + */ + protected int width = -1; + + public ECPoint[] getPreComp() + { + return preComp; + } + + public void setPreComp(ECPoint[] preComp) + { + this.preComp = preComp; + } + + public int getWidth() + { + return width; + } + + public void setWidth(int width) + { + this.width = width; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointUtil.java new file mode 100644 index 0000000..e4fbb8d --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/FixedPointUtil.java @@ -0,0 +1,71 @@ +package org.bouncycastle.math.ec; + +import java.math.BigInteger; + +public class FixedPointUtil +{ + public static final String PRECOMP_NAME = "bc_fixed_point"; + + public static int getCombSize(ECCurve c) + { + BigInteger order = c.getOrder(); + return order == null ? c.getFieldSize() + 1 : order.bitLength(); + } + + public static FixedPointPreCompInfo getFixedPointPreCompInfo(PreCompInfo preCompInfo) + { + if ((preCompInfo != null) && (preCompInfo instanceof FixedPointPreCompInfo)) + { + return (FixedPointPreCompInfo)preCompInfo; + } + + return new FixedPointPreCompInfo(); + } + + public static FixedPointPreCompInfo precompute(ECPoint p, int minWidth) + { + ECCurve c = p.getCurve(); + + int n = 1 << minWidth; + FixedPointPreCompInfo info = getFixedPointPreCompInfo(c.getPreCompInfo(p, PRECOMP_NAME)); + ECPoint[] lookupTable = info.getPreComp(); + + if (lookupTable == null || lookupTable.length < n) + { + int bits = getCombSize(c); + int d = (bits + minWidth - 1) / minWidth; + + ECPoint[] pow2Table = new ECPoint[minWidth]; + pow2Table[0] = p; + for (int i = 1; i < minWidth; ++i) + { + pow2Table[i] = pow2Table[i - 1].timesPow2(d); + } + + c.normalizeAll(pow2Table); + + lookupTable = new ECPoint[n]; + lookupTable[0] = c.getInfinity(); + + for (int bit = minWidth - 1; bit >= 0; --bit) + { + ECPoint pow2 = pow2Table[bit]; + + int step = 1 << bit; + for (int i = step; i < n; i += (step << 1)) + { + lookupTable[i] = lookupTable[i - step].add(pow2); + } + } + + c.normalizeAll(lookupTable); + + info.setPreComp(lookupTable); + info.setWidth(minWidth); + + c.setPreCompInfo(p, PRECOMP_NAME, info); + } + + return info; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java new file mode 100644 index 0000000..09b8366 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java @@ -0,0 +1,42 @@ +package org.bouncycastle.math.ec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.endo.GLVEndomorphism; + +public class GLVMultiplier extends AbstractECMultiplier +{ + protected final ECCurve curve; + protected final GLVEndomorphism glvEndomorphism; + + public GLVMultiplier(ECCurve curve, GLVEndomorphism glvEndomorphism) + { + if (curve == null || curve.getOrder() == null) + { + throw new IllegalArgumentException("Need curve with known group order"); + } + + this.curve = curve; + this.glvEndomorphism = glvEndomorphism; + } + + protected ECPoint multiplyPositive(ECPoint p, BigInteger k) + { + if (!curve.equals(p.getCurve())) + { + throw new IllegalStateException(); + } + + BigInteger n = p.getCurve().getOrder(); + BigInteger[] ab = glvEndomorphism.decomposeScalar(k.mod(n)); + BigInteger a = ab[0], b = ab[1]; + + ECPointMap pointMap = glvEndomorphism.getPointMap(); + if (glvEndomorphism.hasEfficientPointMap()) + { + return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap, b); + } + + return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap.map(p), b); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java deleted file mode 100644 index 34395a5..0000000 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java +++ /dev/null @@ -1,860 +0,0 @@ -package org.bouncycastle.math.ec; - -import org.bouncycastle.util.Arrays; - -import java.math.BigInteger; - -class IntArray -{ -// private static int DEINTERLEAVE_MASK = 0x55555555; - - /* - * This expands 8 bit indices into 16 bit contents, by inserting 0s between bits. - * In a binary field, this operation is the same as squaring an 8 bit number. - */ - private static final int[] INTERLEAVE_TABLE = new int[] { 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, - 0x0015, 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, 0x0105, 0x0110, - 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 0x0400, 0x0401, 0x0404, - 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, - 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, - 0x0555, 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, - 0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141, 0x1144, - 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440, - 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, - 0x1515, 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, - 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104, - 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 0x4400, - 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, - 0x4455, 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, - 0x4551, 0x4554, 0x4555, 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 0x5040, 0x5041, 0x5044, - 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, - 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, - 0x5415, 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, - 0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555 }; - - // For toString(); must have length 32 - private static final String ZEROES = "00000000000000000000000000000000"; - - private final static byte[] bitLengths = - { - 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 - }; - - public static int getWordLength(int bits) - { - return (bits + 31) >>> 5; - } - - // TODO make m fixed for the IntArray, and hence compute T once and for all - - private int[] m_ints; - - public IntArray(int intLen) - { - m_ints = new int[intLen]; - } - - public IntArray(int[] ints) - { - m_ints = ints; - } - - public IntArray(BigInteger bigInt) - { - if (bigInt == null || bigInt.signum() < 0) - { - throw new IllegalArgumentException("invalid F2m field value"); - } - - if (bigInt.signum() == 0) - { - m_ints = new int[] { 0 }; - return; - } - - byte[] barr = bigInt.toByteArray(); - int barrLen = barr.length; - int barrStart = 0; - if (barr[0] == 0) - { - // First byte is 0 to enforce highest (=sign) bit is zero. - // In this case ignore barr[0]. - barrLen--; - barrStart = 1; - } - int intLen = (barrLen + 3) / 4; - m_ints = new int[intLen]; - - int iarrJ = intLen - 1; - int rem = barrLen % 4 + barrStart; - int temp = 0; - int barrI = barrStart; - if (barrStart < rem) - { - for (; barrI < rem; barrI++) - { - temp <<= 8; - int barrBarrI = barr[barrI] & 0xFF; - temp |= barrBarrI; - } - m_ints[iarrJ--] = temp; - } - - for (; iarrJ >= 0; iarrJ--) - { - temp = 0; - for (int i = 0; i < 4; i++) - { - temp <<= 8; - int barrBarrI = barr[barrI++] & 0xFF; - temp |= barrBarrI; - } - m_ints[iarrJ] = temp; - } - } - - public boolean isZero() - { - int[] a = m_ints; - for (int i = 0; i < a.length; ++i) - { - if (a[i] != 0) - { - return false; - } - } - return true; - } - - public int getUsedLength() - { - return getUsedLengthFrom(m_ints.length); - } - - public int getUsedLengthFrom(int from) - { - int[] a = m_ints; - from = Math.min(from, a.length); - - if (from < 1) - { - return 0; - } - - // Check if first element will act as sentinel - if (a[0] != 0) - { - while (a[--from] == 0) - { - } - return from + 1; - } - - do - { - if (a[--from] != 0) - { - return from + 1; - } - } - while (from > 0); - - return 0; - } - - public int degree() - { - int i = m_ints.length, w; - do - { - if (i == 0) - { - return 0; - } - w = m_ints[--i]; - } - while (w == 0); - - return (i << 5) + bitLength(w); - } - - private static int bitLength(int w) - { - int t = w >>> 16; - if (t == 0) - { - t = w >>> 8; - return (t == 0) ? bitLengths[w] : 8 + bitLengths[t]; - } - - int u = t >>> 8; - return (u == 0) ? 16 + bitLengths[t] : 24 + bitLengths[u]; - } - - private int[] resizedInts(int newLen) - { - int[] newInts = new int[newLen]; - System.arraycopy(m_ints, 0, newInts, 0, Math.min(m_ints.length, newLen)); - return newInts; - } - - public BigInteger toBigInteger() - { - int usedLen = getUsedLength(); - if (usedLen == 0) - { - return ECConstants.ZERO; - } - - int highestInt = m_ints[usedLen - 1]; - byte[] temp = new byte[4]; - int barrI = 0; - boolean trailingZeroBytesDone = false; - for (int j = 3; j >= 0; j--) - { - byte thisByte = (byte) (highestInt >>> (8 * j)); - if (trailingZeroBytesDone || (thisByte != 0)) - { - trailingZeroBytesDone = true; - temp[barrI++] = thisByte; - } - } - - int barrLen = 4 * (usedLen - 1) + barrI; - byte[] barr = new byte[barrLen]; - for (int j = 0; j < barrI; j++) - { - barr[j] = temp[j]; - } - // Highest value int is done now - - for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--) - { - for (int j = 3; j >= 0; j--) - { - barr[barrI++] = (byte) (m_ints[iarrJ] >>> (8 * j)); - } - } - return new BigInteger(1, barr); - } - - private static int shiftLeft(int[] x, int count) - { - int prev = 0; - for (int i = 0; i < count; ++i) - { - int next = x[i]; - x[i] = (next << 1) | prev; - prev = next >>> 31; - } - return prev; - } - - public void addOneShifted(int shift) - { - if (shift >= m_ints.length) - { - m_ints = resizedInts(shift + 1); - } - - m_ints[shift] ^= 1; - } - - private void addShiftedByBits(IntArray other, int bits) - { - int words = bits >>> 5; - int shift = bits & 0x1F; - - if (shift == 0) - { - addShiftedByWords(other, words); - return; - } - - int otherUsedLen = other.getUsedLength(); - if (otherUsedLen == 0) - { - return; - } - - int minLen = otherUsedLen + words + 1; - if (minLen > m_ints.length) - { - m_ints = resizedInts(minLen); - } - - int shiftInv = 32 - shift, prev = 0; - for (int i = 0; i < otherUsedLen; ++i) - { - int next = other.m_ints[i]; - m_ints[i + words] ^= (next << shift) | prev; - prev = next >>> shiftInv; - } - m_ints[otherUsedLen + words] ^= prev; - } - - private static int addShiftedByBits(int[] x, int[] y, int count, int shift) - { - int shiftInv = 32 - shift, prev = 0; - for (int i = 0; i < count; ++i) - { - int next = y[i]; - x[i] ^= (next << shift) | prev; - prev = next >>> shiftInv; - } - return prev; - } - - private static int addShiftedByBits(int[] x, int xOff, int[] y, int yOff, int count, int shift) - { - int shiftInv = 32 - shift, prev = 0; - for (int i = 0; i < count; ++i) - { - int next = y[yOff + i]; - x[xOff + i] ^= (next << shift) | prev; - prev = next >>> shiftInv; - } - return prev; - } - - public void addShiftedByWords(IntArray other, int words) - { - int otherUsedLen = other.getUsedLength(); - if (otherUsedLen == 0) - { - return; - } - - int minLen = otherUsedLen + words; - if (minLen > m_ints.length) - { - m_ints = resizedInts(minLen); - } - - for (int i = 0; i < otherUsedLen; i++) - { - m_ints[words + i] ^= other.m_ints[i]; - } - } - - private static void addShiftedByWords(int[] x, int xOff, int[] y, int count) - { - for (int i = 0; i < count; ++i) - { - x[xOff + i] ^= y[i]; - } - } - - private static void add(int[] x, int[] y, int count) - { - for (int i = 0; i < count; ++i) - { - x[i] ^= y[i]; - } - } - - private static void distribute(int[] x, int dst1, int dst2, int src, int count) - { - for (int i = 0; i < count; ++i) - { - int v = x[src + i]; - x[dst1 + i] ^= v; - x[dst2 + i] ^= v; - } - } - - public int getLength() - { - return m_ints.length; - } - - public void flipWord(int bit, int word) - { - int len = m_ints.length; - int n = bit >>> 5; - if (n < len) - { - int shift = bit & 0x1F; - if (shift == 0) - { - m_ints[n] ^= word; - } - else - { - m_ints[n] ^= word << shift; - if (++n < len) - { - m_ints[n] ^= word >>> (32 - shift); - } - } - } - } - - public int getWord(int bit) - { - int len = m_ints.length; - int n = bit >>> 5; - if (n >= len) - { - return 0; - } - int shift = bit & 0x1F; - if (shift == 0) - { - return m_ints[n]; - } - int result = m_ints[n] >>> shift; - if (++n < len) - { - result |= m_ints[n] << (32 - shift); - } - return result; - } - - public boolean testBitZero() - { - return m_ints.length > 0 && (m_ints[0] & 1) != 0; - } - - public boolean testBit(int n) - { - // theInt = n / 32 - int theInt = n >>> 5; - // theBit = n % 32 - int theBit = n & 0x1F; - int tester = 1 << theBit; - return ((m_ints[theInt] & tester) != 0); - } - - public void flipBit(int n) - { - // theInt = n / 32 - int theInt = n >>> 5; - // theBit = n % 32 - int theBit = n & 0x1F; - int flipper = 1 << theBit; - m_ints[theInt] ^= flipper; - } - - public void setBit(int n) - { - // theInt = n / 32 - int theInt = n >>> 5; - // theBit = n % 32 - int theBit = n & 0x1F; - int setter = 1 << theBit; - m_ints[theInt] |= setter; - } - - public void clearBit(int n) - { - // theInt = n / 32 - int theInt = n >>> 5; - // theBit = n % 32 - int theBit = n & 0x1F; - int setter = 1 << theBit; - m_ints[theInt] &= ~setter; - } - - public IntArray multiply(IntArray other, int m) - { - int aLen = getUsedLength(); - if (aLen == 0) - { - return new IntArray(1); - } - - int bLen = other.getUsedLength(); - if (bLen == 0) - { - return new IntArray(1); - } - - IntArray A = this, B = other; - if (aLen > bLen) - { - A = other; B = this; - int tmp = aLen; aLen = bLen; bLen = tmp; - } - - if (aLen == 1) - { - int a = A.m_ints[0]; - int[] b = B.m_ints; - int[] c = new int[aLen + bLen]; - if ((a & 1) != 0) - { - add(c, b, bLen); - } - int k = 1; - while ((a >>>= 1) != 0) - { - if ((a & 1) != 0) - { - addShiftedByBits(c, b, bLen, k); - } - ++k; - } - return new IntArray(c); - } - - // TODO It'd be better to be able to tune the width directly (need support for interleaving arbitrary widths) - int complexity = aLen <= 8 ? 1 : 2; - - int width = 1 << complexity; - int shifts = (32 >>> complexity); - - int bExt = bLen; - if ((B.m_ints[bLen - 1] >>> (33 - shifts)) != 0) - { - ++bExt; - } - - int cLen = bExt + aLen; - - int[] c = new int[cLen << width]; - System.arraycopy(B.m_ints, 0, c, 0, bLen); - interleave(A.m_ints, 0, c, bExt, aLen, complexity); - - int[] ci = new int[1 << width]; - for (int i = 1; i < ci.length; ++i) - { - ci[i] = ci[i - 1] + cLen; - } - - int MASK = (1 << width) - 1; - - int k = 0; - for (;;) - { - for (int aPos = 0; aPos < aLen; ++aPos) - { - int index = (c[bExt + aPos] >>> k) & MASK; - if (index != 0) - { - addShiftedByWords(c, aPos + ci[index], c, bExt); - } - } - - if ((k += width) >= 32) - { - break; - } - - shiftLeft(c, bExt); - } - - int ciPos = ci.length, pow2 = ciPos >>> 1, offset = 32; - while (--ciPos > 1) - { - if (ciPos == pow2) - { - offset -= shifts; - addShiftedByBits(c, ci[1], c, ci[pow2], cLen, offset); - pow2 >>>= 1; - } - else - { - distribute(c, ci[pow2], ci[ciPos - pow2], ci[ciPos], cLen); - } - } - - // TODO reduce in place to avoid extra copying - IntArray p = new IntArray(cLen); - System.arraycopy(c, ci[1], p.m_ints, 0, cLen); - return p; - } - -// private static void deInterleave(int[] x, int xOff, int[] z, int zOff, int count, int rounds) -// { -// for (int i = 0; i < count; ++i) -// { -// z[zOff + i] = deInterleave(x[zOff + i], rounds); -// } -// } -// -// private static int deInterleave(int x, int rounds) -// { -// while (--rounds >= 0) -// { -// x = deInterleave16(x & DEINTERLEAVE_MASK) | (deInterleave16((x >>> 1) & DEINTERLEAVE_MASK) << 16); -// } -// return x; -// } -// -// private static int deInterleave16(int x) -// { -// x = (x | (x >>> 1)) & 0x33333333; -// x = (x | (x >>> 2)) & 0x0F0F0F0F; -// x = (x | (x >>> 4)) & 0x00FF00FF; -// x = (x | (x >>> 8)) & 0x0000FFFF; -// return x; -// } - - public void reduce(int m, int[] ks) - { - int len = getUsedLength(); - int mLen = (m + 31) >>> 5; - if (len < mLen) - { - return; - } - - int _2m = m << 1; - int pos = Math.min(_2m - 2, (len << 5) - 1); - - int kMax = ks[ks.length - 1]; - if (kMax < m - 31) - { - reduceWordWise(pos, m, ks); - } - else - { - reduceBitWise(pos, m, ks); - } - - // Instead of flipping the high bits in the loop, explicitly clear any partial word above m bits - int partial = m & 0x1F; - if (partial != 0) - { - m_ints[mLen - 1] &= (1 << partial) - 1; - } - - if (len > mLen) - { - m_ints = resizedInts(mLen); - } - } - - private void reduceBitWise(int from, int m, int[] ks) - { - for (int i = from; i >= m; --i) - { - if (testBit(i)) - { -// clearBit(i); - int bit = i - m; - flipBit(bit); - int j = ks.length; - while (--j >= 0) - { - flipBit(ks[j] + bit); - } - } - } - } - - private void reduceWordWise(int from, int m, int[] ks) - { - int pos = m + ((from - m) & ~0x1F); - for (int i = pos; i >= m; i -= 32) - { - int word = getWord(i); - if (word != 0) - { -// flipWord(i); - int bit = i - m; - flipWord(bit, word); - int j = ks.length; - while (--j >= 0) - { - flipWord(ks[j] + bit, word); - } - } - } - } - - public IntArray square(int m) - { - int len = getUsedLength(); - if (len == 0) - { - return this; - } - - int _2len = len << 1; - int[] r = new int[_2len]; - - int pos = 0; - while (pos < _2len) - { - int mi = m_ints[pos >>> 1]; - r[pos++] = interleave16(mi & 0xFFFF); - r[pos++] = interleave16(mi >>> 16); - } - - return new IntArray(r); - } - - private static void interleave(int[] x, int xOff, int[] z, int zOff, int count, int rounds) - { - for (int i = 0; i < count; ++i) - { - z[zOff + i] = interleave(x[xOff + i], rounds); - } - } - - private static int interleave(int x, int rounds) - { - while (--rounds >= 0) - { - x = interleave16(x & 0xFFFF) | (interleave16(x >>> 16) << 1); - } - return x; - } - - private static int interleave16(int n) - { - return INTERLEAVE_TABLE[n & 0xFF] | INTERLEAVE_TABLE[n >>> 8] << 16; - } - - public IntArray modInverse(int m, int[] ks) - { - // Inversion in F2m using the extended Euclidean algorithm - // Input: A nonzero polynomial a(z) of degree at most m-1 - // Output: a(z)^(-1) mod f(z) - - int uzDegree = degree(); - if (uzDegree == 1) - { - return this; - } - - // u(z) := a(z) - IntArray uz = (IntArray)clone(); - - int t = getWordLength(m); - - // v(z) := f(z) - IntArray vz = new IntArray(t); - vz.setBit(m); - vz.setBit(0); - vz.setBit(ks[0]); - if (ks.length > 1) - { - vz.setBit(ks[1]); - vz.setBit(ks[2]); - } - - // g1(z) := 1, g2(z) := 0 - IntArray g1z = new IntArray(t); - g1z.setBit(0); - IntArray g2z = new IntArray(t); - - while (uzDegree != 0) - { - // j := deg(u(z)) - deg(v(z)) - int j = uzDegree - vz.degree(); - - // If j < 0 then: u(z) <-> v(z), g1(z) <-> g2(z), j := -j - if (j < 0) - { - final IntArray uzCopy = uz; - uz = vz; - vz = uzCopy; - - final IntArray g1zCopy = g1z; - g1z = g2z; - g2z = g1zCopy; - - j = -j; - } - - // u(z) := u(z) + z^j * v(z) - // Note, that no reduction modulo f(z) is required, because - // deg(u(z) + z^j * v(z)) <= max(deg(u(z)), j + deg(v(z))) - // = max(deg(u(z)), deg(u(z)) - deg(v(z)) + deg(v(z)) - // = deg(u(z)) - // uz = uz.xor(vz.shiftLeft(j)); - uz.addShiftedByBits(vz, j); - uzDegree = uz.degree(); - - // g1(z) := g1(z) + z^j * g2(z) -// g1z = g1z.xor(g2z.shiftLeft(j)); - if (uzDegree != 0) - { - g1z.addShiftedByBits(g2z, j); - } - } - return g2z; - } - - public boolean equals(Object o) - { - if (!(o instanceof IntArray)) - { - return false; - } - IntArray other = (IntArray) o; - int usedLen = getUsedLength(); - if (other.getUsedLength() != usedLen) - { - return false; - } - for (int i = 0; i < usedLen; i++) - { - if (m_ints[i] != other.m_ints[i]) - { - return false; - } - } - return true; - } - - public int hashCode() - { - int usedLen = getUsedLength(); - int hash = 1; - for (int i = 0; i < usedLen; i++) - { - hash *= 31; - hash ^= m_ints[i]; - } - return hash; - } - - public Object clone() - { - return new IntArray(Arrays.clone(m_ints)); - } - - public String toString() - { - int i = getUsedLength(); - if (i == 0) - { - return "0"; - } - - StringBuffer sb = new StringBuffer(Integer.toBinaryString(m_ints[--i])); - while (--i >= 0) - { - String s = Integer.toBinaryString(m_ints[i]); - - // Add leading zeroes, except for highest significant word - int len = s.length(); - if (len < 32) - { - sb.append(ZEROES.substring(len)); - } - - sb.append(s); - } - return sb.toString(); - } -} \ No newline at end of file diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java index 7e8b172..b963118 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/LongArray.java @@ -4,15 +4,17 @@ import org.bouncycastle.util.Arrays; import java.math.BigInteger; -class LongArray +class LongArray implements Cloneable { // private static long DEINTERLEAVE_MASK = 0x5555555555555555L; /* * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits. * In a binary field, this operation is the same as squaring an 8 bit number. + * + * NOTE: All entries are positive so sign-extension is not an issue. */ - private static final int[] INTERLEAVE2_TABLE = new int[] + private static final short[] INTERLEAVE2_TABLE = new short[] { 0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, @@ -371,6 +373,23 @@ class LongArray } } + public boolean isOne() + { + long[] a = m_ints; + if (a[0] != 1L) + { + return false; + } + for (int i = 1; i < a.length; ++i) + { + if (a[i] != 0L) + { + return false; + } + } + return true; + } + public boolean isZero() { long[] a = m_ints; @@ -822,12 +841,12 @@ class LongArray add(c, cOff, b, 0, bLen); } int k = 1; - while ((a >>>= 1) != 0) + while ((a >>>= 1) != 0L) { if ((a & 1L) != 0L) { long carry = addShiftedUp(c, cOff, b, 0, bLen, k); - if (carry != 0) + if (carry != 0L) { c[cOff + bLen] ^= carry; } @@ -871,8 +890,8 @@ class LongArray if (aLen == 1) { - long a = A.m_ints[0]; - if (a == 1L) + long a0 = A.m_ints[0]; + if (a0 == 1L) { return B; } @@ -880,13 +899,13 @@ class LongArray /* * Fast path for small A, with performance dependent only on the number of set bits */ - long[] c = new long[cLen]; - multiplyWord(a, B.m_ints, bLen, c, 0); + long[] c0 = new long[cLen]; + multiplyWord(a0, B.m_ints, bLen, c0, 0); /* * Reduce the raw answer against the reduction coefficients */ - return reduceResult(c, 0, cLen, m, ks); + return reduceResult(c0, 0, cLen, m, ks); } /* @@ -1003,8 +1022,8 @@ class LongArray if (aLen == 1) { - long a = A.m_ints[0]; - if (a == 1L) + long a0 = A.m_ints[0]; + if (a0 == 1L) { return B; } @@ -1012,13 +1031,13 @@ class LongArray /* * Fast path for small A, with performance dependent only on the number of set bits */ - long[] c = new long[cLen]; - multiplyWord(a, B.m_ints, bLen, c, 0); + long[] c0 = new long[cLen]; + multiplyWord(a0, B.m_ints, bLen, c0, 0); /* * Reduce the raw answer against the reduction coefficients */ - return reduceResult(c, 0, cLen, m, ks); + return reduceResult(c0, 0, cLen, m, ks); } /* @@ -1077,7 +1096,8 @@ class LongArray aVal >>>= 4; int v = (int)aVal & MASK; addBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); - if ((aVal >>>= 4) == 0L) + aVal >>>= 4; + if (aVal == 0L) { break; } @@ -1085,10 +1105,12 @@ class LongArray } } - int cOff = c.length; - while ((cOff -= cLen) != 0) { - addShiftedUp(c, cOff - cLen, c, cOff, cLen, 8); + int cOff = c.length; + while ((cOff -= cLen) != 0) + { + addShiftedUp(c, cOff - cLen, c, cOff, cLen, 8); + } } /* @@ -1132,8 +1154,8 @@ class LongArray if (aLen == 1) { - long a = A.m_ints[0]; - if (a == 1L) + long a0 = A.m_ints[0]; + if (a0 == 1L) { return B; } @@ -1141,13 +1163,13 @@ class LongArray /* * Fast path for small A, with performance dependent only on the number of set bits */ - long[] c = new long[cLen]; - multiplyWord(a, B.m_ints, bLen, c, 0); + long[] c0 = new long[cLen]; + multiplyWord(a0, B.m_ints, bLen, c0, 0); /* * Reduce the raw answer against the reduction coefficients */ - return reduceResult(c, 0, cLen, m, ks); + return reduceResult(c0, 0, cLen, m, ks); } // NOTE: This works, but is slower than width 4 processing @@ -1314,6 +1336,158 @@ class LongArray return reduceResult(c, ci[1], cLen, m, ks); } + public LongArray modReduce(int m, int[] ks) + { + long[] buf = Arrays.clone(m_ints); + int rLen = reduceInPlace(buf, 0, buf.length, m, ks); + return new LongArray(buf, 0, rLen); + } + + public LongArray multiply(LongArray other, int m, int[] ks) + { + /* + * Find out the degree of each argument and handle the zero cases + */ + int aDeg = degree(); + if (aDeg == 0) + { + return this; + } + int bDeg = other.degree(); + if (bDeg == 0) + { + return other; + } + + /* + * Swap if necessary so that A is the smaller argument + */ + LongArray A = this, B = other; + if (aDeg > bDeg) + { + A = other; B = this; + int tmp = aDeg; aDeg = bDeg; bDeg = tmp; + } + + /* + * Establish the word lengths of the arguments and result + */ + int aLen = (aDeg + 63) >>> 6; + int bLen = (bDeg + 63) >>> 6; + int cLen = (aDeg + bDeg + 62) >>> 6; + + if (aLen == 1) + { + long a0 = A.m_ints[0]; + if (a0 == 1L) + { + return B; + } + + /* + * Fast path for small A, with performance dependent only on the number of set bits + */ + long[] c0 = new long[cLen]; + multiplyWord(a0, B.m_ints, bLen, c0, 0); + + /* + * Reduce the raw answer against the reduction coefficients + */ +// return reduceResult(c0, 0, cLen, m, ks); + return new LongArray(c0, 0, cLen); + } + + /* + * Determine if B will get bigger during shifting + */ + int bMax = (bDeg + 7 + 63) >>> 6; + + /* + * Lookup table for the offset of each B in the tables + */ + int[] ti = new int[16]; + + /* + * Precompute table of all 4-bit products of B + */ + long[] T0 = new long[bMax << 4]; + int tOff = bMax; + ti[1] = tOff; + System.arraycopy(B.m_ints, 0, T0, tOff, bLen); + for (int i = 2; i < 16; ++i) + { + ti[i] = (tOff += bMax); + if ((i & 1) == 0) + { + shiftUp(T0, tOff >>> 1, T0, tOff, bMax, 1); + } + else + { + add(T0, bMax, T0, tOff - bMax, T0, tOff, bMax); + } + } + + /* + * Second table with all 4-bit products of B shifted 4 bits + */ + long[] T1 = new long[T0.length]; + shiftUp(T0, 0, T1, 0, T0.length, 4); +// shiftUp(T0, bMax, T1, bMax, tOff, 4); + + long[] a = A.m_ints; + long[] c = new long[cLen << 3]; + + int MASK = 0xF; + + /* + * Lopez-Dahab (Modified) algorithm + */ + + for (int aPos = 0; aPos < aLen; ++aPos) + { + long aVal = a[aPos]; + int cOff = aPos; + for (;;) + { + int u = (int)aVal & MASK; + aVal >>>= 4; + int v = (int)aVal & MASK; + addBoth(c, cOff, T0, ti[u], T1, ti[v], bMax); + aVal >>>= 4; + if (aVal == 0L) + { + break; + } + cOff += cLen; + } + } + + { + int cOff = c.length; + while ((cOff -= cLen) != 0) + { + addShiftedUp(c, cOff - cLen, c, cOff, cLen, 8); + } + } + + /* + * Finally the raw answer is collected, reduce it against the reduction coefficients + */ +// return reduceResult(c, 0, cLen, m, ks); + return new LongArray(c, 0, cLen); + } + + public void reduce(int m, int[] ks) + { + long[] buf = m_ints; + int rLen = reduceInPlace(buf, 0, buf.length, m, ks); + if (rLen < buf.length) + { + m_ints = new long[rLen]; + System.arraycopy(buf, 0, m_ints, 0, rLen); + } + } + private static LongArray reduceResult(long[] buf, int off, int len, int m, int[] ks) { int rLen = reduceInPlace(buf, off, len, m, ks); @@ -1405,13 +1579,13 @@ class LongArray private static void reduceBit(long[] buf, int off, int bit, int m, int[] ks) { flipBit(buf, off, bit); - int base = bit - m; + int n = bit - m; int j = ks.length; while (--j >= 0) { - flipBit(buf, off, ks[j] + base); + flipBit(buf, off, ks[j] + n); } - flipBit(buf, off, base); + flipBit(buf, off, n); } private static void reduceWordWise(long[] buf, int off, int len, int toBit, int m, int[] ks) @@ -1428,12 +1602,14 @@ class LongArray } } - int partial = toBit & 0x3F; - long word = buf[off + toPos] >>> partial; - if (word != 0) { - buf[off + toPos] ^= word << partial; - reduceWord(buf, off, toBit, word, m, ks); + int partial = toBit & 0x3F; + long word = buf[off + toPos] >>> partial; + if (word != 0) + { + buf[off + toPos] ^= word << partial; + reduceWord(buf, off, toBit, word, m, ks); + } } } @@ -1502,37 +1678,59 @@ class LongArray return new LongArray(r, 0, reduceInPlace(r, 0, r.length, m, ks)); } -// private LongArray modSquareN(int n, int m, int[] ks) -// { -// int len = getUsedLength(); -// if (len == 0) -// { -// return this; -// } -// -// int mLen = (m + 63) >>> 6; -// long[] r = new long[mLen << 1]; -// System.arraycopy(m_ints, 0, r, 0, len); -// -// while (--n >= 0) -// { -// squareInPlace(r, len, m, ks); -// len = reduceInPlace(r, 0, r.length, m, ks); -// } -// -// return new LongArray(r, 0, len); -// } -// -// private static void squareInPlace(long[] x, int xLen, int m, int[] ks) -// { -// int pos = xLen << 1; -// while (--xLen >= 0) -// { -// long xVal = x[xLen]; -// x[--pos] = interleave2_32to64((int)(xVal >>> 32)); -// x[--pos] = interleave2_32to64((int)xVal); -// } -// } + public LongArray modSquareN(int n, int m, int[] ks) + { + int len = getUsedLength(); + if (len == 0) + { + return this; + } + + int mLen = (m + 63) >>> 6; + long[] r = new long[mLen << 1]; + System.arraycopy(m_ints, 0, r, 0, len); + + while (--n >= 0) + { + squareInPlace(r, len, m, ks); + len = reduceInPlace(r, 0, r.length, m, ks); + } + + return new LongArray(r, 0, len); + } + + public LongArray square(int m, int[] ks) + { + int len = getUsedLength(); + if (len == 0) + { + return this; + } + + int _2len = len << 1; + long[] r = new long[_2len]; + + int pos = 0; + while (pos < _2len) + { + long mi = m_ints[pos >>> 1]; + r[pos++] = interleave2_32to64((int)mi); + r[pos++] = interleave2_32to64((int)(mi >>> 32)); + } + + return new LongArray(r, 0, r.length); + } + + private static void squareInPlace(long[] x, int xLen, int m, int[] ks) + { + int pos = xLen << 1; + while (--xLen >= 0) + { + long xVal = x[xLen]; + x[--pos] = interleave2_32to64((int)(xVal >>> 32)); + x[--pos] = interleave2_32to64((int)xVal); + } + } private static void interleave(long[] x, int xOff, long[] z, int zOff, int count, int width) { @@ -1856,6 +2054,10 @@ class LongArray * Output: a(z)^(-1) mod f(z) */ int uzDegree = degree(); + if (uzDegree == 0) + { + throw new IllegalStateException(); + } if (uzDegree == 1) { return this; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java new file mode 100644 index 0000000..099f5fb --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java @@ -0,0 +1,16 @@ +package org.bouncycastle.math.ec; + +public class ScaleXPointMap implements ECPointMap +{ + protected final ECFieldElement scale; + + public ScaleXPointMap(ECFieldElement scale) + { + this.scale = scale; + } + + public ECPoint map(ECPoint p) + { + return p.scaleX(scale); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java index 96e666d..229fae4 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java @@ -54,12 +54,6 @@ class SimpleBigDecimal this.scale = scale; } - private SimpleBigDecimal(SimpleBigDecimal limBigDec) - { - bigInt = limBigDec.bigInt; - scale = limBigDec.scale; - } - private void checkScale(SimpleBigDecimal b) { if (scale != b.scale) @@ -78,7 +72,7 @@ class SimpleBigDecimal if (newScale == scale) { - return new SimpleBigDecimal(this); + return this; } return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale), diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java index 42d6738..aef0cf7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java @@ -386,11 +386,11 @@ class Tnaf /** * Applies the operation τ() to an - * ECPoint.F2m. - * @param p The ECPoint.F2m to which τ() is applied. + * ECPoint.AbstractF2m. + * @param p The ECPoint.AbstractF2m to which τ() is applied. * @return τ(p) */ - public static ECPoint.F2m tau(ECPoint.F2m p) + public static ECPoint.AbstractF2m tau(ECPoint.AbstractF2m p) { return p.tau(); } @@ -405,7 +405,7 @@ class Tnaf * @throws IllegalArgumentException if the given ECCurve is not a Koblitz * curve. */ - public static byte getMu(ECCurve.F2m curve) + public static byte getMu(ECCurve.AbstractF2m curve) { if (!curve.isKoblitz()) { @@ -420,6 +420,16 @@ class Tnaf return 1; } + public static byte getMu(ECFieldElement curveA) + { + return (byte)(curveA.isZero() ? -1 : 1); + } + + public static byte getMu(int curveA) + { + return (byte)(curveA == 0 ? -1 : 1); + } + /** * Calculates the Lucas Sequence elements Uk-1 and * Uk or Vk-1 and @@ -525,55 +535,64 @@ class Tnaf * @throws IllegalArgumentException if curve is not a * Koblitz curve (Anomalous Binary Curve, ABC). */ - public static BigInteger[] getSi(ECCurve.F2m curve) + public static BigInteger[] getSi(ECCurve.AbstractF2m curve) { if (!curve.isKoblitz()) { throw new IllegalArgumentException("si is defined for Koblitz curves only"); } - int m = curve.getM(); + int m = curve.getFieldSize(); int a = curve.getA().toBigInteger().intValue(); - byte mu = curve.getMu(); - int h = curve.getH().intValue(); + byte mu = getMu(a); + int shifts = getShiftsForCofactor(curve.getCofactor()); int index = m + 3 - a; BigInteger[] ui = getLucas(mu, index, false); - - BigInteger dividend0; - BigInteger dividend1; if (mu == 1) { - dividend0 = ECConstants.ONE.subtract(ui[1]); - dividend1 = ECConstants.ONE.subtract(ui[0]); - } - else if (mu == -1) - { - dividend0 = ECConstants.ONE.add(ui[1]); - dividend1 = ECConstants.ONE.add(ui[0]); - } - else - { - throw new IllegalArgumentException("mu must be 1 or -1"); + ui[0] = ui[0].negate(); + ui[1] = ui[1].negate(); } - BigInteger[] si = new BigInteger[2]; + BigInteger dividend0 = ECConstants.ONE.add(ui[1]).shiftRight(shifts); + BigInteger dividend1 = ECConstants.ONE.add(ui[0]).shiftRight(shifts).negate(); - if (h == 2) - { - si[0] = dividend0.shiftRight(1); - si[1] = dividend1.shiftRight(1).negate(); - } - else if (h == 4) + return new BigInteger[] { dividend0, dividend1 }; + } + + public static BigInteger[] getSi(int fieldSize, int curveA, BigInteger cofactor) + { + byte mu = getMu(curveA); + int shifts = getShiftsForCofactor(cofactor); + int index = fieldSize + 3 - curveA; + BigInteger[] ui = getLucas(mu, index, false); + if (mu == 1) { - si[0] = dividend0.shiftRight(2); - si[1] = dividend1.shiftRight(2).negate(); + ui[0] = ui[0].negate(); + ui[1] = ui[1].negate(); } - else + + BigInteger dividend0 = ECConstants.ONE.add(ui[1]).shiftRight(shifts); + BigInteger dividend1 = ECConstants.ONE.add(ui[0]).shiftRight(shifts).negate(); + + return new BigInteger[] { dividend0, dividend1 }; + } + + protected static int getShiftsForCofactor(BigInteger h) + { + if (h != null) { - throw new IllegalArgumentException("h (Cofactor) must be 2 or 4"); + if (h.equals(ECConstants.TWO)) + { + return 1; + } + if (h.equals(ECConstants.FOUR)) + { + return 2; + } } - return si; + throw new IllegalArgumentException("h (Cofactor) must be 2 or 4"); } /** @@ -625,70 +644,77 @@ class Tnaf } /** - * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m} + * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m} * by a BigInteger using the reduced τ-adic * NAF (RTNAF) method. - * @param p The ECPoint.F2m to multiply. + * @param p The ECPoint.AbstractF2m to multiply. * @param k The BigInteger by which to multiply p. * @return k * p */ - public static ECPoint.F2m multiplyRTnaf(ECPoint.F2m p, BigInteger k) + public static ECPoint.AbstractF2m multiplyRTnaf(ECPoint.AbstractF2m p, BigInteger k) { - ECCurve.F2m curve = (ECCurve.F2m) p.getCurve(); - int m = curve.getM(); - byte a = (byte) curve.getA().toBigInteger().intValue(); - byte mu = curve.getMu(); + ECCurve.AbstractF2m curve = (ECCurve.AbstractF2m) p.getCurve(); + int m = curve.getFieldSize(); + int a = curve.getA().toBigInteger().intValue(); + byte mu = getMu(a); BigInteger[] s = curve.getSi(); - ZTauElement rho = partModReduction(k, m, a, s, mu, (byte)10); + ZTauElement rho = partModReduction(k, m, (byte)a, s, mu, (byte)10); return multiplyTnaf(p, rho); } /** - * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m} + * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m} * by an element λ of Z[τ] * using the τ-adic NAF (TNAF) method. - * @param p The ECPoint.F2m to multiply. + * @param p The ECPoint.AbstractF2m to multiply. * @param lambda The element λ of * Z[τ]. * @return λ * p */ - public static ECPoint.F2m multiplyTnaf(ECPoint.F2m p, ZTauElement lambda) + public static ECPoint.AbstractF2m multiplyTnaf(ECPoint.AbstractF2m p, ZTauElement lambda) { - ECCurve.F2m curve = (ECCurve.F2m)p.getCurve(); - byte mu = curve.getMu(); + ECCurve.AbstractF2m curve = (ECCurve.AbstractF2m)p.getCurve(); + byte mu = getMu(curve.getA()); byte[] u = tauAdicNaf(mu, lambda); - ECPoint.F2m q = multiplyFromTnaf(p, u); + ECPoint.AbstractF2m q = multiplyFromTnaf(p, u); return q; } /** - * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m} + * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m} * by an element λ of Z[τ] * using the τ-adic NAF (TNAF) method, given the TNAF * of λ. - * @param p The ECPoint.F2m to multiply. + * @param p The ECPoint.AbstractF2m to multiply. * @param u The the TNAF of λ.. * @return λ * p */ - public static ECPoint.F2m multiplyFromTnaf(ECPoint.F2m p, byte[] u) + public static ECPoint.AbstractF2m multiplyFromTnaf(ECPoint.AbstractF2m p, byte[] u) { - ECCurve.F2m curve = (ECCurve.F2m)p.getCurve(); - ECPoint.F2m q = (ECPoint.F2m) curve.getInfinity(); + ECCurve curve = p.getCurve(); + ECPoint.AbstractF2m q = (ECPoint.AbstractF2m)curve.getInfinity(); + ECPoint.AbstractF2m pNeg = (ECPoint.AbstractF2m)p.negate(); + int tauCount = 0; for (int i = u.length - 1; i >= 0; i--) { - q = tau(q); - if (u[i] == 1) + ++tauCount; + byte ui = u[i]; + if (ui != 0) { - q = (ECPoint.F2m)q.addSimple(p); - } - else if (u[i] == -1) - { - q = (ECPoint.F2m)q.subtractSimple(p); + q = q.tauPow(tauCount); + tauCount = 0; + + ECPoint x = ui > 0 ? p : pNeg; + q = (ECPoint.AbstractF2m)q.add(x); } } + if (tauCount > 0) + { + q = q.tauPow(tauCount); + } return q; } @@ -803,26 +829,17 @@ class Tnaf * @param a The parameter a of the elliptic curve. * @return The precomputation array for p. */ - public static ECPoint.F2m[] getPreComp(ECPoint.F2m p, byte a) + public static ECPoint.AbstractF2m[] getPreComp(ECPoint.AbstractF2m p, byte a) { - ECPoint.F2m[] pu; - pu = new ECPoint.F2m[16]; - pu[1] = p; - byte[][] alphaTnaf; - if (a == 0) - { - alphaTnaf = Tnaf.alpha0Tnaf; - } - else - { - // a == 1 - alphaTnaf = Tnaf.alpha1Tnaf; - } + byte[][] alphaTnaf = (a == 0) ? Tnaf.alpha0Tnaf : Tnaf.alpha1Tnaf; + + ECPoint.AbstractF2m[] pu = new ECPoint.AbstractF2m[(alphaTnaf.length + 1) >>> 1]; + pu[0] = p; int precompLen = alphaTnaf.length; - for (int i = 3; i < precompLen; i = i + 2) + for (int i = 3; i < precompLen; i += 2) { - pu[i] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]); + pu[i >>> 1] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]); } p.getCurve().normalizeAll(pu); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java index 59a9313..90b0847 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafL2RMultiplier.java @@ -31,7 +31,7 @@ public class WNafL2RMultiplier extends AbstractECMultiplier int i = wnaf.length; /* - * NOTE This code optimizes the first window using the precomputed points to substitute an + * NOTE: We try to optimize the first window using the precomputed points to substitute an * addition for 2 or more doublings. */ if (i > 1) @@ -42,19 +42,14 @@ public class WNafL2RMultiplier extends AbstractECMultiplier int n = Math.abs(digit); ECPoint[] table = digit < 0 ? preCompNeg : preComp; - /* - * NOTE: We use this optimization conservatively, since some coordinate systems have - * significantly cheaper doubling relative to addition. - * - * (n << 2) selects precomputed values in the lower half of the table - * (n << 3) selects precomputed values in the lower quarter of the table - */ - //if ((n << 2) < (1 << width)) - if ((n << 3) < (1 << width)) + // Optimization can only be used for values in the lower half of the table + if ((n << 2) < (1 << width)) { int highest = LongArray.bitLengths[n]; - int lowBits = n ^ (1 << (highest - 1)); + + // TODO Get addition/doubling cost ratio from curve and compare to 'scale' to see if worth substituting? int scale = width - highest; + int lowBits = n ^ (1 << (highest - 1)); int i1 = ((1 << (width - 1)) - 1); int i2 = (lowBits << scale) + 1; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java index d142ab7..e8f16e6 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java @@ -10,47 +10,47 @@ public class WNafPreCompInfo implements PreCompInfo * Array holding the precomputed ECPoints used for a Window * NAF multiplication. */ - private ECPoint[] preComp = null; + protected ECPoint[] preComp = null; /** * Array holding the negations of the precomputed ECPoints used * for a Window NAF multiplication. */ - private ECPoint[] preCompNeg = null; + protected ECPoint[] preCompNeg = null; /** * Holds an ECPoint representing twice(this). Used for the * Window NAF multiplication to create or extend the precomputed values. */ - private ECPoint twiceP = null; + protected ECPoint twice = null; - protected ECPoint[] getPreComp() + public ECPoint[] getPreComp() { return preComp; } - protected ECPoint[] getPreCompNeg() + public void setPreComp(ECPoint[] preComp) { - return preCompNeg; + this.preComp = preComp; } - protected void setPreComp(ECPoint[] preComp) + public ECPoint[] getPreCompNeg() { - this.preComp = preComp; + return preCompNeg; } - protected void setPreCompNeg(ECPoint[] preCompNeg) + public void setPreCompNeg(ECPoint[] preCompNeg) { this.preCompNeg = preCompNeg; } - protected ECPoint getTwiceP() + public ECPoint getTwice() { - return twiceP; + return twice; } - protected void setTwiceP(ECPoint twiceP) + public void setTwice(ECPoint twice) { - this.twiceP = twiceP; + this.twice = twice; } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java index 6465d66..339689e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WNafUtil.java @@ -4,7 +4,13 @@ import java.math.BigInteger; public abstract class WNafUtil { - private static int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 }; + public static final String PRECOMP_NAME = "bc_wnaf"; + + private static final int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 }; + + private static final byte[] EMPTY_BYTES = new byte[0]; + private static final int[] EMPTY_INTS = new int[0]; + private static final ECPoint[] EMPTY_POINTS = new ECPoint[0]; public static int[] generateCompactNaf(BigInteger k) { @@ -12,30 +18,35 @@ public abstract class WNafUtil { throw new IllegalArgumentException("'k' must have bitlength < 2^16"); } + if (k.signum() == 0) + { + return EMPTY_INTS; + } BigInteger _3k = k.shiftLeft(1).add(k); - int digits = _3k.bitLength() - 1; - int[] naf = new int[(digits + 1) >> 1]; + int bits = _3k.bitLength(); + int[] naf = new int[bits >> 1]; - int length = 0, zeroes = 0; - for (int i = 1; i <= digits; ++i) - { - boolean _3kBit = _3k.testBit(i); - boolean kBit = k.testBit(i); + BigInteger diff = _3k.xor(k); - if (_3kBit == kBit) + int highBit = bits - 1, length = 0, zeroes = 0; + for (int i = 1; i < highBit; ++i) + { + if (!diff.testBit(i)) { ++zeroes; + continue; } - else - { - int digit = kBit ? -1 : 1; - naf[length++] = (digit << 16) | zeroes; - zeroes = 0; - } + + int digit = k.testBit(i) ? -1 : 1; + naf[length++] = (digit << 16) | zeroes; + zeroes = 1; + ++i; } + naf[length++] = (1 << 16) | zeroes; + if (naf.length > length) { naf = trim(naf, length); @@ -59,6 +70,10 @@ public abstract class WNafUtil { throw new IllegalArgumentException("'k' must have bitlength < 2^16"); } + if (k.signum() == 0) + { + return EMPTY_INTS; + } int[] wnaf = new int[k.bitLength() / width + 1]; @@ -114,9 +129,10 @@ public abstract class WNafUtil BigInteger k0 = g, k1 = h; int j = 0, d0 = 0, d1 = 0; - while (k0.signum() > 0 || k1.signum() > 0 || d0 > 0 || d1 > 0) + int offset = 0; + while ((d0 | d1) != 0 || k0.bitLength() > offset || k1.bitLength() > offset) { - int n0 = (k0.intValue() + d0) & 7, n1 = (k1.intValue() + d1) & 7; + int n0 = ((k0.intValue() >>> offset) + d0) & 7, n1 = ((k1.intValue() >>> offset) + d1) & 7; int u0 = n0 & 1; if (u0 != 0) @@ -140,15 +156,19 @@ public abstract class WNafUtil if ((d0 << 1) == 1 + u0) { - d0 = 1 - d0; + d0 ^= 1; } if ((d1 << 1) == 1 + u1) { - d1 = 1 - d1; + d1 ^= 1; } - k0 = k0.shiftRight(1); - k1 = k1.shiftRight(1); + if (++offset == 30) + { + offset = 0; + k0 = k0.shiftRight(30); + k1 = k1.shiftRight(30); + } jsf[j++] = (byte)((u0 << 4) | (u1 & 0xF)); } @@ -164,19 +184,29 @@ public abstract class WNafUtil public static byte[] generateNaf(BigInteger k) { + if (k.signum() == 0) + { + return EMPTY_BYTES; + } + BigInteger _3k = k.shiftLeft(1).add(k); int digits = _3k.bitLength() - 1; byte[] naf = new byte[digits]; - for (int i = 1; i <= digits; ++i) - { - boolean _3kBit = _3k.testBit(i); - boolean kBit = k.testBit(i); + BigInteger diff = _3k.xor(k); - naf[i - 1] = (byte)(_3kBit == kBit ? 0 : kBit ? -1 : 1); + for (int i = 1; i < digits; ++i) + { + if (diff.testBit(i)) + { + naf[i - 1] = (byte)(k.testBit(i) ? -1 : 1); + ++i; + } } + naf[digits - 1] = 1; + return naf; } @@ -203,6 +233,10 @@ public abstract class WNafUtil { throw new IllegalArgumentException("'width' must be in the range [2, 8]"); } + if (k.signum() == 0) + { + return EMPTY_BYTES; + } byte[] wnaf = new byte[k.bitLength() + 1]; @@ -250,6 +284,24 @@ public abstract class WNafUtil return wnaf; } + public static int getNafWeight(BigInteger k) + { + if (k.signum() == 0) + { + return 0; + } + + BigInteger _3k = k.shiftLeft(1).add(k); + BigInteger diff = _3k.xor(k); + + return diff.bitCount(); + } + + public static WNafPreCompInfo getWNafPreCompInfo(ECPoint p) + { + return getWNafPreCompInfo(p.getCurve().getPreCompInfo(p, PRECOMP_NAME)); + } + public static WNafPreCompInfo getWNafPreCompInfo(PreCompInfo preCompInfo) { if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo)) @@ -291,48 +343,143 @@ public abstract class WNafUtil return w + 2; } - public static WNafPreCompInfo precompute(ECPoint p, int width, boolean includeNegated) + public static ECPoint mapPointWithPrecomp(ECPoint p, int width, boolean includeNegated, + ECPointMap pointMap) { ECCurve c = p.getCurve(); - WNafPreCompInfo wnafPreCompInfo = getWNafPreCompInfo(c.getPreCompInfo(p)); + WNafPreCompInfo wnafPreCompP = precompute(p, width, includeNegated); - ECPoint[] preComp = wnafPreCompInfo.getPreComp(); - if (preComp == null) + ECPoint q = pointMap.map(p); + WNafPreCompInfo wnafPreCompQ = getWNafPreCompInfo(c.getPreCompInfo(q, PRECOMP_NAME)); + + ECPoint twiceP = wnafPreCompP.getTwice(); + if (twiceP != null) { - preComp = new ECPoint[]{ p }; + ECPoint twiceQ = pointMap.map(twiceP); + wnafPreCompQ.setTwice(twiceQ); } - int preCompLen = preComp.length; - int reqPreCompLen = 1 << Math.max(0, width - 2); + ECPoint[] preCompP = wnafPreCompP.getPreComp(); + ECPoint[] preCompQ = new ECPoint[preCompP.length]; + for (int i = 0; i < preCompP.length; ++i) + { + preCompQ[i] = pointMap.map(preCompP[i]); + } + wnafPreCompQ.setPreComp(preCompQ); - if (preCompLen < reqPreCompLen) + if (includeNegated) { - ECPoint twiceP = wnafPreCompInfo.getTwiceP(); - if (twiceP == null) + ECPoint[] preCompNegQ = new ECPoint[preCompQ.length]; + for (int i = 0; i < preCompNegQ.length; ++i) { - twiceP = preComp[0].twice().normalize(); - wnafPreCompInfo.setTwiceP(twiceP); + preCompNegQ[i] = preCompQ[i].negate(); } + wnafPreCompQ.setPreCompNeg(preCompNegQ); + } + c.setPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ); + + return q; + } + + public static WNafPreCompInfo precompute(ECPoint p, int width, boolean includeNegated) + { + ECCurve c = p.getCurve(); + WNafPreCompInfo wnafPreCompInfo = getWNafPreCompInfo(c.getPreCompInfo(p, PRECOMP_NAME)); + + int iniPreCompLen = 0, reqPreCompLen = 1 << Math.max(0, width - 2); + + ECPoint[] preComp = wnafPreCompInfo.getPreComp(); + if (preComp == null) + { + preComp = EMPTY_POINTS; + } + else + { + iniPreCompLen = preComp.length; + } + + if (iniPreCompLen < reqPreCompLen) + { preComp = resizeTable(preComp, reqPreCompLen); - /* - * TODO Okeya/Sakurai paper has precomputation trick and "Montgomery's Trick" to speed this up. - * Also, co-Z arithmetic could avoid the subsequent normalization too. - */ - for (int i = preCompLen; i < reqPreCompLen; i++) + if (reqPreCompLen == 1) { + preComp[0] = p.normalize(); + } + else + { + int curPreCompLen = iniPreCompLen; + if (curPreCompLen == 0) + { + preComp[0] = p; + curPreCompLen = 1; + } + + ECFieldElement iso = null; + + if (reqPreCompLen == 2) + { + preComp[1] = p.threeTimes(); + } + else + { + ECPoint twiceP = wnafPreCompInfo.getTwice(), last = preComp[curPreCompLen - 1]; + if (twiceP == null) + { + twiceP = preComp[0].twice(); + wnafPreCompInfo.setTwice(twiceP); + + /* + * For Fp curves with Jacobian projective coordinates, use a (quasi-)isomorphism + * where 'twiceP' is "affine", so that the subsequent additions are cheaper. This + * also requires scaling the initial point's X, Y coordinates, and reversing the + * isomorphism as part of the subsequent normalization. + * + * NOTE: The correctness of this optimization depends on: + * 1) additions do not use the curve's A, B coefficients. + * 2) no special cases (i.e. Q +/- Q) when calculating 1P, 3P, 5P, ... + */ + if (ECAlgorithms.isFpCurve(c) && c.getFieldSize() >= 64) + { + switch (c.getCoordinateSystem()) + { + case ECCurve.COORD_JACOBIAN: + case ECCurve.COORD_JACOBIAN_CHUDNOVSKY: + case ECCurve.COORD_JACOBIAN_MODIFIED: + { + iso = twiceP.getZCoord(0); + twiceP = c.createPoint(twiceP.getXCoord().toBigInteger(), twiceP.getYCoord() + .toBigInteger()); + + ECFieldElement iso2 = iso.square(), iso3 = iso2.multiply(iso); + last = last.scaleX(iso2).scaleY(iso3); + + if (iniPreCompLen == 0) + { + preComp[0] = last; + } + break; + } + } + } + } + + while (curPreCompLen < reqPreCompLen) + { + /* + * Compute the new ECPoints for the precomputation array. The values 1, 3, + * 5, ..., 2^(width-1)-1 times p are computed + */ + preComp[curPreCompLen++] = last = last.add(twiceP); + } + } + /* - * Compute the new ECPoints for the precomputation array. The values 1, 3, 5, ..., - * 2^(width-1)-1 times p are computed + * Having oft-used operands in affine form makes operations faster. */ - preComp[i] = twiceP.add(preComp[i - 1]); + c.normalizeAll(preComp, iniPreCompLen, reqPreCompLen - iniPreCompLen, iso); } - - /* - * Having oft-used operands in affine form makes operations faster. - */ - c.normalizeAll(preComp); } wnafPreCompInfo.setPreComp(preComp); @@ -365,7 +512,7 @@ public abstract class WNafUtil wnafPreCompInfo.setPreCompNeg(preCompNeg); } - c.setPreCompInfo(p, wnafPreCompInfo); + c.setPreCompInfo(p, PRECOMP_NAME, wnafPreCompInfo); return wnafPreCompInfo; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java index 7bd30ec..7974e1d 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java @@ -8,111 +8,117 @@ import java.math.BigInteger; */ public class WTauNafMultiplier extends AbstractECMultiplier { + // TODO Create WTauNafUtil class and move various functionality into it + static final String PRECOMP_NAME = "bc_wtnaf"; + /** - * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m} + * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m} * by k using the reduced τ-adic NAF (RTNAF) * method. - * @param p The ECPoint.F2m to multiply. + * @param point The ECPoint.AbstractF2m to multiply. * @param k The integer by which to multiply k. * @return p multiplied by k. */ protected ECPoint multiplyPositive(ECPoint point, BigInteger k) { - if (!(point instanceof ECPoint.F2m)) + if (!(point instanceof ECPoint.AbstractF2m)) { - throw new IllegalArgumentException("Only ECPoint.F2m can be " + + throw new IllegalArgumentException("Only ECPoint.AbstractF2m can be " + "used in WTauNafMultiplier"); } - ECPoint.F2m p = (ECPoint.F2m)point; - ECCurve.F2m curve = (ECCurve.F2m)p.getCurve(); - int m = curve.getM(); + ECPoint.AbstractF2m p = (ECPoint.AbstractF2m)point; + ECCurve.AbstractF2m curve = (ECCurve.AbstractF2m)p.getCurve(); + int m = curve.getFieldSize(); byte a = curve.getA().toBigInteger().byteValue(); - byte mu = curve.getMu(); + byte mu = Tnaf.getMu(a); BigInteger[] s = curve.getSi(); ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10); - return multiplyWTnaf(p, rho, curve.getPreCompInfo(p), a, mu); + return multiplyWTnaf(p, rho, curve.getPreCompInfo(p, PRECOMP_NAME), a, mu); } /** - * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m} + * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m} * by an element λ of Z[τ] using * the τ-adic NAF (TNAF) method. - * @param p The ECPoint.F2m to multiply. + * @param p The ECPoint.AbstractF2m to multiply. * @param lambda The element λ of * Z[τ] of which to compute the * [τ]-adic NAF. * @return p multiplied by λ. */ - private ECPoint.F2m multiplyWTnaf(ECPoint.F2m p, ZTauElement lambda, + private ECPoint.AbstractF2m multiplyWTnaf(ECPoint.AbstractF2m p, ZTauElement lambda, PreCompInfo preCompInfo, byte a, byte mu) { - ZTauElement[] alpha; - if (a == 0) - { - alpha = Tnaf.alpha0; - } - else - { - // a == 1 - alpha = Tnaf.alpha1; - } + ZTauElement[] alpha = (a == 0) ? Tnaf.alpha0 : Tnaf.alpha1; BigInteger tw = Tnaf.getTw(mu, Tnaf.WIDTH); byte[]u = Tnaf.tauAdicWNaf(mu, lambda, Tnaf.WIDTH, - BigInteger.valueOf(Tnaf.POW_2_WIDTH), tw, alpha); + BigInteger.valueOf(Tnaf.POW_2_WIDTH), tw, alpha); return multiplyFromWTnaf(p, u, preCompInfo); } /** - * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m} + * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.AbstractF2m ECPoint.AbstractF2m} * by an element λ of Z[τ] * using the window τ-adic NAF (TNAF) method, given the * WTNAF of λ. - * @param p The ECPoint.F2m to multiply. + * @param p The ECPoint.AbstractF2m to multiply. * @param u The the WTNAF of λ.. * @return λ * p */ - private static ECPoint.F2m multiplyFromWTnaf(ECPoint.F2m p, byte[] u, - PreCompInfo preCompInfo) + private static ECPoint.AbstractF2m multiplyFromWTnaf(ECPoint.AbstractF2m p, byte[] u, PreCompInfo preCompInfo) { - ECCurve.F2m curve = (ECCurve.F2m)p.getCurve(); + ECCurve.AbstractF2m curve = (ECCurve.AbstractF2m)p.getCurve(); byte a = curve.getA().toBigInteger().byteValue(); - ECPoint.F2m[] pu; + ECPoint.AbstractF2m[] pu; if ((preCompInfo == null) || !(preCompInfo instanceof WTauNafPreCompInfo)) { pu = Tnaf.getPreComp(p, a); - curve.setPreCompInfo(p, new WTauNafPreCompInfo(pu)); + + WTauNafPreCompInfo pre = new WTauNafPreCompInfo(); + pre.setPreComp(pu); + curve.setPreCompInfo(p, PRECOMP_NAME, pre); } else { pu = ((WTauNafPreCompInfo)preCompInfo).getPreComp(); } + // TODO Include negations in precomp (optionally) and use from here + ECPoint.AbstractF2m[] puNeg = new ECPoint.AbstractF2m[pu.length]; + for (int i = 0; i < pu.length; ++i) + { + puNeg[i] = (ECPoint.AbstractF2m)pu[i].negate(); + } + + // q = infinity - ECPoint.F2m q = (ECPoint.F2m) p.getCurve().getInfinity(); + ECPoint.AbstractF2m q = (ECPoint.AbstractF2m) p.getCurve().getInfinity(); + + int tauCount = 0; for (int i = u.length - 1; i >= 0; i--) { - q = Tnaf.tau(q); - if (u[i] != 0) + ++tauCount; + int ui = u[i]; + if (ui != 0) { - if (u[i] > 0) - { - q = q.addSimple(pu[u[i]]); - } - else - { - // u[i] < 0 - q = q.subtractSimple(pu[-u[i]]); - } + q = q.tauPow(tauCount); + tauCount = 0; + + ECPoint x = ui > 0 ? pu[ui >>> 1] : puNeg[(-ui) >>> 1]; + q = (ECPoint.AbstractF2m)q.add(x); } } - + if (tauCount > 0) + { + q = q.tauPow(tauCount); + } return q; } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java index d7c583f..5800660 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java @@ -4,36 +4,21 @@ package org.bouncycastle.math.ec; * Class holding precomputation data for the WTNAF (Window * τ-adic Non-Adjacent Form) algorithm. */ -class WTauNafPreCompInfo implements PreCompInfo +public class WTauNafPreCompInfo implements PreCompInfo { /** - * Array holding the precomputed ECPoint.F2ms used for the - * WTNAF multiplication in - * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply() - * WTauNafMultiplier.multiply()}. + * Array holding the precomputed ECPoint.AbstractF2ms used for the + * WTNAF multiplication. */ - private ECPoint.F2m[] preComp = null; + protected ECPoint.AbstractF2m[] preComp = null; - /** - * Constructor for WTauNafPreCompInfo - * @param preComp Array holding the precomputed ECPoint.F2ms - * used for the WTNAF multiplication in - * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply() - * WTauNafMultiplier.multiply()}. - */ - WTauNafPreCompInfo(ECPoint.F2m[] preComp) + public ECPoint.AbstractF2m[] getPreComp() { - this.preComp = preComp; + return preComp; } - /** - * @return the array holding the precomputed ECPoint.F2ms - * used for the WTNAF multiplication in - * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply() - * WTauNafMultiplier.multiply()}. - */ - protected ECPoint.F2m[] getPreComp() + public void setPreComp(ECPoint.AbstractF2m[] preComp) { - return preComp; + this.preComp = preComp; } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java new file mode 100644 index 0000000..b46cba6 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java @@ -0,0 +1,79 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +public class SecP192K1Curve extends ECCurve.AbstractFp +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37")); + + private static final int SecP192K1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP192K1Point infinity; + + public SecP192K1Curve() + { + super(q); + + this.infinity = new SecP192K1Point(this, null, null); + + this.a = fromBigInteger(ECConstants.ZERO); + this.b = fromBigInteger(BigInteger.valueOf(3)); + this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D")); + this.cofactor = BigInteger.valueOf(1); + + this.coord = SecP192K1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP192K1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP192K1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP192K1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP192K1Point(this, x, y, zs, withCompression); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java new file mode 100644 index 0000000..1a0bde8 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java @@ -0,0 +1,177 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat192; + +public class SecP192K1Field +{ + // 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1 + static final int[] P = new int[]{ 0xFFFFEE37, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x013C4FD1, 0x00002392, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0xFFFFDC6E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFEC3B02F, 0xFFFFDC6D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00002391, 0x00000002 }; + private static final int P5 = 0xFFFFFFFF; + private static final int PExt11 = 0xFFFFFFFF; + private static final int PInv33 = 0x11C9; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat192.add(x, y, z); + if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) + { + Nat.add33To(6, PInv33, z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(12, xx, yy, zz); + if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(12, zz, PExtInv.length); + } + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(6, x, z); + if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) + { + Nat.add33To(6, PInv33, z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat192.fromBigInteger(x); + if (z[5] == P5 && Nat192.gte(z, P)) + { + Nat192.subFrom(P, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(6, x, 0, z); + } + else + { + int c = Nat192.add(x, P, z); + Nat.shiftDownBit(6, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat192.createExt(); + Nat192.mul(x, y, tt); + reduce(tt, z); + } + + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat192.mulAddTo(x, y, zz); + if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(12, zz, PExtInv.length); + } + } + } + + public static void negate(int[] x, int[] z) + { + if (Nat192.isZero(x)) + { + Nat192.zero(z); + } + else + { + Nat192.sub(P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long cc = Nat192.mul33Add(PInv33, xx, 6, xx, 0, z, 0); + int c = Nat192.mul33DWordAdd(PInv33, cc, z, 0); + + // assert c == 0L || c == 1L; + + if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) + { + Nat.add33To(6, PInv33, z); + } + } + + public static void reduce32(int x, int[] z) + { + if ((x != 0 && Nat192.mul33WordAdd(PInv33, x, z, 0) != 0) + || (z[5] == P5 && Nat192.gte(z, P))) + { + Nat.add33To(6, PInv33, z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat192.createExt(); + Nat192.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat192.createExt(); + Nat192.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat192.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat192.sub(x, y, z); + if (c != 0) + { + Nat.sub33From(6, PInv33, z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(12, xx, yy, zz); + if (c != 0) + { + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(12, zz, PExtInv.length); + } + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(6, x, 0, z); + if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) + { + Nat.add33To(6, PInv33, z); + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java new file mode 100644 index 0000000..642c44c --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java @@ -0,0 +1,213 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat192; +import org.bouncycastle.util.Arrays; + +public class SecP192K1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP192K1Curve.q; + + protected int[] x; + + public SecP192K1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP192K1FieldElement"); + } + + this.x = SecP192K1Field.fromBigInteger(x); + } + + public SecP192K1FieldElement() + { + this.x = Nat192.create(); + } + + protected SecP192K1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat192.isZero(x); + } + + public boolean isOne() + { + return Nat192.isOne(x); + } + + public boolean testBitZero() + { + return Nat192.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat192.toBigInteger(x); + } + + public String getFieldName() + { + return "SecP192K1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat192.create(); + SecP192K1Field.add(x, ((SecP192K1FieldElement)b).x, z); + return new SecP192K1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat192.create(); + SecP192K1Field.addOne(x, z); + return new SecP192K1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat192.create(); + SecP192K1Field.subtract(x, ((SecP192K1FieldElement)b).x, z); + return new SecP192K1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat192.create(); + SecP192K1Field.multiply(x, ((SecP192K1FieldElement)b).x, z); + return new SecP192K1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat192.create(); + Mod.invert(SecP192K1Field.P, ((SecP192K1FieldElement)b).x, z); + SecP192K1Field.multiply(z, x, z); + return new SecP192K1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat192.create(); + SecP192K1Field.negate(x, z); + return new SecP192K1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat192.create(); + SecP192K1Field.square(x, z); + return new SecP192K1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP192K1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat192.create(); + Mod.invert(SecP192K1Field.P, x, z); + return new SecP192K1FieldElement(z); + } + + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + /* + * Raise this element to the exponent 2^190 - 2^30 - 2^10 - 2^6 - 2^5 - 2^4 - 2^1 + * + * Breaking up the exponent's binary representation into "repunits", we get: + * { 159 1s } { 1 0s } { 19 1s } { 1 0s } { 3 1s } { 3 0s} { 3 1s } { 1 0s } + * + * Therefore we need an addition chain containing 3, 19, 159 (the lengths of the repunits) + * We use: 1, 2, [3], 6, 8, 16, [19], 35, 70, 140, [159] + */ + + int[] x1 = this.x; + if (Nat192.isZero(x1) || Nat192.isOne(x1)) + { + return this; + } + + int[] x2 = Nat192.create(); + SecP192K1Field.square(x1, x2); + SecP192K1Field.multiply(x2, x1, x2); + int[] x3 = Nat192.create(); + SecP192K1Field.square(x2, x3); + SecP192K1Field.multiply(x3, x1, x3); + int[] x6 = Nat192.create(); + SecP192K1Field.squareN(x3, 3, x6); + SecP192K1Field.multiply(x6, x3, x6); + int[] x8 = x6; + SecP192K1Field.squareN(x6, 2, x8); + SecP192K1Field.multiply(x8, x2, x8); + int[] x16 = x2; + SecP192K1Field.squareN(x8, 8, x16); + SecP192K1Field.multiply(x16, x8, x16); + int[] x19 = x8; + SecP192K1Field.squareN(x16, 3, x19); + SecP192K1Field.multiply(x19, x3, x19); + int[] x35 = Nat192.create(); + SecP192K1Field.squareN(x19, 16, x35); + SecP192K1Field.multiply(x35, x16, x35); + int[] x70 = x16; + SecP192K1Field.squareN(x35, 35, x70); + SecP192K1Field.multiply(x70, x35, x70); + int[] x140 = x35; + SecP192K1Field.squareN(x70, 70, x140); + SecP192K1Field.multiply(x140, x70, x140); + int[] x159 = x70; + SecP192K1Field.squareN(x140, 19, x159); + SecP192K1Field.multiply(x159, x19, x159); + + int[] t1 = x159; + SecP192K1Field.squareN(t1, 20, t1); + SecP192K1Field.multiply(t1, x19, t1); + SecP192K1Field.squareN(t1, 4, t1); + SecP192K1Field.multiply(t1, x3, t1); + SecP192K1Field.squareN(t1, 6, t1); + SecP192K1Field.multiply(t1, x3, t1); + SecP192K1Field.square(t1, t1); + + int[] t2 = x3; + SecP192K1Field.square(t1, t2); + + return Nat192.eq(x1, t2) ? new SecP192K1FieldElement(t1) : null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP192K1FieldElement)) + { + return false; + } + + SecP192K1FieldElement o = (SecP192K1FieldElement)other; + return Nat192.eq(x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 6); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java new file mode 100644 index 0000000..e4ecf01 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java @@ -0,0 +1,298 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat192; + +public class SecP192K1Point extends ECPoint.AbstractFp +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, + boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP192K1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + // B.3 pg 62 + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.x, Y1 = (SecP192K1FieldElement)this.y; + SecP192K1FieldElement X2 = (SecP192K1FieldElement)b.getXCoord(), Y2 = (SecP192K1FieldElement)b.getYCoord(); + + SecP192K1FieldElement Z1 = (SecP192K1FieldElement)this.zs[0]; + SecP192K1FieldElement Z2 = (SecP192K1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat192.createExt(); + int[] t2 = Nat192.create(); + int[] t3 = Nat192.create(); + int[] t4 = Nat192.create(); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP192K1Field.square(Z1.x, S2); + + U2 = t2; + SecP192K1Field.multiply(S2, X2.x, U2); + + SecP192K1Field.multiply(S2, Z1.x, S2); + SecP192K1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP192K1Field.square(Z2.x, S1); + + U1 = tt1; + SecP192K1Field.multiply(S1, X1.x, U1); + + SecP192K1Field.multiply(S1, Z2.x, S1); + SecP192K1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat192.create(); + SecP192K1Field.subtract(U1, U2, H); + + int[] R = t2; + SecP192K1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat192.isZero(H)) + { + if (Nat192.isZero(R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP192K1Field.square(H, HSquared); + + int[] G = Nat192.create(); + SecP192K1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP192K1Field.multiply(HSquared, U1, V); + + SecP192K1Field.negate(G, G); + Nat192.mul(S1, G, tt1); + + c = Nat192.addBothTo(V, V, G); + SecP192K1Field.reduce32(c, G); + + SecP192K1FieldElement X3 = new SecP192K1FieldElement(t4); + SecP192K1Field.square(R, X3.x); + SecP192K1Field.subtract(X3.x, G, X3.x); + + SecP192K1FieldElement Y3 = new SecP192K1FieldElement(G); + SecP192K1Field.subtract(V, X3.x, Y3.x); + SecP192K1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP192K1Field.reduce(tt1, Y3.x); + + SecP192K1FieldElement Z3 = new SecP192K1FieldElement(H); + if (!Z1IsOne) + { + SecP192K1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP192K1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[] { Z3 }; + + return new SecP192K1Point(curve, X3, Y3, zs, this.withCompression); + } + + // B.3 pg 62 + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP192K1FieldElement Y1 = (SecP192K1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.x, Z1 = (SecP192K1FieldElement)this.zs[0]; + + int c; + + int[] Y1Squared = Nat192.create(); + SecP192K1Field.square(Y1.x, Y1Squared); + + int[] T = Nat192.create(); + SecP192K1Field.square(Y1Squared, T); + + int[] M = Nat192.create(); + SecP192K1Field.square(X1.x, M); + c = Nat192.addBothTo(M, M, M); + SecP192K1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP192K1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(6, S, 2, 0); + SecP192K1Field.reduce32(c, S); + + int[] t1 = Nat192.create(); + c = Nat.shiftUpBits(6, T, 3, 0, t1); + SecP192K1Field.reduce32(c, t1); + + SecP192K1FieldElement X3 = new SecP192K1FieldElement(T); + SecP192K1Field.square(M, X3.x); + SecP192K1Field.subtract(X3.x, S, X3.x); + SecP192K1Field.subtract(X3.x, S, X3.x); + + SecP192K1FieldElement Y3 = new SecP192K1FieldElement(S); + SecP192K1Field.subtract(S, X3.x, Y3.x); + SecP192K1Field.multiply(Y3.x, M, Y3.x); + SecP192K1Field.subtract(Y3.x, t1, Y3.x); + + SecP192K1FieldElement Z3 = new SecP192K1FieldElement(M); + SecP192K1Field.twice(Y1.x, Z3.x); + if (!Z1.isOne()) + { + SecP192K1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP192K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP192K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java new file mode 100644 index 0000000..be67100 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java @@ -0,0 +1,80 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +public class SecP192R1Curve extends ECCurve.AbstractFp +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF")); + + private static final int SecP192R1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP192R1Point infinity; + + public SecP192R1Curve() + { + super(q); + + this.infinity = new SecP192R1Point(this, null, null); + + this.a = fromBigInteger(new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"))); + this.b = fromBigInteger(new BigInteger(1, + Hex.decode("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"))); + this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831")); + this.cofactor = BigInteger.valueOf(1); + + this.coord = SecP192R1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP192R1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP192R1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP192R1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP192R1Point(this, x, y, zs, withCompression); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java new file mode 100644 index 0000000..75e2f5c --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java @@ -0,0 +1,286 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat192; + +public class SecP192R1Field +{ + private static final long M = 0xFFFFFFFFL; + + // 2^192 - 2^64 - 1 + static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001, + 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFE, + 0xFFFFFFFF, 0x00000001, 0x00000000, 0x00000002 }; + private static final int P5 = 0xFFFFFFFF; + private static final int PExt11 = 0xFFFFFFFF; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat192.add(x, y, z); + if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(12, xx, yy, zz); + if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(12, zz, PExtInv.length); + } + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(6, x, z); + if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) + { + addPInvTo(z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat192.fromBigInteger(x); + if (z[5] == P5 && Nat192.gte(z, P)) + { + Nat192.subFrom(P, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(6, x, 0, z); + } + else + { + int c = Nat192.add(x, P, z); + Nat.shiftDownBit(6, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat192.createExt(); + Nat192.mul(x, y, tt); + reduce(tt, z); + } + + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat192.mulAddTo(x, y, zz); + if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(12, zz, PExtInv.length); + } + } + } + + public static void negate(int[] x, int[] z) + { + if (Nat192.isZero(x)) + { + Nat192.zero(z); + } + else + { + Nat192.sub(P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long xx06 = xx[6] & M, xx07 = xx[7] & M, xx08 = xx[8] & M; + long xx09 = xx[9] & M, xx10 = xx[10] & M, xx11 = xx[11] & M; + + long t0 = xx06 + xx10; + long t1 = xx07 + xx11; + + long cc = 0; + cc += (xx[0] & M) + t0; + int z0 = (int)cc; + cc >>= 32; + cc += (xx[1] & M) + t1; + z[1] = (int)cc; + cc >>= 32; + + t0 += xx08; + t1 += xx09; + + cc += (xx[2] & M) + t0; + long z2 = cc & M; + cc >>= 32; + cc += (xx[3] & M) + t1; + z[3] = (int)cc; + cc >>= 32; + + t0 -= xx06; + t1 -= xx07; + + cc += (xx[4] & M) + t0; + z[4] = (int)cc; + cc >>= 32; + cc += (xx[5] & M) + t1; + z[5] = (int)cc; + cc >>= 32; + + z2 += cc; + + cc += (z0 & M); + z[0] = (int)cc; + cc >>= 32; + if (cc != 0) + { + cc += (z[1] & M); + z[1] = (int)cc; + z2 += cc >> 32; + } + z[2] = (int)z2; + cc = z2 >> 32; + +// assert cc == 0 || cc == 1; + + if ((cc != 0 && Nat.incAt(6, z, 3) != 0) + || (z[5] == P5 && Nat192.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void reduce32(int x, int[] z) + { + long cc = 0; + + if (x != 0) + { + long xx06 = x & M; + + cc += (z[0] & M) + xx06; + z[0] = (int)cc; + cc >>= 32; + if (cc != 0) + { + cc += (z[1] & M); + z[1] = (int)cc; + cc >>= 32; + } + cc += (z[2] & M) + xx06; + z[2] = (int)cc; + cc >>= 32; + +// assert cc == 0 || cc == 1; + } + + if ((cc != 0 && Nat.incAt(6, z, 3) != 0) + || (z[5] == P5 && Nat192.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat192.createExt(); + Nat192.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat192.createExt(); + Nat192.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat192.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat192.sub(x, y, z); + if (c != 0) + { + subPInvFrom(z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(12, xx, yy, zz); + if (c != 0) + { + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(12, zz, PExtInv.length); + } + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(6, x, 0, z); + if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) + { + addPInvTo(z); + } + } + + private static void addPInvTo(int[] z) + { + long c = (z[0] & M) + 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + } + c += (z[2] & M) + 1; + z[2] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.incAt(6, z, 3); + } + } + + private static void subPInvFrom(int[] z) + { + long c = (z[0] & M) - 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + } + c += (z[2] & M) - 1; + z[2] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.decAt(6, z, 3); + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java new file mode 100644 index 0000000..68c8080 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java @@ -0,0 +1,190 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat192; +import org.bouncycastle.util.Arrays; + +public class SecP192R1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP192R1Curve.q; + + protected int[] x; + + public SecP192R1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP192R1FieldElement"); + } + + this.x = SecP192R1Field.fromBigInteger(x); + } + + public SecP192R1FieldElement() + { + this.x = Nat192.create(); + } + + protected SecP192R1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat192.isZero(x); + } + + public boolean isOne() + { + return Nat192.isOne(x); + } + + public boolean testBitZero() + { + return Nat192.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat192.toBigInteger(x); + } + + public String getFieldName() + { + return "SecP192R1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat192.create(); + SecP192R1Field.add(x, ((SecP192R1FieldElement)b).x, z); + return new SecP192R1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat192.create(); + SecP192R1Field.addOne(x, z); + return new SecP192R1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat192.create(); + SecP192R1Field.subtract(x, ((SecP192R1FieldElement)b).x, z); + return new SecP192R1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat192.create(); + SecP192R1Field.multiply(x, ((SecP192R1FieldElement)b).x, z); + return new SecP192R1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat192.create(); + Mod.invert(SecP192R1Field.P, ((SecP192R1FieldElement)b).x, z); + SecP192R1Field.multiply(z, x, z); + return new SecP192R1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat192.create(); + SecP192R1Field.negate(x, z); + return new SecP192R1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat192.create(); + SecP192R1Field.square(x, z); + return new SecP192R1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP192R1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat192.create(); + Mod.invert(SecP192R1Field.P, x, z); + return new SecP192R1FieldElement(z); + } + + // D.1.4 91 + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + // Raise this element to the exponent 2^190 - 2^62 + + int[] x1 = this.x; + if (Nat192.isZero(x1) || Nat192.isOne(x1)) + { + return this; + } + + int[] t1 = Nat192.create(); + int[] t2 = Nat192.create(); + + SecP192R1Field.square(x1, t1); + SecP192R1Field.multiply(t1, x1, t1); + + SecP192R1Field.squareN(t1, 2, t2); + SecP192R1Field.multiply(t2, t1, t2); + + SecP192R1Field.squareN(t2, 4, t1); + SecP192R1Field.multiply(t1, t2, t1); + + SecP192R1Field.squareN(t1, 8, t2); + SecP192R1Field.multiply(t2, t1, t2); + + SecP192R1Field.squareN(t2, 16, t1); + SecP192R1Field.multiply(t1, t2, t1); + + SecP192R1Field.squareN(t1, 32, t2); + SecP192R1Field.multiply(t2, t1, t2); + + SecP192R1Field.squareN(t2, 64, t1); + SecP192R1Field.multiply(t1, t2, t1); + + SecP192R1Field.squareN(t1, 62, t1); + SecP192R1Field.square(t1, t2); + + return Nat192.eq(x1, t2) ? new SecP192R1FieldElement(t1) : null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP192R1FieldElement)) + { + return false; + } + + SecP192R1FieldElement o = (SecP192R1FieldElement)other; + return Nat192.eq(x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 6); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java new file mode 100644 index 0000000..f60fc13 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java @@ -0,0 +1,310 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat192; + +public class SecP192R1Point extends ECPoint.AbstractFp +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP192R1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + // B.3 pg 62 + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.x, Y1 = (SecP192R1FieldElement)this.y; + SecP192R1FieldElement X2 = (SecP192R1FieldElement)b.getXCoord(), Y2 = (SecP192R1FieldElement)b.getYCoord(); + + SecP192R1FieldElement Z1 = (SecP192R1FieldElement)this.zs[0]; + SecP192R1FieldElement Z2 = (SecP192R1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat192.createExt(); + int[] t2 = Nat192.create(); + int[] t3 = Nat192.create(); + int[] t4 = Nat192.create(); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP192R1Field.square(Z1.x, S2); + + U2 = t2; + SecP192R1Field.multiply(S2, X2.x, U2); + + SecP192R1Field.multiply(S2, Z1.x, S2); + SecP192R1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP192R1Field.square(Z2.x, S1); + + U1 = tt1; + SecP192R1Field.multiply(S1, X1.x, U1); + + SecP192R1Field.multiply(S1, Z2.x, S1); + SecP192R1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat192.create(); + SecP192R1Field.subtract(U1, U2, H); + + int[] R = t2; + SecP192R1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat192.isZero(H)) + { + if (Nat192.isZero(R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP192R1Field.square(H, HSquared); + + int[] G = Nat192.create(); + SecP192R1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP192R1Field.multiply(HSquared, U1, V); + + SecP192R1Field.negate(G, G); + Nat192.mul(S1, G, tt1); + + c = Nat192.addBothTo(V, V, G); + SecP192R1Field.reduce32(c, G); + + SecP192R1FieldElement X3 = new SecP192R1FieldElement(t4); + SecP192R1Field.square(R, X3.x); + SecP192R1Field.subtract(X3.x, G, X3.x); + + SecP192R1FieldElement Y3 = new SecP192R1FieldElement(G); + SecP192R1Field.subtract(V, X3.x, Y3.x); + SecP192R1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP192R1Field.reduce(tt1, Y3.x); + + SecP192R1FieldElement Z3 = new SecP192R1FieldElement(H); + if (!Z1IsOne) + { + SecP192R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP192R1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; + + return new SecP192R1Point(curve, X3, Y3, zs, this.withCompression); + } + + // B.3 pg 62 + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP192R1FieldElement Y1 = (SecP192R1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.x, Z1 = (SecP192R1FieldElement)this.zs[0]; + + int c; + int[] t1 = Nat192.create(); + int[] t2 = Nat192.create(); + + int[] Y1Squared = Nat192.create(); + SecP192R1Field.square(Y1.x, Y1Squared); + + int[] T = Nat192.create(); + SecP192R1Field.square(Y1Squared, T); + + boolean Z1IsOne = Z1.isOne(); + + int[] Z1Squared = Z1.x; + if (!Z1IsOne) + { + Z1Squared = t2; + SecP192R1Field.square(Z1.x, Z1Squared); + } + + SecP192R1Field.subtract(X1.x, Z1Squared, t1); + + int[] M = t2; + SecP192R1Field.add(X1.x, Z1Squared, M); + SecP192R1Field.multiply(M, t1, M); + c = Nat192.addBothTo(M, M, M); + SecP192R1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP192R1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(6, S, 2, 0); + SecP192R1Field.reduce32(c, S); + + c = Nat.shiftUpBits(6, T, 3, 0, t1); + SecP192R1Field.reduce32(c, t1); + + SecP192R1FieldElement X3 = new SecP192R1FieldElement(T); + SecP192R1Field.square(M, X3.x); + SecP192R1Field.subtract(X3.x, S, X3.x); + SecP192R1Field.subtract(X3.x, S, X3.x); + + SecP192R1FieldElement Y3 = new SecP192R1FieldElement(S); + SecP192R1Field.subtract(S, X3.x, Y3.x); + SecP192R1Field.multiply(Y3.x, M, Y3.x); + SecP192R1Field.subtract(Y3.x, t1, Y3.x); + + SecP192R1FieldElement Z3 = new SecP192R1FieldElement(M); + SecP192R1Field.twice(Y1.x, Z3.x); + if (!Z1IsOne) + { + SecP192R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP192R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP192R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java new file mode 100644 index 0000000..ad733da --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java @@ -0,0 +1,78 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +public class SecP224K1Curve extends ECCurve.AbstractFp +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D")); + + private static final int SECP224K1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP224K1Point infinity; + + public SecP224K1Curve() + { + super(q); + + this.infinity = new SecP224K1Point(this, null, null); + + this.a = fromBigInteger(ECConstants.ZERO); + this.b = fromBigInteger(BigInteger.valueOf(5)); + this.order = new BigInteger(1, Hex.decode("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7")); + this.cofactor = BigInteger.valueOf(1); + this.coord = SECP224K1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP224K1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP224K1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP224K1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP224K1Point(this, x, y, zs, withCompression); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java new file mode 100644 index 0000000..0146fec --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java @@ -0,0 +1,178 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat224; + +public class SecP224K1Field +{ + // 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1 + static final int[] P = new int[]{ 0xFFFFE56D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x02C23069, 0x00003526, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFCADA, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFD3DCF97, 0xFFFFCAD9, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00003525, 0x00000002 }; + private static final int P6 = 0xFFFFFFFF; + private static final int PExt13 = 0xFFFFFFFF; + private static final int PInv33 = 0x1A93; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat224.add(x, y, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(14, xx, yy, zz); + if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(14, zz, PExtInv.length); + } + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(7, x, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat224.fromBigInteger(x); + if (z[6] == P6 && Nat224.gte(z, P)) + { + Nat.add33To(7, PInv33, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(7, x, 0, z); + } + else + { + int c = Nat224.add(x, P, z); + Nat.shiftDownBit(7, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat224.createExt(); + Nat224.mul(x, y, tt); + reduce(tt, z); + } + + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat224.mulAddTo(x, y, zz); + if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(14, zz, PExtInv.length); + } + } + } + + public static void negate(int[] x, int[] z) + { + if (Nat224.isZero(x)) + { + Nat224.zero(z); + } + else + { + Nat224.sub(P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long cc = Nat224.mul33Add(PInv33, xx, 7, xx, 0, z, 0); + int c = Nat224.mul33DWordAdd(PInv33, cc, z, 0); + + // assert c == 0L || c == 1L; + + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } + + public static void reduce32(int x, int[] z) + { + if ((x != 0 && Nat224.mul33WordAdd(PInv33, x, z, 0) != 0) + || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat224.createExt(); + Nat224.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat224.createExt(); + Nat224.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat224.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat224.sub(x, y, z); + if (c != 0) + { + Nat.sub33From(7, PInv33, z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(14, xx, yy, zz); + if (c != 0) + { + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(14, zz, PExtInv.length); + } + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(7, x, 0, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java new file mode 100644 index 0000000..8285a4e --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java @@ -0,0 +1,243 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat224; +import org.bouncycastle.util.Arrays; + +public class SecP224K1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP224K1Curve.q; + + // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q) + private static final int[] PRECOMP_POW2 = new int[]{ 0x33bfd202, 0xdcfad133, 0x2287624a, 0xc3811ba8, + 0xa85558fc, 0x1eaef5d7, 0x8edf154c }; + + protected int[] x; + + public SecP224K1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP224K1FieldElement"); + } + + this.x = SecP224K1Field.fromBigInteger(x); + } + + public SecP224K1FieldElement() + { + this.x = Nat224.create(); + } + + protected SecP224K1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat224.isZero(x); + } + + public boolean isOne() + { + return Nat224.isOne(x); + } + + public boolean testBitZero() + { + return Nat224.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat224.toBigInteger(x); + } + + public String getFieldName() + { + return "SecP224K1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224K1Field.add(x, ((SecP224K1FieldElement)b).x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat224.create(); + SecP224K1Field.addOne(x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224K1Field.subtract(x, ((SecP224K1FieldElement)b).x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224K1Field.multiply(x, ((SecP224K1FieldElement)b).x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat224.create(); + Mod.invert(SecP224K1Field.P, ((SecP224K1FieldElement)b).x, z); + SecP224K1Field.multiply(z, x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat224.create(); + SecP224K1Field.negate(x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat224.create(); + SecP224K1Field.square(x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP224K1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat224.create(); + Mod.invert(SecP224K1Field.P, x, z); + return new SecP224K1FieldElement(z); + } + + // D.1.4 91 + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + /* + * Q == 8m + 5, so we use Pocklington's method for this case. + * + * First, raise this element to the exponent 2^221 - 2^29 - 2^9 - 2^8 - 2^6 - 2^4 - 2^1 (i.e. m + 1) + * + * Breaking up the exponent's binary representation into "repunits", we get: + * { 191 1s } { 1 0s } { 19 1s } { 2 0s } { 1 1s } { 1 0s} { 1 1s } { 1 0s} { 3 1s } { 1 0s} + * + * Therefore we need an addition chain containing 1, 3, 19, 191 (the lengths of the repunits) + * We use: [1], 2, [3], 4, 8, 11, [19], 23, 42, 84, 107, [191] + */ + + int[] x1 = this.x; + if (Nat224.isZero(x1) || Nat224.isOne(x1)) + { + return this; + } + + int[] x2 = Nat224.create(); + SecP224K1Field.square(x1, x2); + SecP224K1Field.multiply(x2, x1, x2); + int[] x3 = x2; + SecP224K1Field.square(x2, x3); + SecP224K1Field.multiply(x3, x1, x3); + int[] x4 = Nat224.create(); + SecP224K1Field.square(x3, x4); + SecP224K1Field.multiply(x4, x1, x4); + int[] x8 = Nat224.create(); + SecP224K1Field.squareN(x4, 4, x8); + SecP224K1Field.multiply(x8, x4, x8); + int[] x11 = Nat224.create(); + SecP224K1Field.squareN(x8, 3, x11); + SecP224K1Field.multiply(x11, x3, x11); + int[] x19 = x11; + SecP224K1Field.squareN(x11, 8, x19); + SecP224K1Field.multiply(x19, x8, x19); + int[] x23 = x8; + SecP224K1Field.squareN(x19, 4, x23); + SecP224K1Field.multiply(x23, x4, x23); + int[] x42 = x4; + SecP224K1Field.squareN(x23, 19, x42); + SecP224K1Field.multiply(x42, x19, x42); + int[] x84 = Nat224.create(); + SecP224K1Field.squareN(x42, 42, x84); + SecP224K1Field.multiply(x84, x42, x84); + int[] x107 = x42; + SecP224K1Field.squareN(x84, 23, x107); + SecP224K1Field.multiply(x107, x23, x107); + int[] x191 = x23; + SecP224K1Field.squareN(x107, 84, x191); + SecP224K1Field.multiply(x191, x84, x191); + + int[] t1 = x191; + SecP224K1Field.squareN(t1, 20, t1); + SecP224K1Field.multiply(t1, x19, t1); + SecP224K1Field.squareN(t1, 3, t1); + SecP224K1Field.multiply(t1, x1, t1); + SecP224K1Field.squareN(t1, 2, t1); + SecP224K1Field.multiply(t1, x1, t1); + SecP224K1Field.squareN(t1, 4, t1); + SecP224K1Field.multiply(t1, x3, t1); + SecP224K1Field.square(t1, t1); + + int[] t2 = x84; + SecP224K1Field.square(t1, t2); + + if (Nat224.eq(x1, t2)) + { + return new SecP224K1FieldElement(t1); + } + + /* + * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess, + * which is ((4x)^(m + 1))/2 mod Q + */ + SecP224K1Field.multiply(t1, PRECOMP_POW2, t1); + + SecP224K1Field.square(t1, t2); + + if (Nat224.eq(x1, t2)) + { + return new SecP224K1FieldElement(t1); + } + + return null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP224K1FieldElement)) + { + return false; + } + + SecP224K1FieldElement o = (SecP224K1FieldElement)other; + return Nat224.eq(x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 7); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java new file mode 100644 index 0000000..a4d37b5 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java @@ -0,0 +1,298 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat224; + +public class SecP224K1Point extends ECPoint.AbstractFp +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, + boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP224K1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + // B.3 pg 62 + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.x, Y1 = (SecP224K1FieldElement)this.y; + SecP224K1FieldElement X2 = (SecP224K1FieldElement)b.getXCoord(), Y2 = (SecP224K1FieldElement)b.getYCoord(); + + SecP224K1FieldElement Z1 = (SecP224K1FieldElement)this.zs[0]; + SecP224K1FieldElement Z2 = (SecP224K1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat224.createExt(); + int[] t2 = Nat224.create(); + int[] t3 = Nat224.create(); + int[] t4 = Nat224.create(); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP224K1Field.square(Z1.x, S2); + + U2 = t2; + SecP224K1Field.multiply(S2, X2.x, U2); + + SecP224K1Field.multiply(S2, Z1.x, S2); + SecP224K1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP224K1Field.square(Z2.x, S1); + + U1 = tt1; + SecP224K1Field.multiply(S1, X1.x, U1); + + SecP224K1Field.multiply(S1, Z2.x, S1); + SecP224K1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat224.create(); + SecP224K1Field.subtract(U1, U2, H); + + int[] R = t2; + SecP224K1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat224.isZero(H)) + { + if (Nat224.isZero(R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP224K1Field.square(H, HSquared); + + int[] G = Nat224.create(); + SecP224K1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP224K1Field.multiply(HSquared, U1, V); + + SecP224K1Field.negate(G, G); + Nat224.mul(S1, G, tt1); + + c = Nat224.addBothTo(V, V, G); + SecP224K1Field.reduce32(c, G); + + SecP224K1FieldElement X3 = new SecP224K1FieldElement(t4); + SecP224K1Field.square(R, X3.x); + SecP224K1Field.subtract(X3.x, G, X3.x); + + SecP224K1FieldElement Y3 = new SecP224K1FieldElement(G); + SecP224K1Field.subtract(V, X3.x, Y3.x); + SecP224K1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP224K1Field.reduce(tt1, Y3.x); + + SecP224K1FieldElement Z3 = new SecP224K1FieldElement(H); + if (!Z1IsOne) + { + SecP224K1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP224K1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[] { Z3 }; + + return new SecP224K1Point(curve, X3, Y3, zs, this.withCompression); + } + + // B.3 pg 62 + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP224K1FieldElement Y1 = (SecP224K1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.x, Z1 = (SecP224K1FieldElement)this.zs[0]; + + int c; + + int[] Y1Squared = Nat224.create(); + SecP224K1Field.square(Y1.x, Y1Squared); + + int[] T = Nat224.create(); + SecP224K1Field.square(Y1Squared, T); + + int[] M = Nat224.create(); + SecP224K1Field.square(X1.x, M); + c = Nat224.addBothTo(M, M, M); + SecP224K1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP224K1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(7, S, 2, 0); + SecP224K1Field.reduce32(c, S); + + int[] t1 = Nat224.create(); + c = Nat.shiftUpBits(7, T, 3, 0, t1); + SecP224K1Field.reduce32(c, t1); + + SecP224K1FieldElement X3 = new SecP224K1FieldElement(T); + SecP224K1Field.square(M, X3.x); + SecP224K1Field.subtract(X3.x, S, X3.x); + SecP224K1Field.subtract(X3.x, S, X3.x); + + SecP224K1FieldElement Y3 = new SecP224K1FieldElement(S); + SecP224K1Field.subtract(S, X3.x, Y3.x); + SecP224K1Field.multiply(Y3.x, M, Y3.x); + SecP224K1Field.subtract(Y3.x, t1, Y3.x); + + SecP224K1FieldElement Z3 = new SecP224K1FieldElement(M); + SecP224K1Field.twice(Y1.x, Z3.x); + if (!Z1.isOne()) + { + SecP224K1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP224K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP224K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java new file mode 100644 index 0000000..c844329 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java @@ -0,0 +1,80 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +public class SecP224R1Curve extends ECCurve.AbstractFp +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001")); + + private static final int SecP224R1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP224R1Point infinity; + + public SecP224R1Curve() + { + super(q); + + this.infinity = new SecP224R1Point(this, null, null); + + this.a = fromBigInteger(new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"))); + this.b = fromBigInteger(new BigInteger(1, + Hex.decode("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"))); + this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D")); + this.cofactor = BigInteger.valueOf(1); + + this.coord = SecP224R1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP224R1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP224R1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP224R1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP224R1Point(this, x, y, zs, withCompression); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java new file mode 100644 index 0000000..e05f677 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java @@ -0,0 +1,298 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat224; + +public class SecP224R1Field +{ + private static final long M = 0xFFFFFFFFL; + + // 2^224 - 2^96 + 1 + static final int[] P = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001 }; + private static final int P6 = 0xFFFFFFFF; + private static final int PExt13 = 0xFFFFFFFF; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat224.add(x, y, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(14, xx, yy, zz); + if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(14, zz, PExtInv.length); + } + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(7, x, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat224.fromBigInteger(x); + if (z[6] == P6 && Nat224.gte(z, P)) + { + Nat224.subFrom(P, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(7, x, 0, z); + } + else + { + int c = Nat224.add(x, P, z); + Nat.shiftDownBit(7, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat224.createExt(); + Nat224.mul(x, y, tt); + reduce(tt, z); + } + + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat224.mulAddTo(x, y, zz); + if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(14, zz, PExtInv.length); + } + } + } + + public static void negate(int[] x, int[] z) + { + if (Nat224.isZero(x)) + { + Nat224.zero(z); + } + else + { + Nat224.sub(P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long xx10 = xx[10] & M, xx11 = xx[11] & M, xx12 = xx[12] & M, xx13 = xx[13] & M; + + final long n = 1; + + long t0 = (xx[7] & M) + xx11 - n; + long t1 = (xx[8] & M) + xx12; + long t2 = (xx[9] & M) + xx13; + + long cc = 0; + cc += (xx[0] & M) - t0; + long z0 = cc & M; + cc >>= 32; + cc += (xx[1] & M) - t1; + z[1] = (int)cc; + cc >>= 32; + cc += (xx[2] & M) - t2; + z[2] = (int)cc; + cc >>= 32; + cc += (xx[3] & M) + t0 - xx10; + long z3 = cc & M; + cc >>= 32; + cc += (xx[4] & M) + t1 - xx11; + z[4] = (int)cc; + cc >>= 32; + cc += (xx[5] & M) + t2 - xx12; + z[5] = (int)cc; + cc >>= 32; + cc += (xx[6] & M) + xx10 - xx13; + z[6] = (int)cc; + cc >>= 32; + cc += n; + +// assert cc >= 0; + + z3 += cc; + + z0 -= cc; + z[0] = (int)z0; + cc = z0 >> 32; + if (cc != 0) + { + cc += (z[1] & M); + z[1] = (int)cc; + cc >>= 32; + cc += (z[2] & M); + z[2] = (int)cc; + z3 += cc >> 32; + } + z[3] = (int)z3; + cc = z3 >> 32; + +// assert cc == 0 || cc == 1; + + if ((cc != 0 && Nat.incAt(7, z, 4) != 0) + || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void reduce32(int x, int[] z) + { + long cc = 0; + + if (x != 0) + { + long xx07 = x & M; + + cc += (z[0] & M) - xx07; + z[0] = (int)cc; + cc >>= 32; + if (cc != 0) + { + cc += (z[1] & M); + z[1] = (int)cc; + cc >>= 32; + cc += (z[2] & M); + z[2] = (int)cc; + cc >>= 32; + } + cc += (z[3] & M) + xx07; + z[3] = (int)cc; + cc >>= 32; + +// assert cc == 0 || cc == 1; + } + + if ((cc != 0 && Nat.incAt(7, z, 4) != 0) + || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat224.createExt(); + Nat224.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat224.createExt(); + Nat224.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat224.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat224.sub(x, y, z); + if (c != 0) + { + subPInvFrom(z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(14, xx, yy, zz); + if (c != 0) + { + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(14, zz, PExtInv.length); + } + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(7, x, 0, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + private static void addPInvTo(int[] z) + { + long c = (z[0] & M) - 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) + 1; + z[3] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.incAt(7, z, 4); + } + } + + private static void subPInvFrom(int[] z) + { + long c = (z[0] & M) + 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) - 1; + z[3] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.decAt(7, z, 4); + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java new file mode 100644 index 0000000..4a28f3d --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java @@ -0,0 +1,273 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat224; +import org.bouncycastle.util.Arrays; + +public class SecP224R1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP224R1Curve.q; + + protected int[] x; + + public SecP224R1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP224R1FieldElement"); + } + + this.x = SecP224R1Field.fromBigInteger(x); + } + + public SecP224R1FieldElement() + { + this.x = Nat224.create(); + } + + protected SecP224R1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat224.isZero(x); + } + + public boolean isOne() + { + return Nat224.isOne(x); + } + + public boolean testBitZero() + { + return Nat224.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat224.toBigInteger(x); + } + + public String getFieldName() + { + return "SecP224R1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224R1Field.add(x, ((SecP224R1FieldElement)b).x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat224.create(); + SecP224R1Field.addOne(x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224R1Field.subtract(x, ((SecP224R1FieldElement)b).x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224R1Field.multiply(x, ((SecP224R1FieldElement)b).x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat224.create(); + Mod.invert(SecP224R1Field.P, ((SecP224R1FieldElement)b).x, z); + SecP224R1Field.multiply(z, x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat224.create(); + SecP224R1Field.negate(x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat224.create(); + SecP224R1Field.square(x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP224R1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat224.create(); + Mod.invert(SecP224R1Field.P, x, z); + return new SecP224R1FieldElement(z); + } + + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + int[] c = this.x; + if (Nat224.isZero(c) || Nat224.isOne(c)) + { + return this; + } + + int[] nc = Nat224.create(); + SecP224R1Field.negate(c, nc); + + int[] r = Mod.random(SecP224R1Field.P); + int[] t = Nat224.create(); + + if (!isSquare(c)) + { + return null; + } + + while (!trySqrt(nc, r, t)) + { + SecP224R1Field.addOne(r, r); + } + + SecP224R1Field.square(t, r); + + return Nat224.eq(c, r) ? new SecP224R1FieldElement(t) : null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP224R1FieldElement)) + { + return false; + } + + SecP224R1FieldElement o = (SecP224R1FieldElement)other; + return Nat224.eq(x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 7); + } + + private static boolean isSquare(int[] x) + { + int[] t1 = Nat224.create(); + int[] t2 = Nat224.create(); + Nat224.copy(x, t1); + + for (int i = 0; i < 7; ++i) + { + Nat224.copy(t1, t2); + SecP224R1Field.squareN(t1, 1 << i, t1); + SecP224R1Field.multiply(t1, t2, t1); + } + + SecP224R1Field.squareN(t1, 95, t1); + return Nat224.isOne(t1); + } + + private static void RM(int[] nc, int[] d0, int[] e0, int[] d1, int[] e1, int[] f1, int[] t) + { + SecP224R1Field.multiply(e1, e0, t); + SecP224R1Field.multiply(t, nc, t); + SecP224R1Field.multiply(d1, d0, f1); + SecP224R1Field.add(f1, t, f1); + SecP224R1Field.multiply(d1, e0, t); + Nat224.copy(f1, d1); + SecP224R1Field.multiply(e1, d0, e1); + SecP224R1Field.add(e1, t, e1); + SecP224R1Field.square(e1, f1); + SecP224R1Field.multiply(f1, nc, f1); + } + + private static void RP(int[] nc, int[] d1, int[] e1, int[] f1, int[] t) + { + Nat224.copy(nc, f1); + + int[] d0 = Nat224.create(); + int[] e0 = Nat224.create(); + + for (int i = 0; i < 7; ++i) + { + Nat224.copy(d1, d0); + Nat224.copy(e1, e0); + + int j = 1 << i; + while (--j >= 0) + { + RS(d1, e1, f1, t); + } + + RM(nc, d0, e0, d1, e1, f1, t); + } + } + + private static void RS(int[] d, int[] e, int[] f, int[] t) + { + SecP224R1Field.multiply(e, d, e); + SecP224R1Field.twice(e, e); + SecP224R1Field.square(d, t); + SecP224R1Field.add(f, t, d); + SecP224R1Field.multiply(f, t, f); + int c = Nat.shiftUpBits(7, f, 2, 0); + SecP224R1Field.reduce32(c, f); + } + + private static boolean trySqrt(int[] nc, int[] r, int[] t) + { + int[] d1 = Nat224.create(); + Nat224.copy(r, d1); + int[] e1 = Nat224.create(); + e1[0] = 1; + int[] f1 = Nat224.create(); + RP(nc, d1, e1, f1, t); + + int[] d0 = Nat224.create(); + int[] e0 = Nat224.create(); + + for (int k = 1; k < 96; ++k) + { + Nat224.copy(d1, d0); + Nat224.copy(e1, e0); + + RS(d1, e1, f1, t); + + if (Nat224.isZero(d1)) + { + Mod.invert(SecP224R1Field.P, e0, t); + SecP224R1Field.multiply(t, d0, t); + return true; + } + } + + return false; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java new file mode 100644 index 0000000..31da6f6 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java @@ -0,0 +1,308 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat224; + +public class SecP224R1Point extends ECPoint.AbstractFp +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP224R1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Y1 = (SecP224R1FieldElement)this.y; + SecP224R1FieldElement X2 = (SecP224R1FieldElement)b.getXCoord(), Y2 = (SecP224R1FieldElement)b.getYCoord(); + + SecP224R1FieldElement Z1 = (SecP224R1FieldElement)this.zs[0]; + SecP224R1FieldElement Z2 = (SecP224R1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat224.createExt(); + int[] t2 = Nat224.create(); + int[] t3 = Nat224.create(); + int[] t4 = Nat224.create(); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP224R1Field.square(Z1.x, S2); + + U2 = t2; + SecP224R1Field.multiply(S2, X2.x, U2); + + SecP224R1Field.multiply(S2, Z1.x, S2); + SecP224R1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP224R1Field.square(Z2.x, S1); + + U1 = tt1; + SecP224R1Field.multiply(S1, X1.x, U1); + + SecP224R1Field.multiply(S1, Z2.x, S1); + SecP224R1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat224.create(); + SecP224R1Field.subtract(U1, U2, H); + + int[] R = t2; + SecP224R1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat224.isZero(H)) + { + if (Nat224.isZero(R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP224R1Field.square(H, HSquared); + + int[] G = Nat224.create(); + SecP224R1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP224R1Field.multiply(HSquared, U1, V); + + SecP224R1Field.negate(G, G); + Nat224.mul(S1, G, tt1); + + c = Nat224.addBothTo(V, V, G); + SecP224R1Field.reduce32(c, G); + + SecP224R1FieldElement X3 = new SecP224R1FieldElement(t4); + SecP224R1Field.square(R, X3.x); + SecP224R1Field.subtract(X3.x, G, X3.x); + + SecP224R1FieldElement Y3 = new SecP224R1FieldElement(G); + SecP224R1Field.subtract(V, X3.x, Y3.x); + SecP224R1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP224R1Field.reduce(tt1, Y3.x); + + SecP224R1FieldElement Z3 = new SecP224R1FieldElement(H); + if (!Z1IsOne) + { + SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP224R1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; + + return new SecP224R1Point(curve, X3, Y3, zs, this.withCompression); + } + + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP224R1FieldElement Y1 = (SecP224R1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Z1 = (SecP224R1FieldElement)this.zs[0]; + + int c; + int[] t1 = Nat224.create(); + int[] t2 = Nat224.create(); + + int[] Y1Squared = Nat224.create(); + SecP224R1Field.square(Y1.x, Y1Squared); + + int[] T = Nat224.create(); + SecP224R1Field.square(Y1Squared, T); + + boolean Z1IsOne = Z1.isOne(); + + int[] Z1Squared = Z1.x; + if (!Z1IsOne) + { + Z1Squared = t2; + SecP224R1Field.square(Z1.x, Z1Squared); + } + + SecP224R1Field.subtract(X1.x, Z1Squared, t1); + + int[] M = t2; + SecP224R1Field.add(X1.x, Z1Squared, M); + SecP224R1Field.multiply(M, t1, M); + c = Nat224.addBothTo(M, M, M); + SecP224R1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP224R1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(7, S, 2, 0); + SecP224R1Field.reduce32(c, S); + + c = Nat.shiftUpBits(7, T, 3, 0, t1); + SecP224R1Field.reduce32(c, t1); + + SecP224R1FieldElement X3 = new SecP224R1FieldElement(T); + SecP224R1Field.square(M, X3.x); + SecP224R1Field.subtract(X3.x, S, X3.x); + SecP224R1Field.subtract(X3.x, S, X3.x); + + SecP224R1FieldElement Y3 = new SecP224R1FieldElement(S); + SecP224R1Field.subtract(S, X3.x, Y3.x); + SecP224R1Field.multiply(Y3.x, M, Y3.x); + SecP224R1Field.subtract(Y3.x, t1, Y3.x); + + SecP224R1FieldElement Z3 = new SecP224R1FieldElement(M); + SecP224R1Field.twice(Y1.x, Z3.x); + if (!Z1IsOne) + { + SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP224R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP224R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java new file mode 100644 index 0000000..9b88576 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java @@ -0,0 +1,78 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +public class SecP256K1Curve extends ECCurve.AbstractFp +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")); + + private static final int SECP256K1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP256K1Point infinity; + + public SecP256K1Curve() + { + super(q); + + this.infinity = new SecP256K1Point(this, null, null); + + this.a = fromBigInteger(ECConstants.ZERO); + this.b = fromBigInteger(BigInteger.valueOf(7)); + this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")); + this.cofactor = BigInteger.valueOf(1); + this.coord = SECP256K1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP256K1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP256K1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP256K1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP256K1Point(this, x, y, zs, withCompression); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java new file mode 100644 index 0000000..c7b4def --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java @@ -0,0 +1,179 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat256; + +public class SecP256K1Field +{ + // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 + static final int[] P = new int[]{ 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x000E90A1, 0x000007A2, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0xFFFFF85E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFFF16F5F, 0xFFFFF85D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000007A1, 0x00000002 }; + private static final int P7 = 0xFFFFFFFF; + private static final int PExt15 = 0xFFFFFFFF; + private static final int PInv33 = 0x3D1; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat256.add(x, y, z); + if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) + { + Nat.add33To(8, PInv33, z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(16, xx, yy, zz); + if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(16, zz, PExtInv.length); + } + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(8, x, z); + if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) + { + Nat.add33To(8, PInv33, z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat256.fromBigInteger(x); + if (z[7] == P7 && Nat256.gte(z, P)) + { + Nat256.subFrom(P, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(8, x, 0, z); + } + else + { + int c = Nat256.add(x, P, z); + Nat.shiftDownBit(8, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat256.createExt(); + Nat256.mul(x, y, tt); + reduce(tt, z); + } + + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat256.mulAddTo(x, y, zz); + if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(16, zz, PExtInv.length); + } + } + } + + public static void negate(int[] x, int[] z) + { + if (Nat256.isZero(x)) + { + Nat256.zero(z); + } + else + { + Nat256.sub(P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long cc = Nat256.mul33Add(PInv33, xx, 8, xx, 0, z, 0); + int c = Nat256.mul33DWordAdd(PInv33, cc, z, 0); + + // assert c == 0L || c == 1L; + + if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) + { + Nat.add33To(8, PInv33, z); + } + } + + public static void reduce32(int x, int[] z) + { + if ((x != 0 && Nat256.mul33WordAdd(PInv33, x, z, 0) != 0) + || (z[7] == P7 && Nat256.gte(z, P))) + { + Nat.add33To(8, PInv33, z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat256.createExt(); + Nat256.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat256.createExt(); + Nat256.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat256.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat256.sub(x, y, z); + if (c != 0) + { + Nat.sub33From(8, PInv33, z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(16, xx, yy, zz); + if (c != 0) + { + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(16, zz, PExtInv.length); + } + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(8, x, 0, z); + if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) + { + Nat.add33To(8, PInv33, z); + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java new file mode 100644 index 0000000..467b17f --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java @@ -0,0 +1,215 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat256; +import org.bouncycastle.util.Arrays; + +public class SecP256K1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP256K1Curve.q; + + protected int[] x; + + public SecP256K1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP256K1FieldElement"); + } + + this.x = SecP256K1Field.fromBigInteger(x); + } + + public SecP256K1FieldElement() + { + this.x = Nat256.create(); + } + + protected SecP256K1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat256.isZero(x); + } + + public boolean isOne() + { + return Nat256.isOne(x); + } + + public boolean testBitZero() + { + return Nat256.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat256.toBigInteger(x); + } + + public String getFieldName() + { + return "SecP256K1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat256.create(); + SecP256K1Field.add(x, ((SecP256K1FieldElement)b).x, z); + return new SecP256K1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat256.create(); + SecP256K1Field.addOne(x, z); + return new SecP256K1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat256.create(); + SecP256K1Field.subtract(x, ((SecP256K1FieldElement)b).x, z); + return new SecP256K1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat256.create(); + SecP256K1Field.multiply(x, ((SecP256K1FieldElement)b).x, z); + return new SecP256K1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat256.create(); + Mod.invert(SecP256K1Field.P, ((SecP256K1FieldElement)b).x, z); + SecP256K1Field.multiply(z, x, z); + return new SecP256K1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat256.create(); + SecP256K1Field.negate(x, z); + return new SecP256K1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat256.create(); + SecP256K1Field.square(x, z); + return new SecP256K1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP256K1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat256.create(); + Mod.invert(SecP256K1Field.P, x, z); + return new SecP256K1FieldElement(z); + } + + // D.1.4 91 + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + /* + * Raise this element to the exponent 2^254 - 2^30 - 2^7 - 2^6 - 2^5 - 2^4 - 2^2 + * + * Breaking up the exponent's binary representation into "repunits", we get: + * { 223 1s } { 1 0s } { 22 1s } { 4 0s } { 2 1s } { 2 0s} + * + * Therefore we need an addition chain containing 2, 22, 223 (the lengths of the repunits) + * We use: 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + */ + + int[] x1 = this.x; + if (Nat256.isZero(x1) || Nat256.isOne(x1)) + { + return this; + } + + int[] x2 = Nat256.create(); + SecP256K1Field.square(x1, x2); + SecP256K1Field.multiply(x2, x1, x2); + int[] x3 = Nat256.create(); + SecP256K1Field.square(x2, x3); + SecP256K1Field.multiply(x3, x1, x3); + int[] x6 = Nat256.create(); + SecP256K1Field.squareN(x3, 3, x6); + SecP256K1Field.multiply(x6, x3, x6); + int[] x9 = x6; + SecP256K1Field.squareN(x6, 3, x9); + SecP256K1Field.multiply(x9, x3, x9); + int[] x11 = x9; + SecP256K1Field.squareN(x9, 2, x11); + SecP256K1Field.multiply(x11, x2, x11); + int[] x22 = Nat256.create(); + SecP256K1Field.squareN(x11, 11, x22); + SecP256K1Field.multiply(x22, x11, x22); + int[] x44 = x11; + SecP256K1Field.squareN(x22, 22, x44); + SecP256K1Field.multiply(x44, x22, x44); + int[] x88 = Nat256.create(); + SecP256K1Field.squareN(x44, 44, x88); + SecP256K1Field.multiply(x88, x44, x88); + int[] x176 = Nat256.create(); + SecP256K1Field.squareN(x88, 88, x176); + SecP256K1Field.multiply(x176, x88, x176); + int[] x220 = x88; + SecP256K1Field.squareN(x176, 44, x220); + SecP256K1Field.multiply(x220, x44, x220); + int[] x223 = x44; + SecP256K1Field.squareN(x220, 3, x223); + SecP256K1Field.multiply(x223, x3, x223); + + int[] t1 = x223; + SecP256K1Field.squareN(t1, 23, t1); + SecP256K1Field.multiply(t1, x22, t1); + SecP256K1Field.squareN(t1, 6, t1); + SecP256K1Field.multiply(t1, x2, t1); + SecP256K1Field.squareN(t1, 2, t1); + + int[] t2 = x2; + SecP256K1Field.square(t1, t2); + + return Nat256.eq(x1, t2) ? new SecP256K1FieldElement(t1) : null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP256K1FieldElement)) + { + return false; + } + + SecP256K1FieldElement o = (SecP256K1FieldElement)other; + return Nat256.eq(x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 8); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java new file mode 100644 index 0000000..43c9c55 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java @@ -0,0 +1,298 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat256; + +public class SecP256K1Point extends ECPoint.AbstractFp +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, + boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP256K1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + // B.3 pg 62 + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.x, Y1 = (SecP256K1FieldElement)this.y; + SecP256K1FieldElement X2 = (SecP256K1FieldElement)b.getXCoord(), Y2 = (SecP256K1FieldElement)b.getYCoord(); + + SecP256K1FieldElement Z1 = (SecP256K1FieldElement)this.zs[0]; + SecP256K1FieldElement Z2 = (SecP256K1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat256.createExt(); + int[] t2 = Nat256.create(); + int[] t3 = Nat256.create(); + int[] t4 = Nat256.create(); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP256K1Field.square(Z1.x, S2); + + U2 = t2; + SecP256K1Field.multiply(S2, X2.x, U2); + + SecP256K1Field.multiply(S2, Z1.x, S2); + SecP256K1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP256K1Field.square(Z2.x, S1); + + U1 = tt1; + SecP256K1Field.multiply(S1, X1.x, U1); + + SecP256K1Field.multiply(S1, Z2.x, S1); + SecP256K1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat256.create(); + SecP256K1Field.subtract(U1, U2, H); + + int[] R = t2; + SecP256K1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat256.isZero(H)) + { + if (Nat256.isZero(R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP256K1Field.square(H, HSquared); + + int[] G = Nat256.create(); + SecP256K1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP256K1Field.multiply(HSquared, U1, V); + + SecP256K1Field.negate(G, G); + Nat256.mul(S1, G, tt1); + + c = Nat256.addBothTo(V, V, G); + SecP256K1Field.reduce32(c, G); + + SecP256K1FieldElement X3 = new SecP256K1FieldElement(t4); + SecP256K1Field.square(R, X3.x); + SecP256K1Field.subtract(X3.x, G, X3.x); + + SecP256K1FieldElement Y3 = new SecP256K1FieldElement(G); + SecP256K1Field.subtract(V, X3.x, Y3.x); + SecP256K1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP256K1Field.reduce(tt1, Y3.x); + + SecP256K1FieldElement Z3 = new SecP256K1FieldElement(H); + if (!Z1IsOne) + { + SecP256K1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP256K1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[] { Z3 }; + + return new SecP256K1Point(curve, X3, Y3, zs, this.withCompression); + } + + // B.3 pg 62 + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP256K1FieldElement Y1 = (SecP256K1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.x, Z1 = (SecP256K1FieldElement)this.zs[0]; + + int c; + + int[] Y1Squared = Nat256.create(); + SecP256K1Field.square(Y1.x, Y1Squared); + + int[] T = Nat256.create(); + SecP256K1Field.square(Y1Squared, T); + + int[] M = Nat256.create(); + SecP256K1Field.square(X1.x, M); + c = Nat256.addBothTo(M, M, M); + SecP256K1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP256K1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(8, S, 2, 0); + SecP256K1Field.reduce32(c, S); + + int[] t1 = Nat256.create(); + c = Nat.shiftUpBits(8, T, 3, 0, t1); + SecP256K1Field.reduce32(c, t1); + + SecP256K1FieldElement X3 = new SecP256K1FieldElement(T); + SecP256K1Field.square(M, X3.x); + SecP256K1Field.subtract(X3.x, S, X3.x); + SecP256K1Field.subtract(X3.x, S, X3.x); + + SecP256K1FieldElement Y3 = new SecP256K1FieldElement(S); + SecP256K1Field.subtract(S, X3.x, Y3.x); + SecP256K1Field.multiply(Y3.x, M, Y3.x); + SecP256K1Field.subtract(Y3.x, t1, Y3.x); + + SecP256K1FieldElement Z3 = new SecP256K1FieldElement(M); + SecP256K1Field.twice(Y1.x, Z3.x); + if (!Z1.isOne()) + { + SecP256K1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP256K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP256K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java new file mode 100644 index 0000000..5ff6a38 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java @@ -0,0 +1,80 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +public class SecP256R1Curve extends ECCurve.AbstractFp +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")); + + private static final int SecP256R1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP256R1Point infinity; + + public SecP256R1Curve() + { + super(q); + + this.infinity = new SecP256R1Point(this, null, null); + + this.a = fromBigInteger(new BigInteger(1, + Hex.decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"))); + this.b = fromBigInteger(new BigInteger(1, + Hex.decode("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"))); + this.order = new BigInteger(1, Hex.decode("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")); + this.cofactor = BigInteger.valueOf(1); + + this.coord = SecP256R1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP256R1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP256R1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP256R1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP256R1Point(this, x, y, zs, withCompression); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java new file mode 100644 index 0000000..5a066d8 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java @@ -0,0 +1,312 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat256; + +public class SecP256R1Field +{ + private static final long M = 0xFFFFFFFFL; + + // 2^256 - 2^224 + 2^192 + 2^96 - 1 + static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0x00000001, 0xFFFFFFFE, + 0x00000002, 0xFFFFFFFE }; + private static final int P7 = 0xFFFFFFFF; + private static final int PExt15 = 0xFFFFFFFF; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat256.add(x, y, z); + if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(16, xx, yy, zz); + if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt))) + { + Nat.subFrom(16, PExt, zz); + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(8, x, z); + if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) + { + addPInvTo(z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat256.fromBigInteger(x); + if (z[7] == P7 && Nat256.gte(z, P)) + { + Nat256.subFrom(P, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(8, x, 0, z); + } + else + { + int c = Nat256.add(x, P, z); + Nat.shiftDownBit(8, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat256.createExt(); + Nat256.mul(x, y, tt); + reduce(tt, z); + } + + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat256.mulAddTo(x, y, zz); + if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt))) + { + Nat.subFrom(16, PExt, zz); + } + } + + public static void negate(int[] x, int[] z) + { + if (Nat256.isZero(x)) + { + Nat256.zero(z); + } + else + { + Nat256.sub(P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long xx08 = xx[8] & M, xx09 = xx[9] & M, xx10 = xx[10] & M, xx11 = xx[11] & M; + long xx12 = xx[12] & M, xx13 = xx[13] & M, xx14 = xx[14] & M, xx15 = xx[15] & M; + + final long n = 6; + + xx08 -= n; + + long t0 = xx08 + xx09; + long t1 = xx09 + xx10; + long t2 = xx10 + xx11 - xx15; + long t3 = xx11 + xx12; + long t4 = xx12 + xx13; + long t5 = xx13 + xx14; + long t6 = xx14 + xx15; + + long cc = 0; + cc += (xx[0] & M) + t0 - t3 - t5; + z[0] = (int)cc; + cc >>= 32; + cc += (xx[1] & M) + t1 - t4 - t6; + z[1] = (int)cc; + cc >>= 32; + cc += (xx[2] & M) + t2 - t5; + z[2] = (int)cc; + cc >>= 32; + cc += (xx[3] & M) + (t3 << 1) + xx13 - xx15 - t0; + z[3] = (int)cc; + cc >>= 32; + cc += (xx[4] & M) + (t4 << 1) + xx14 - t1; + z[4] = (int)cc; + cc >>= 32; + cc += (xx[5] & M) + (t5 << 1) - t2; + z[5] = (int)cc; + cc >>= 32; + cc += (xx[6] & M) + (t6 << 1) + t5 - t0; + z[6] = (int)cc; + cc >>= 32; + cc += (xx[7] & M) + (xx15 << 1) + xx08 - t2 - t4; + z[7] = (int)cc; + cc >>= 32; + cc += n; + +// assert cc >= 0; + + reduce32((int)cc, z); + } + + public static void reduce32(int x, int[] z) + { + long cc = 0; + + if (x != 0) + { + long xx08 = x & M; + + cc += (z[0] & M) + xx08; + z[0] = (int)cc; + cc >>= 32; + if (cc != 0) + { + cc += (z[1] & M); + z[1] = (int)cc; + cc >>= 32; + cc += (z[2] & M); + z[2] = (int)cc; + cc >>= 32; + } + cc += (z[3] & M) - xx08; + z[3] = (int)cc; + cc >>= 32; + if (cc != 0) + { + cc += (z[4] & M); + z[4] = (int)cc; + cc >>= 32; + cc += (z[5] & M); + z[5] = (int)cc; + cc >>= 32; + } + cc += (z[6] & M) - xx08; + z[6] = (int)cc; + cc >>= 32; + cc += (z[7] & M) + xx08; + z[7] = (int)cc; + cc >>= 32; + +// assert cc == 0 || cc == 1; + } + + if (cc != 0 || (z[7] == P7 && Nat256.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat256.createExt(); + Nat256.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat256.createExt(); + Nat256.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat256.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat256.sub(x, y, z); + if (c != 0) + { + subPInvFrom(z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(16, xx, yy, zz); + if (c != 0) + { + Nat.addTo(16, PExt, zz); + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(8, x, 0, z); + if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) + { + addPInvTo(z); + } + } + + private static void addPInvTo(int[] z) + { + long c = (z[0] & M) + 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) - 1; + z[3] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M); + z[5] = (int)c; + c >>= 32; + } + c += (z[6] & M) - 1; + z[6] = (int)c; + c >>= 32; + c += (z[7] & M) + 1; + z[7] = (int)c; +// c >>= 32; + } + + private static void subPInvFrom(int[] z) + { + long c = (z[0] & M) - 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) + 1; + z[3] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M); + z[5] = (int)c; + c >>= 32; + } + c += (z[6] & M) + 1; + z[6] = (int)c; + c >>= 32; + c += (z[7] & M) - 1; + z[7] = (int)c; +// c >>= 32; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java new file mode 100644 index 0000000..be250d1 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java @@ -0,0 +1,189 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat256; +import org.bouncycastle.util.Arrays; + +public class SecP256R1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP256R1Curve.q; + + protected int[] x; + + public SecP256R1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP256R1FieldElement"); + } + + this.x = SecP256R1Field.fromBigInteger(x); + } + + public SecP256R1FieldElement() + { + this.x = Nat256.create(); + } + + protected SecP256R1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat256.isZero(x); + } + + public boolean isOne() + { + return Nat256.isOne(x); + } + + public boolean testBitZero() + { + return Nat256.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat256.toBigInteger(x); + } + + public String getFieldName() + { + return "SecP256R1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat256.create(); + SecP256R1Field.add(x, ((SecP256R1FieldElement)b).x, z); + return new SecP256R1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat256.create(); + SecP256R1Field.addOne(x, z); + return new SecP256R1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat256.create(); + SecP256R1Field.subtract(x, ((SecP256R1FieldElement)b).x, z); + return new SecP256R1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat256.create(); + SecP256R1Field.multiply(x, ((SecP256R1FieldElement)b).x, z); + return new SecP256R1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat256.create(); + Mod.invert(SecP256R1Field.P, ((SecP256R1FieldElement)b).x, z); + SecP256R1Field.multiply(z, x, z); + return new SecP256R1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat256.create(); + SecP256R1Field.negate(x, z); + return new SecP256R1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat256.create(); + SecP256R1Field.square(x, z); + return new SecP256R1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP256R1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat256.create(); + Mod.invert(SecP256R1Field.P, x, z); + return new SecP256R1FieldElement(z); + } + + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + // Raise this element to the exponent 2^254 - 2^222 + 2^190 + 2^94 + + int[] x1 = this.x; + if (Nat256.isZero(x1) || Nat256.isOne(x1)) + { + return this; + } + + int[] t1 = Nat256.create(); + int[] t2 = Nat256.create(); + + SecP256R1Field.square(x1, t1); + SecP256R1Field.multiply(t1, x1, t1); + + SecP256R1Field.squareN(t1, 2, t2); + SecP256R1Field.multiply(t2, t1, t2); + + SecP256R1Field.squareN(t2, 4, t1); + SecP256R1Field.multiply(t1, t2, t1); + + SecP256R1Field.squareN(t1, 8, t2); + SecP256R1Field.multiply(t2, t1, t2); + + SecP256R1Field.squareN(t2, 16, t1); + SecP256R1Field.multiply(t1, t2, t1); + + SecP256R1Field.squareN(t1, 32, t1); + SecP256R1Field.multiply(t1, x1, t1); + + SecP256R1Field.squareN(t1, 96, t1); + SecP256R1Field.multiply(t1, x1, t1); + + SecP256R1Field.squareN(t1, 94, t1); + SecP256R1Field.square(t1, t2); + + return Nat256.eq(x1, t2) ? new SecP256R1FieldElement(t1) : null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP256R1FieldElement)) + { + return false; + } + + SecP256R1FieldElement o = (SecP256R1FieldElement)other; + return Nat256.eq(x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 8); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java new file mode 100644 index 0000000..78b5ff8 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java @@ -0,0 +1,308 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat256; + +public class SecP256R1Point extends ECPoint.AbstractFp +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP256R1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.x, Y1 = (SecP256R1FieldElement)this.y; + SecP256R1FieldElement X2 = (SecP256R1FieldElement)b.getXCoord(), Y2 = (SecP256R1FieldElement)b.getYCoord(); + + SecP256R1FieldElement Z1 = (SecP256R1FieldElement)this.zs[0]; + SecP256R1FieldElement Z2 = (SecP256R1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat256.createExt(); + int[] t2 = Nat256.create(); + int[] t3 = Nat256.create(); + int[] t4 = Nat256.create(); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP256R1Field.square(Z1.x, S2); + + U2 = t2; + SecP256R1Field.multiply(S2, X2.x, U2); + + SecP256R1Field.multiply(S2, Z1.x, S2); + SecP256R1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP256R1Field.square(Z2.x, S1); + + U1 = tt1; + SecP256R1Field.multiply(S1, X1.x, U1); + + SecP256R1Field.multiply(S1, Z2.x, S1); + SecP256R1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat256.create(); + SecP256R1Field.subtract(U1, U2, H); + + int[] R = t2; + SecP256R1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat256.isZero(H)) + { + if (Nat256.isZero(R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP256R1Field.square(H, HSquared); + + int[] G = Nat256.create(); + SecP256R1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP256R1Field.multiply(HSquared, U1, V); + + SecP256R1Field.negate(G, G); + Nat256.mul(S1, G, tt1); + + c = Nat256.addBothTo(V, V, G); + SecP256R1Field.reduce32(c, G); + + SecP256R1FieldElement X3 = new SecP256R1FieldElement(t4); + SecP256R1Field.square(R, X3.x); + SecP256R1Field.subtract(X3.x, G, X3.x); + + SecP256R1FieldElement Y3 = new SecP256R1FieldElement(G); + SecP256R1Field.subtract(V, X3.x, Y3.x); + SecP256R1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP256R1Field.reduce(tt1, Y3.x); + + SecP256R1FieldElement Z3 = new SecP256R1FieldElement(H); + if (!Z1IsOne) + { + SecP256R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP256R1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; + + return new SecP256R1Point(curve, X3, Y3, zs, this.withCompression); + } + + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP256R1FieldElement Y1 = (SecP256R1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.x, Z1 = (SecP256R1FieldElement)this.zs[0]; + + int c; + int[] t1 = Nat256.create(); + int[] t2 = Nat256.create(); + + int[] Y1Squared = Nat256.create(); + SecP256R1Field.square(Y1.x, Y1Squared); + + int[] T = Nat256.create(); + SecP256R1Field.square(Y1Squared, T); + + boolean Z1IsOne = Z1.isOne(); + + int[] Z1Squared = Z1.x; + if (!Z1IsOne) + { + Z1Squared = t2; + SecP256R1Field.square(Z1.x, Z1Squared); + } + + SecP256R1Field.subtract(X1.x, Z1Squared, t1); + + int[] M = t2; + SecP256R1Field.add(X1.x, Z1Squared, M); + SecP256R1Field.multiply(M, t1, M); + c = Nat256.addBothTo(M, M, M); + SecP256R1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP256R1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(8, S, 2, 0); + SecP256R1Field.reduce32(c, S); + + c = Nat.shiftUpBits(8, T, 3, 0, t1); + SecP256R1Field.reduce32(c, t1); + + SecP256R1FieldElement X3 = new SecP256R1FieldElement(T); + SecP256R1Field.square(M, X3.x); + SecP256R1Field.subtract(X3.x, S, X3.x); + SecP256R1Field.subtract(X3.x, S, X3.x); + + SecP256R1FieldElement Y3 = new SecP256R1FieldElement(S); + SecP256R1Field.subtract(S, X3.x, Y3.x); + SecP256R1Field.multiply(Y3.x, M, Y3.x); + SecP256R1Field.subtract(Y3.x, t1, Y3.x); + + SecP256R1FieldElement Z3 = new SecP256R1FieldElement(M); + SecP256R1Field.twice(Y1.x, Z3.x); + if (!Z1IsOne) + { + SecP256R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP256R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP256R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java new file mode 100644 index 0000000..27cbcdb --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java @@ -0,0 +1,80 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +public class SecP384R1Curve extends ECCurve.AbstractFp +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF")); + + private static final int SecP384R1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP384R1Point infinity; + + public SecP384R1Curve() + { + super(q); + + this.infinity = new SecP384R1Point(this, null, null); + + this.a = fromBigInteger(new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"))); + this.b = fromBigInteger(new BigInteger(1, + Hex.decode("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"))); + this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973")); + this.cofactor = BigInteger.valueOf(1); + + this.coord = SecP384R1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP384R1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP384R1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP384R1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP384R1Point(this, x, y, zs, withCompression); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java new file mode 100644 index 0000000..fcbb872 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java @@ -0,0 +1,295 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat384; + +public class SecP384R1Field +{ + private static final long M = 0xFFFFFFFFL; + + // 2^384 - 2^128 - 2^96 + 2^32 - 1 + static final int[] P = new int[]{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x00000001, 0xFFFFFFFE, 0x00000000, 0x00000002, 0x00000000, 0xFFFFFFFE, + 0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000000, + 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0x00000001, + 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFE, 0xFFFFFFFF, + 0x00000001, 0x00000002 }; + private static final int P11 = 0xFFFFFFFF; + private static final int PExt23 = 0xFFFFFFFF; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat.add(12, x, y, z); + if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P))) + { + addPInvTo(z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(24, xx, yy, zz); + if (c != 0 || (zz[23] == PExt23 && Nat.gte(24, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(24, zz, PExtInv.length); + } + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(12, x, z); + if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P))) + { + addPInvTo(z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat.fromBigInteger(384, x); + if (z[11] == P11 && Nat.gte(12, z, P)) + { + Nat.subFrom(12, P, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(12, x, 0, z); + } + else + { + int c = Nat.add(12, x, P, z); + Nat.shiftDownBit(12, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat.create(24); + Nat384.mul(x, y, tt); + reduce(tt, z); + } + + public static void negate(int[] x, int[] z) + { + if (Nat.isZero(12, x)) + { + Nat.zero(12, z); + } + else + { + Nat.sub(12, P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long xx16 = xx[16] & M, xx17 = xx[17] & M, xx18 = xx[18] & M, xx19 = xx[19] & M; + long xx20 = xx[20] & M, xx21 = xx[21] & M, xx22 = xx[22] & M, xx23 = xx[23] & M; + + final long n = 1; + + long t0 = (xx[12] & M) + xx20 - n; + long t1 = (xx[13] & M) + xx22; + long t2 = (xx[14] & M) + xx22 + xx23; + long t3 = (xx[15] & M) + xx23; + long t4 = xx17 + xx21; + long t5 = xx21 - xx23; + long t6 = xx22 - xx23; + + long cc = 0; + cc += (xx[0] & M) + t0 + t5; + z[0] = (int)cc; + cc >>= 32; + cc += (xx[1] & M) + xx23 - t0 + t1; + z[1] = (int)cc; + cc >>= 32; + cc += (xx[2] & M) - xx21 - t1 + t2; + z[2] = (int)cc; + cc >>= 32; + cc += (xx[3] & M) + t0 - t2 + t3 + t5; + z[3] = (int)cc; + cc >>= 32; + cc += (xx[4] & M) + xx16 + xx21 + t0 + t1 - t3 + t5; + z[4] = (int)cc; + cc >>= 32; + cc += (xx[5] & M) - xx16 + t1 + t2 + t4; + z[5] = (int)cc; + cc >>= 32; + cc += (xx[6] & M) + xx18 - xx17 + t2 + t3; + z[6] = (int)cc; + cc >>= 32; + cc += (xx[7] & M) + xx16 + xx19 - xx18 + t3; + z[7] = (int)cc; + cc >>= 32; + cc += (xx[8] & M) + xx16 + xx17 + xx20 - xx19; + z[8] = (int)cc; + cc >>= 32; + cc += (xx[9] & M) + xx18 - xx20 + t4; + z[9] = (int)cc; + cc >>= 32; + cc += (xx[10] & M) + xx18 + xx19 - t5 + t6; + z[10] = (int)cc; + cc >>= 32; + cc += (xx[11] & M) + xx19 + xx20 - t6; + z[11] = (int)cc; + cc >>= 32; + cc += n; + +// assert cc >= 0; + + reduce32((int)cc, z); + } + + public static void reduce32(int x, int[] z) + { + long cc = 0; + + if (x != 0) + { + long xx12 = x & M; + + cc += (z[0] & M) + xx12; + z[0] = (int)cc; + cc >>= 32; + cc += (z[1] & M) - xx12; + z[1] = (int)cc; + cc >>= 32; + if (cc != 0) + { + cc += (z[2] & M); + z[2] = (int)cc; + cc >>= 32; + } + cc += (z[3] & M) + xx12; + z[3] = (int)cc; + cc >>= 32; + cc += (z[4] & M) + xx12; + z[4] = (int)cc; + cc >>= 32; + +// assert cc == 0 || cc == 1; + } + + if ((cc != 0 && Nat.incAt(12, z, 5) != 0) + || (z[11] == P11 && Nat.gte(12, z, P))) + { + addPInvTo(z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat.create(24); + Nat384.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat.create(24); + Nat384.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat384.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat.sub(12, x, y, z); + if (c != 0) + { + subPInvFrom(z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(24, xx, yy, zz); + if (c != 0) + { + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(24, zz, PExtInv.length); + } + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(12, x, 0, z); + if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P))) + { + addPInvTo(z); + } + } + + private static void addPInvTo(int[] z) + { + long c = (z[0] & M) + 1; + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - 1; + z[1] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) + 1; + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) + 1; + z[4] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.incAt(12, z, 5); + } + } + + private static void subPInvFrom(int[] z) + { + long c = (z[0] & M) - 1; + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) + 1; + z[1] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) - 1; + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - 1; + z[4] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.decAt(12, z, 5); + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java new file mode 100644 index 0000000..24e585d --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java @@ -0,0 +1,211 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.util.Arrays; + +public class SecP384R1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP384R1Curve.q; + + protected int[] x; + + public SecP384R1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP384R1FieldElement"); + } + + this.x = SecP384R1Field.fromBigInteger(x); + } + + public SecP384R1FieldElement() + { + this.x = Nat.create(12); + } + + protected SecP384R1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat.isZero(12, x); + } + + public boolean isOne() + { + return Nat.isOne(12, x); + } + + public boolean testBitZero() + { + return Nat.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat.toBigInteger(12, x); + } + + public String getFieldName() + { + return "SecP384R1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat.create(12); + SecP384R1Field.add(x, ((SecP384R1FieldElement)b).x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat.create(12); + SecP384R1Field.addOne(x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat.create(12); + SecP384R1Field.subtract(x, ((SecP384R1FieldElement)b).x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat.create(12); + SecP384R1Field.multiply(x, ((SecP384R1FieldElement)b).x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat.create(12); + Mod.invert(SecP384R1Field.P, ((SecP384R1FieldElement)b).x, z); + SecP384R1Field.multiply(z, x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat.create(12); + SecP384R1Field.negate(x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat.create(12); + SecP384R1Field.square(x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP384R1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat.create(12); + Mod.invert(SecP384R1Field.P, x, z); + return new SecP384R1FieldElement(z); + } + + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + // Raise this element to the exponent 2^382 - 2^126 - 2^94 + 2^30 + + int[] x1 = this.x; + if (Nat.isZero(12, x1) || Nat.isOne(12, x1)) + { + return this; + } + + int[] t1 = Nat.create(12); + int[] t2 = Nat.create(12); + int[] t3 = Nat.create(12); + int[] t4 = Nat.create(12); + + SecP384R1Field.square(x1, t1); + SecP384R1Field.multiply(t1, x1, t1); + + SecP384R1Field.squareN(t1, 2, t2); + SecP384R1Field.multiply(t2, t1, t2); + + SecP384R1Field.square(t2, t2); + SecP384R1Field.multiply(t2, x1, t2); + + SecP384R1Field.squareN(t2, 5, t3); + SecP384R1Field.multiply(t3, t2, t3); + + SecP384R1Field.squareN(t3, 5, t4); + SecP384R1Field.multiply(t4, t2, t4); + + SecP384R1Field.squareN(t4, 15, t2); + SecP384R1Field.multiply(t2, t4, t2); + + SecP384R1Field.squareN(t2, 2, t3); + SecP384R1Field.multiply(t1, t3, t1); + + SecP384R1Field.squareN(t3, 28, t3); + SecP384R1Field.multiply(t2, t3, t2); + + SecP384R1Field.squareN(t2, 60, t3); + SecP384R1Field.multiply(t3, t2, t3); + + int[] r = t2; + + SecP384R1Field.squareN(t3, 120, r); + SecP384R1Field.multiply(r, t3, r); + + SecP384R1Field.squareN(r, 15, r); + SecP384R1Field.multiply(r, t4, r); + + SecP384R1Field.squareN(r, 33, r); + SecP384R1Field.multiply(r, t1, r); + + SecP384R1Field.squareN(r, 64, r); + SecP384R1Field.multiply(r, x1, r); + + SecP384R1Field.squareN(r, 30, t1); + SecP384R1Field.square(t1, t2); + + return Nat.eq(12, x1, t2) ? new SecP384R1FieldElement(t1) : null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP384R1FieldElement)) + { + return false; + } + + SecP384R1FieldElement o = (SecP384R1FieldElement)other; + return Nat.eq(12, x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 12); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java new file mode 100644 index 0000000..32c3b3f --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java @@ -0,0 +1,309 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat384; + +public class SecP384R1Point extends ECPoint.AbstractFp +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP384R1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.x, Y1 = (SecP384R1FieldElement)this.y; + SecP384R1FieldElement X2 = (SecP384R1FieldElement)b.getXCoord(), Y2 = (SecP384R1FieldElement)b.getYCoord(); + + SecP384R1FieldElement Z1 = (SecP384R1FieldElement)this.zs[0]; + SecP384R1FieldElement Z2 = (SecP384R1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat.create(24); + int[] tt2 = Nat.create(24); + int[] t3 = Nat.create(12); + int[] t4 = Nat.create(12); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP384R1Field.square(Z1.x, S2); + + U2 = tt2; + SecP384R1Field.multiply(S2, X2.x, U2); + + SecP384R1Field.multiply(S2, Z1.x, S2); + SecP384R1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP384R1Field.square(Z2.x, S1); + + U1 = tt1; + SecP384R1Field.multiply(S1, X1.x, U1); + + SecP384R1Field.multiply(S1, Z2.x, S1); + SecP384R1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat.create(12); + SecP384R1Field.subtract(U1, U2, H); + + int[] R = Nat.create(12); + SecP384R1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat.isZero(12, H)) + { + if (Nat.isZero(12, R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP384R1Field.square(H, HSquared); + + int[] G = Nat.create(12); + SecP384R1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP384R1Field.multiply(HSquared, U1, V); + + SecP384R1Field.negate(G, G); + Nat384.mul(S1, G, tt1); + + c = Nat.addBothTo(12, V, V, G); + SecP384R1Field.reduce32(c, G); + + SecP384R1FieldElement X3 = new SecP384R1FieldElement(t4); + SecP384R1Field.square(R, X3.x); + SecP384R1Field.subtract(X3.x, G, X3.x); + + SecP384R1FieldElement Y3 = new SecP384R1FieldElement(G); + SecP384R1Field.subtract(V, X3.x, Y3.x); + Nat384.mul(Y3.x, R, tt2); + SecP384R1Field.addExt(tt1, tt2, tt1); + SecP384R1Field.reduce(tt1, Y3.x); + + SecP384R1FieldElement Z3 = new SecP384R1FieldElement(H); + if (!Z1IsOne) + { + SecP384R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP384R1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; + + return new SecP384R1Point(curve, X3, Y3, zs, this.withCompression); + } + + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP384R1FieldElement Y1 = (SecP384R1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.x, Z1 = (SecP384R1FieldElement)this.zs[0]; + + int c; + int[] t1 = Nat.create(12); + int[] t2 = Nat.create(12); + + int[] Y1Squared = Nat.create(12); + SecP384R1Field.square(Y1.x, Y1Squared); + + int[] T = Nat.create(12); + SecP384R1Field.square(Y1Squared, T); + + boolean Z1IsOne = Z1.isOne(); + + int[] Z1Squared = Z1.x; + if (!Z1IsOne) + { + Z1Squared = t2; + SecP384R1Field.square(Z1.x, Z1Squared); + } + + SecP384R1Field.subtract(X1.x, Z1Squared, t1); + + int[] M = t2; + SecP384R1Field.add(X1.x, Z1Squared, M); + SecP384R1Field.multiply(M, t1, M); + c = Nat.addBothTo(12, M, M, M); + SecP384R1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP384R1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(12, S, 2, 0); + SecP384R1Field.reduce32(c, S); + + c = Nat.shiftUpBits(12, T, 3, 0, t1); + SecP384R1Field.reduce32(c, t1); + + SecP384R1FieldElement X3 = new SecP384R1FieldElement(T); + SecP384R1Field.square(M, X3.x); + SecP384R1Field.subtract(X3.x, S, X3.x); + SecP384R1Field.subtract(X3.x, S, X3.x); + + SecP384R1FieldElement Y3 = new SecP384R1FieldElement(S); + SecP384R1Field.subtract(S, X3.x, Y3.x); + SecP384R1Field.multiply(Y3.x, M, Y3.x); + SecP384R1Field.subtract(Y3.x, t1, Y3.x); + + SecP384R1FieldElement Z3 = new SecP384R1FieldElement(M); + SecP384R1Field.twice(Y1.x, Z3.x); + if (!Z1IsOne) + { + SecP384R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP384R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP384R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java new file mode 100644 index 0000000..16691b1 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java @@ -0,0 +1,80 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.encoders.Hex; + +public class SecP521R1Curve extends ECCurve.AbstractFp +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + + private static final int SecP521R1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP521R1Point infinity; + + public SecP521R1Curve() + { + super(q); + + this.infinity = new SecP521R1Point(this, null, null); + + this.a = fromBigInteger(new BigInteger(1, + Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"))); + this.b = fromBigInteger(new BigInteger(1, + Hex.decode("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"))); + this.order = new BigInteger(1, Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409")); + this.cofactor = BigInteger.valueOf(1); + + this.coord = SecP521R1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP521R1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP521R1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP521R1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP521R1Point(this, x, y, zs, withCompression); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java new file mode 100644 index 0000000..00f1066 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java @@ -0,0 +1,156 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.math.raw.Nat512; + +public class SecP521R1Field +{ + // 2^521 - 1 + static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x1FF }; + private static final int P16 = 0x1FF; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat.add(16, x, y, z) + x[16] + y[16]; + if (c > P16 || (c == P16 && Nat.eq(16, z, P))) + { + c += Nat.inc(16, z); + c &= P16; + } + z[16] = c; + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(16, x, z) + x[16]; + if (c > P16 || (c == P16 && Nat.eq(16, z, P))) + { + c += Nat.inc(16, z); + c &= P16; + } + z[16] = c; + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat.fromBigInteger(521, x); + if (Nat.eq(17, z, P)) + { + Nat.zero(17, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + int x16 = x[16]; + int c = Nat.shiftDownBit(16, x, x16, z); + z[16] = (x16 >>> 1) | (c >>> 23); + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat.create(33); + implMultiply(x, y, tt); + reduce(tt, z); + } + + public static void negate(int[] x, int[] z) + { + if (Nat.isZero(17, x)) + { + Nat.zero(17, z); + } + else + { + Nat.sub(17, P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { +// assert xx[32] >>> 18 == 0; + + int xx32 = xx[32]; + int c = Nat.shiftDownBits(16, xx, 16, 9, xx32, z, 0) >>> 23; + c += xx32 >>> 9; + c += Nat.addTo(16, xx, z); + if (c > P16 || (c == P16 && Nat.eq(16, z, P))) + { + c += Nat.inc(16, z); + c &= P16; + } + z[16] = c; + } + + public static void reduce23(int[] z) + { + int z16 = z[16]; + int c = Nat.addWordTo(16, z16 >>> 9, z) + (z16 & P16); + if (c > P16 || (c == P16 && Nat.eq(16, z, P))) + { + c += Nat.inc(16, z); + c &= P16; + } + z[16] = c; + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat.create(33); + implSquare(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat.create(33); + implSquare(x, tt); + reduce(tt, z); + + while (--n > 0) + { + implSquare(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat.sub(16, x, y, z) + x[16] - y[16]; + if (c < 0) + { + c += Nat.dec(16, z); + c &= P16; + } + z[16] = c; + } + + public static void twice(int[] x, int[] z) + { + int x16 = x[16]; + int c = Nat.shiftUpBit(16, x, x16 << 23, z) | (x16 << 1); + z[16] = c & P16; + } + + protected static void implMultiply(int[] x, int[] y, int[] zz) + { + Nat512.mul(x, y, zz); + + int x16 = x[16], y16 = y[16]; + zz[32] = Nat.mul31BothAdd(16, x16, y, y16, x, zz, 16) + (x16 * y16); + } + + protected static void implSquare(int[] x, int[] zz) + { + Nat512.square(x, zz); + + int x16 = x[16]; + zz[32] = Nat.mulWordAddTo(16, x16 << 1, x, 0, zz, 16) + (x16 * x16); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java new file mode 100644 index 0000000..ce9b639 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java @@ -0,0 +1,169 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.raw.Mod; +import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.util.Arrays; + +public class SecP521R1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP521R1Curve.q; + + protected int[] x; + + public SecP521R1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP521R1FieldElement"); + } + + this.x = SecP521R1Field.fromBigInteger(x); + } + + public SecP521R1FieldElement() + { + this.x = Nat.create(17); + } + + protected SecP521R1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat.isZero(17, x); + } + + public boolean isOne() + { + return Nat.isOne(17, x); + } + + public boolean testBitZero() + { + return Nat.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat.toBigInteger(17, x); + } + + public String getFieldName() + { + return "SecP521R1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat.create(17); + SecP521R1Field.add(x, ((SecP521R1FieldElement)b).x, z); + return new SecP521R1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat.create(17); + SecP521R1Field.addOne(x, z); + return new SecP521R1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat.create(17); + SecP521R1Field.subtract(x, ((SecP521R1FieldElement)b).x, z); + return new SecP521R1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat.create(17); + SecP521R1Field.multiply(x, ((SecP521R1FieldElement)b).x, z); + return new SecP521R1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat.create(17); + Mod.invert(SecP521R1Field.P, ((SecP521R1FieldElement)b).x, z); + SecP521R1Field.multiply(z, x, z); + return new SecP521R1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat.create(17); + SecP521R1Field.negate(x, z); + return new SecP521R1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat.create(17); + SecP521R1Field.square(x, z); + return new SecP521R1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP521R1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat.create(17); + Mod.invert(SecP521R1Field.P, x, z); + return new SecP521R1FieldElement(z); + } + + // D.1.4 91 + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + // Raise this element to the exponent 2^519 + + int[] x1 = this.x; + if (Nat.isZero(17, x1) || Nat.isOne(17, x1)) + { + return this; + } + + int[] t1 = Nat.create(17); + int[] t2 = Nat.create(17); + + SecP521R1Field.squareN(x1, 519, t1); + SecP521R1Field.square(t1, t2); + + return Nat.eq(17, x1, t2) ? new SecP521R1FieldElement(t1) : null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP521R1FieldElement)) + { + return false; + } + + SecP521R1FieldElement o = (SecP521R1FieldElement)other; + return Nat.eq(17, x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 17); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java new file mode 100644 index 0000000..d0445fa --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java @@ -0,0 +1,333 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.raw.Nat; + +public class SecP521R1Point extends ECPoint.AbstractFp +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP521R1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.x, Y1 = (SecP521R1FieldElement)this.y; + SecP521R1FieldElement X2 = (SecP521R1FieldElement)b.getXCoord(), Y2 = (SecP521R1FieldElement)b.getYCoord(); + + SecP521R1FieldElement Z1 = (SecP521R1FieldElement)this.zs[0]; + SecP521R1FieldElement Z2 = (SecP521R1FieldElement)b.getZCoord(0); + + int[] t1 = Nat.create(17); + int[] t2 = Nat.create(17); + int[] t3 = Nat.create(17); + int[] t4 = Nat.create(17); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP521R1Field.square(Z1.x, S2); + + U2 = t2; + SecP521R1Field.multiply(S2, X2.x, U2); + + SecP521R1Field.multiply(S2, Z1.x, S2); + SecP521R1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP521R1Field.square(Z2.x, S1); + + U1 = t1; + SecP521R1Field.multiply(S1, X1.x, U1); + + SecP521R1Field.multiply(S1, Z2.x, S1); + SecP521R1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat.create(17); + SecP521R1Field.subtract(U1, U2, H); + + int[] R = t2; + SecP521R1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat.isZero(17, H)) + { + if (Nat.isZero(17, R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP521R1Field.square(H, HSquared); + + int[] G = Nat.create(17); + SecP521R1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP521R1Field.multiply(HSquared, U1, V); + + SecP521R1Field.multiply(S1, G, t1); + + SecP521R1FieldElement X3 = new SecP521R1FieldElement(t4); + SecP521R1Field.square(R, X3.x); + SecP521R1Field.add(X3.x, G, X3.x); + SecP521R1Field.subtract(X3.x, V, X3.x); + SecP521R1Field.subtract(X3.x, V, X3.x); + + SecP521R1FieldElement Y3 = new SecP521R1FieldElement(G); + SecP521R1Field.subtract(V, X3.x, Y3.x); + SecP521R1Field.multiply(Y3.x, R, t2); + SecP521R1Field.subtract(t2, t1, Y3.x); + + SecP521R1FieldElement Z3 = new SecP521R1FieldElement(H); + if (!Z1IsOne) + { + SecP521R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP521R1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; + + return new SecP521R1Point(curve, X3, Y3, zs, this.withCompression); + } + + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP521R1FieldElement Y1 = (SecP521R1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP521R1FieldElement X1 = (SecP521R1FieldElement)this.x, Z1 = (SecP521R1FieldElement)this.zs[0]; + + int[] t1 = Nat.create(17); + int[] t2 = Nat.create(17); + + int[] Y1Squared = Nat.create(17); + SecP521R1Field.square(Y1.x, Y1Squared); + + int[] T = Nat.create(17); + SecP521R1Field.square(Y1Squared, T); + + boolean Z1IsOne = Z1.isOne(); + + int[] Z1Squared = Z1.x; + if (!Z1IsOne) + { + Z1Squared = t2; + SecP521R1Field.square(Z1.x, Z1Squared); + } + + SecP521R1Field.subtract(X1.x, Z1Squared, t1); + + int[] M = t2; + SecP521R1Field.add(X1.x, Z1Squared, M); + SecP521R1Field.multiply(M, t1, M); + Nat.addBothTo(17, M, M, M); + SecP521R1Field.reduce23(M); + + int[] S = Y1Squared; + SecP521R1Field.multiply(Y1Squared, X1.x, S); + Nat.shiftUpBits(17, S, 2, 0); + SecP521R1Field.reduce23(S); + + Nat.shiftUpBits(17, T, 3, 0, t1); + SecP521R1Field.reduce23(t1); + + SecP521R1FieldElement X3 = new SecP521R1FieldElement(T); + SecP521R1Field.square(M, X3.x); + SecP521R1Field.subtract(X3.x, S, X3.x); + SecP521R1Field.subtract(X3.x, S, X3.x); + + SecP521R1FieldElement Y3 = new SecP521R1FieldElement(S); + SecP521R1Field.subtract(S, X3.x, Y3.x); + SecP521R1Field.multiply(Y3.x, M, Y3.x); + SecP521R1Field.subtract(Y3.x, t1, Y3.x); + + SecP521R1FieldElement Z3 = new SecP521R1FieldElement(M); + SecP521R1Field.twice(Y1.x, Z3.x); + if (!Z1IsOne) + { + SecP521R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP521R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + protected ECFieldElement two(ECFieldElement x) + { + return x.add(x); + } + + protected ECFieldElement three(ECFieldElement x) + { + return two(x).add(x); + } + + protected ECFieldElement four(ECFieldElement x) + { + return two(two(x)); + } + + protected ECFieldElement eight(ECFieldElement x) + { + return four(two(x)); + } + + protected ECFieldElement doubleProductFromSquares(ECFieldElement a, ECFieldElement b, + ECFieldElement aSquared, ECFieldElement bSquared) + { + /* + * NOTE: If squaring in the field is faster than multiplication, then this is a quicker + * way to calculate 2.A.B, if A^2 and B^2 are already known. + */ + return a.add(b).square().subtract(aSquared).subtract(bSquared); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP521R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java new file mode 100644 index 0000000..2be0c01 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java @@ -0,0 +1,10 @@ +package org.bouncycastle.math.ec.endo; + +import org.bouncycastle.math.ec.ECPointMap; + +public interface ECEndomorphism +{ + ECPointMap getPointMap(); + + boolean hasEfficientPointMap(); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java new file mode 100644 index 0000000..8897bb3 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java @@ -0,0 +1,8 @@ +package org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +public interface GLVEndomorphism extends ECEndomorphism +{ + BigInteger[] decomposeScalar(BigInteger k); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java new file mode 100644 index 0000000..38591c0 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java @@ -0,0 +1,58 @@ +package org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPointMap; +import org.bouncycastle.math.ec.ScaleXPointMap; + +public class GLVTypeBEndomorphism implements GLVEndomorphism +{ + protected final ECCurve curve; + protected final GLVTypeBParameters parameters; + protected final ECPointMap pointMap; + + public GLVTypeBEndomorphism(ECCurve curve, GLVTypeBParameters parameters) + { + this.curve = curve; + this.parameters = parameters; + this.pointMap = new ScaleXPointMap(curve.fromBigInteger(parameters.getBeta())); + } + + public BigInteger[] decomposeScalar(BigInteger k) + { + int bits = parameters.getBits(); + BigInteger b1 = calculateB(k, parameters.getG1(), bits); + BigInteger b2 = calculateB(k, parameters.getG2(), bits); + + GLVTypeBParameters p = parameters; + BigInteger a = k.subtract((b1.multiply(p.getV1A())).add(b2.multiply(p.getV2A()))); + BigInteger b = (b1.multiply(p.getV1B())).add(b2.multiply(p.getV2B())).negate(); + + return new BigInteger[]{ a, b }; + } + + public ECPointMap getPointMap() + { + return pointMap; + } + + public boolean hasEfficientPointMap() + { + return true; + } + + protected BigInteger calculateB(BigInteger k, BigInteger g, int t) + { + boolean negative = (g.signum() < 0); + BigInteger b = k.multiply(g.abs()); + boolean extra = b.testBit(t - 1); + b = b.shiftRight(t); + if (extra) + { + b = b.add(ECConstants.ONE); + } + return negative ? b.negate() : b; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java new file mode 100644 index 0000000..92c175a --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java @@ -0,0 +1,98 @@ +package org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +public class GLVTypeBParameters +{ + private static void checkVector(BigInteger[] v, String name) + { + if (v == null || v.length != 2 || v[0] == null || v[1] == null) + { + throw new IllegalArgumentException("'" + name + "' must consist of exactly 2 (non-null) values"); + } + } + + protected final BigInteger beta; + protected final BigInteger lambda; + protected final BigInteger v1A, v1B, v2A, v2B; + protected final BigInteger g1, g2; + protected final int bits; + + public GLVTypeBParameters(BigInteger beta, BigInteger lambda, BigInteger[] v1, BigInteger[] v2, BigInteger g1, + BigInteger g2, int bits) + { + checkVector(v1, "v1"); + checkVector(v2, "v2"); + + this.beta = beta; + this.lambda = lambda; + this.v1A = v1[0]; + this.v1B = v1[1]; + this.v2A = v2[0]; + this.v2B = v2[1]; + this.g1 = g1; + this.g2 = g2; + this.bits = bits; + } + + public BigInteger getBeta() + { + return beta; + } + + public BigInteger getLambda() + { + return lambda; + } + + /** + * @deprecated Use {@link #getV1A()} and {@link #getV1B()} instead. + */ + public BigInteger[] getV1() + { + return new BigInteger[]{ v1A, v1B }; + } + + public BigInteger getV1A() + { + return v1A; + } + + public BigInteger getV1B() + { + return v1B; + } + + /** + * @deprecated Use {@link #getV2A()} and {@link #getV2B()} instead. + */ + public BigInteger[] getV2() + { + return new BigInteger[]{ v2A, v2B }; + } + + public BigInteger getV2A() + { + return v2A; + } + + public BigInteger getV2B() + { + return v2B; + } + + public BigInteger getG1() + { + return g1; + } + + public BigInteger getG2() + { + return g2; + } + + public int getBits() + { + return bits; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/ExtensionField.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/ExtensionField.java new file mode 100644 index 0000000..dfefba7 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/ExtensionField.java @@ -0,0 +1,8 @@ +package org.bouncycastle.math.field; + +public interface ExtensionField extends FiniteField +{ + FiniteField getSubfield(); + + int getDegree(); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/FiniteField.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/FiniteField.java new file mode 100644 index 0000000..0a5baa0 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/FiniteField.java @@ -0,0 +1,10 @@ +package org.bouncycastle.math.field; + +import java.math.BigInteger; + +public interface FiniteField +{ + BigInteger getCharacteristic(); + + int getDimension(); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/FiniteFields.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/FiniteFields.java new file mode 100644 index 0000000..7197ffd --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/FiniteFields.java @@ -0,0 +1,53 @@ +package org.bouncycastle.math.field; + +import java.math.BigInteger; + +public abstract class FiniteFields +{ + static final FiniteField GF_2 = new PrimeField(BigInteger.valueOf(2)); + static final FiniteField GF_3 = new PrimeField(BigInteger.valueOf(3)); + + public static PolynomialExtensionField getBinaryExtensionField(int[] exponents) + { + if (exponents[0] != 0) + { + throw new IllegalArgumentException("Irreducible polynomials in GF(2) must have constant term"); + } + for (int i = 1; i < exponents.length; ++i) + { + if (exponents[i] <= exponents[i - 1]) + { + throw new IllegalArgumentException("Polynomial exponents must be montonically increasing"); + } + } + + return new GenericPolynomialExtensionField(GF_2, new GF2Polynomial(exponents)); + } + +// public static PolynomialExtensionField getTernaryExtensionField(Term[] terms) +// { +// return new GenericPolynomialExtensionField(GF_3, new GF3Polynomial(terms)); +// } + + public static FiniteField getPrimeField(BigInteger characteristic) + { + int bitLength = characteristic.bitLength(); + if (characteristic.signum() <= 0 || bitLength < 2) + { + throw new IllegalArgumentException("'characteristic' must be >= 2"); + } + + if (bitLength < 3) + { + switch (characteristic.intValue()) + { + case 2: + return GF_2; + case 3: + return GF_3; + } + } + + return new PrimeField(characteristic); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/GF2Polynomial.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/GF2Polynomial.java new file mode 100644 index 0000000..73be768 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/GF2Polynomial.java @@ -0,0 +1,42 @@ +package org.bouncycastle.math.field; + +import org.bouncycastle.util.Arrays; + +class GF2Polynomial implements Polynomial +{ + protected final int[] exponents; + + GF2Polynomial(int[] exponents) + { + this.exponents = Arrays.clone(exponents); + } + + public int getDegree() + { + return exponents[exponents.length - 1]; + } + + public int[] getExponentsPresent() + { + return Arrays.clone(exponents); + } + + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (!(obj instanceof GF2Polynomial)) + { + return false; + } + GF2Polynomial other = (GF2Polynomial)obj; + return Arrays.areEqual(exponents, other.exponents); + } + + public int hashCode() + { + return Arrays.hashCode(exponents); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/GenericPolynomialExtensionField.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/GenericPolynomialExtensionField.java new file mode 100644 index 0000000..0b93a71 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/GenericPolynomialExtensionField.java @@ -0,0 +1,62 @@ +package org.bouncycastle.math.field; + +import java.math.BigInteger; + +import org.bouncycastle.util.Integers; + +class GenericPolynomialExtensionField implements PolynomialExtensionField +{ + protected final FiniteField subfield; + protected final Polynomial minimalPolynomial; + + GenericPolynomialExtensionField(FiniteField subfield, Polynomial polynomial) + { + this.subfield = subfield; + this.minimalPolynomial = polynomial; + } + + public BigInteger getCharacteristic() + { + return subfield.getCharacteristic(); + } + + public int getDimension() + { + return subfield.getDimension() * minimalPolynomial.getDegree(); + } + + public FiniteField getSubfield() + { + return subfield; + } + + public int getDegree() + { + return minimalPolynomial.getDegree(); + } + + public Polynomial getMinimalPolynomial() + { + return minimalPolynomial; + } + + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (!(obj instanceof GenericPolynomialExtensionField)) + { + return false; + } + GenericPolynomialExtensionField other = (GenericPolynomialExtensionField)obj; + return subfield.equals(other.subfield) && minimalPolynomial.equals(other.minimalPolynomial); + } + + public int hashCode() + { + return subfield.hashCode() + ^ Integers.rotateLeft(minimalPolynomial.hashCode(), 16); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/Polynomial.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/Polynomial.java new file mode 100644 index 0000000..e5ccd61 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/Polynomial.java @@ -0,0 +1,12 @@ +package org.bouncycastle.math.field; + +public interface Polynomial +{ + int getDegree(); + +// BigInteger[] getCoefficients(); + + int[] getExponentsPresent(); + +// Term[] getNonZeroTerms(); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/PolynomialExtensionField.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/PolynomialExtensionField.java new file mode 100644 index 0000000..aedcbee --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/PolynomialExtensionField.java @@ -0,0 +1,6 @@ +package org.bouncycastle.math.field; + +public interface PolynomialExtensionField extends ExtensionField +{ + Polynomial getMinimalPolynomial(); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/PrimeField.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/PrimeField.java new file mode 100644 index 0000000..fd1e253 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/field/PrimeField.java @@ -0,0 +1,42 @@ +package org.bouncycastle.math.field; + +import java.math.BigInteger; + +class PrimeField implements FiniteField +{ + protected final BigInteger characteristic; + + PrimeField(BigInteger characteristic) + { + this.characteristic = characteristic; + } + + public BigInteger getCharacteristic() + { + return characteristic; + } + + public int getDimension() + { + return 1; + } + + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (!(obj instanceof PrimeField)) + { + return false; + } + PrimeField other = (PrimeField)obj; + return characteristic.equals(other.characteristic); + } + + public int hashCode() + { + return characteristic.hashCode(); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Mod.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Mod.java new file mode 100644 index 0000000..47e6d8c --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Mod.java @@ -0,0 +1,199 @@ +package org.bouncycastle.math.raw; + +import java.util.Random; + +import org.bouncycastle.util.Pack; + +public abstract class Mod +{ + public static int inverse32(int d) + { +// int x = d + (((d + 1) & 4) << 1); // d.x == 1 mod 2**4 + int x = d; // d.x == 1 mod 2**3 + x *= 2 - d * x; // d.x == 1 mod 2**6 + x *= 2 - d * x; // d.x == 1 mod 2**12 + x *= 2 - d * x; // d.x == 1 mod 2**24 + x *= 2 - d * x; // d.x == 1 mod 2**48 +// assert d * x == 1; + return x; + } + + public static void invert(int[] p, int[] x, int[] z) + { + int len = p.length; + if (Nat.isZero(len, x)) + { + throw new IllegalArgumentException("'x' cannot be 0"); + } + if (Nat.isOne(len, x)) + { + System.arraycopy(x, 0, z, 0, len); + return; + } + + int[] u = Nat.copy(len, x); + int[] a = Nat.create(len); + a[0] = 1; + int ac = 0; + + if ((u[0] & 1) == 0) + { + ac = inversionStep(p, u, len, a, ac); + } + if (Nat.isOne(len, u)) + { + inversionResult(p, ac, a, z); + return; + } + + int[] v = Nat.copy(len, p); + int[] b = Nat.create(len); + int bc = 0; + + int uvLen = len; + + for (;;) + { + while (u[uvLen - 1] == 0 && v[uvLen - 1] == 0) + { + --uvLen; + } + + if (Nat.gte(uvLen, u, v)) + { + Nat.subFrom(uvLen, v, u); +// assert (u[0] & 1) == 0; + ac += Nat.subFrom(len, b, a) - bc; + ac = inversionStep(p, u, uvLen, a, ac); + if (Nat.isOne(uvLen, u)) + { + inversionResult(p, ac, a, z); + return; + } + } + else + { + Nat.subFrom(uvLen, u, v); +// assert (v[0] & 1) == 0; + bc += Nat.subFrom(len, a, b) - ac; + bc = inversionStep(p, v, uvLen, b, bc); + if (Nat.isOne(uvLen, v)) + { + inversionResult(p, bc, b, z); + return; + } + } + } + } + + public static int[] random(int[] p) + { + int len = p.length; + Random rand = new Random(); + int[] s = Nat.create(len); + + int m = p[len - 1]; + m |= m >>> 1; + m |= m >>> 2; + m |= m >>> 4; + m |= m >>> 8; + m |= m >>> 16; + + do + { + for (int i = 0; i != len; i++) + { + s[i] = rand.nextInt(); + } + s[len - 1] &= m; + } + while (Nat.gte(len, s, p)); + + return s; + } + + public static void add(int[] p, int[] x, int[] y, int[] z) + { + int len = p.length; + int c = Nat.add(len, x, y, z); + if (c != 0) + { + Nat.subFrom(len, p, z); + } + } + + public static void subtract(int[] p, int[] x, int[] y, int[] z) + { + int len = p.length; + int c = Nat.sub(len, x, y, z); + if (c != 0) + { + Nat.addTo(len, p, z); + } + } + + private static void inversionResult(int[] p, int ac, int[] a, int[] z) + { + if (ac < 0) + { + Nat.add(p.length, a, p, z); + } + else + { + System.arraycopy(a, 0, z, 0, p.length); + } + } + + private static int inversionStep(int[] p, int[] u, int uLen, int[] x, int xc) + { + int len = p.length; + int count = 0; + while (u[0] == 0) + { + Nat.shiftDownWord(uLen, u, 0); + count += 32; + } + + { + int zeroes = getTrailingZeroes(u[0]); + if (zeroes > 0) + { + Nat.shiftDownBits(uLen, u, zeroes, 0); + count += zeroes; + } + } + + for (int i = 0; i < count; ++i) + { + if ((x[0] & 1) != 0) + { + if (xc < 0) + { + xc += Nat.addTo(len, p, x); + } + else + { + xc += Nat.subFrom(len, p, x); + } + } + +// assert xc == 0 || xc == 1; + Nat.shiftDownBit(len, x, xc); + } + + return xc; + } + + private static int getTrailingZeroes(int x) + { +// assert x != 0; + + int count = 0; + while ((x & 1) == 0) + { + x >>>= 1; + ++count; + } + return count; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat.java new file mode 100644 index 0000000..2057c8b --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat.java @@ -0,0 +1,1078 @@ +package org.bouncycastle.math.raw; + +import java.math.BigInteger; + +import org.bouncycastle.util.Pack; + +public abstract class Nat +{ + private static final long M = 0xFFFFFFFFL; + + public static int add(int len, int[] x, int[] y, int[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[i] & M) + (y[i] & M); + z[i] = (int)c; + c >>>= 32; + } + return (int)c; + } + + public static int add33At(int len, int x, int[] z, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zPos + 0] & M) + (x & M); + z[zPos + 0] = (int)c; + c >>>= 32; + c += (z[zPos + 1] & M) + 1L; + z[zPos + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zPos + 2); + } + + public static int add33At(int len, int x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zOff + zPos] & M) + (x & M); + z[zOff + zPos] = (int)c; + c >>>= 32; + c += (z[zOff + zPos + 1] & M) + 1L; + z[zOff + zPos + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2); + } + + public static int add33To(int len, int x, int[] z) + { + long c = (z[0] & M) + (x & M); + z[0] = (int)c; + c >>>= 32; + c += (z[1] & M) + 1L; + z[1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, 2); + } + + public static int add33To(int len, int x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) + (x & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (z[zOff + 1] & M) + 1L; + z[zOff + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, 2); + } + + public static int addBothTo(int len, int[] x, int[] y, int[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[i] & M) + (y[i] & M) + (z[i] & M); + z[i] = (int)c; + c >>>= 32; + } + return (int)c; + } + + public static int addBothTo(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[xOff + i] & M) + (y[yOff + i] & M) + (z[zOff + i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + return (int)c; + } + + public static int addDWordAt(int len, long x, int[] z, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zPos + 0] & M) + (x & M); + z[zPos + 0] = (int)c; + c >>>= 32; + c += (z[zPos + 1] & M) + (x >>> 32); + z[zPos + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zPos + 2); + } + + public static int addDWordAt(int len, long x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zOff + zPos] & M) + (x & M); + z[zOff + zPos] = (int)c; + c >>>= 32; + c += (z[zOff + zPos + 1] & M) + (x >>> 32); + z[zOff + zPos + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2); + } + + public static int addDWordTo(int len, long x, int[] z) + { + long c = (z[0] & M) + (x & M); + z[0] = (int)c; + c >>>= 32; + c += (z[1] & M) + (x >>> 32); + z[1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, 2); + } + + public static int addDWordTo(int len, long x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) + (x & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (z[zOff + 1] & M) + (x >>> 32); + z[zOff + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, 2); + } + + public static int addTo(int len, int[] x, int[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[i] & M) + (z[i] & M); + z[i] = (int)c; + c >>>= 32; + } + return (int)c; + } + + public static int addTo(int len, int[] x, int xOff, int[] z, int zOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[xOff + i] & M) + (z[zOff + i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + return (int)c; + } + + public static int addWordAt(int len, int x, int[] z, int zPos) + { + // assert zPos <= (len - 1); + long c = (x & M) + (z[zPos] & M); + z[zPos] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zPos + 1); + } + + public static int addWordAt(int len, int x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 1); + long c = (x & M) + (z[zOff + zPos] & M); + z[zOff + zPos] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, zPos + 1); + } + + public static int addWordTo(int len, int x, int[] z) + { + long c = (x & M) + (z[0] & M); + z[0] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, 1); + } + + public static int addWordTo(int len, int x, int[] z, int zOff) + { + long c = (x & M) + (z[zOff] & M); + z[zOff] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, 1); + } + + public static int[] copy(int len, int[] x) + { + int[] z = new int[len]; + System.arraycopy(x, 0, z, 0, len); + return z; + } + + public static void copy(int len, int[] x, int[] z) + { + System.arraycopy(x, 0, z, 0, len); + } + + public static int[] create(int len) + { + return new int[len]; + } + + public static long[] create64(int len) + { + return new long[len]; + } + + public static int dec(int len, int[] z) + { + for (int i = 0; i < len; ++i) + { + if (--z[i] != -1) + { + return 0; + } + } + return -1; + } + + public static int dec(int len, int[] x, int[] z) + { + int i = 0; + while (i < len) + { + int c = x[i] - 1; + z[i] = c; + ++i; + if (c != -1) + { + while (i < len) + { + z[i] = x[i]; + ++i; + } + return 0; + } + } + return -1; + } + + public static int decAt(int len, int[] z, int zPos) + { + // assert zPos <= len; + for (int i = zPos; i < len; ++i) + { + if (--z[i] != -1) + { + return 0; + } + } + return -1; + } + + public static int decAt(int len, int[] z, int zOff, int zPos) + { + // assert zPos <= len; + for (int i = zPos; i < len; ++i) + { + if (--z[zOff + i] != -1) + { + return 0; + } + } + return -1; + } + + public static boolean eq(int len, int[] x, int[] y) + { + for (int i = len - 1; i >= 0; --i) + { + if (x[i] != y[i]) + { + return false; + } + } + return true; + } + + public static int[] fromBigInteger(int bits, BigInteger x) + { + if (x.signum() < 0 || x.bitLength() > bits) + { + throw new IllegalArgumentException(); + } + + int len = (bits + 31) >> 5; + int[] z = create(len); + int i = 0; + while (x.signum() != 0) + { + z[i++] = x.intValue(); + x = x.shiftRight(32); + } + return z; + } + + public static int getBit(int[] x, int bit) + { + if (bit == 0) + { + return x[0] & 1; + } + int w = bit >> 5; + if (w < 0 || w >= x.length) + { + return 0; + } + int b = bit & 31; + return (x[w] >>> b) & 1; + } + + public static boolean gte(int len, int[] x, int[] y) + { + for (int i = len - 1; i >= 0; --i) + { + int x_i = x[i] ^ Integer.MIN_VALUE; + int y_i = y[i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static int inc(int len, int[] z) + { + for (int i = 0; i < len; ++i) + { + if (++z[i] != 0) + { + return 0; + } + } + return 1; + } + + public static int inc(int len, int[] x, int[] z) + { + int i = 0; + while (i < len) + { + int c = x[i] + 1; + z[i] = c; + ++i; + if (c != 0) + { + while (i < len) + { + z[i] = x[i]; + ++i; + } + return 0; + } + } + return 1; + } + + public static int incAt(int len, int[] z, int zPos) + { + // assert zPos <= len; + for (int i = zPos; i < len; ++i) + { + if (++z[i] != 0) + { + return 0; + } + } + return 1; + } + + public static int incAt(int len, int[] z, int zOff, int zPos) + { + // assert zPos <= len; + for (int i = zPos; i < len; ++i) + { + if (++z[zOff + i] != 0) + { + return 0; + } + } + return 1; + } + + public static boolean isOne(int len, int[] x) + { + if (x[0] != 1) + { + return false; + } + for (int i = 1; i < len; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static boolean isZero(int len, int[] x) + { + for (int i = 0; i < len; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static void mul(int len, int[] x, int[] y, int[] zz) + { + zz[len] = mulWord(len, x[0], y, zz); + + for (int i = 1; i < len; ++i) + { + zz[i + len] = mulWordAddTo(len, x[i], y, 0, zz, i); + } + } + + public static void mul(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + zz[zzOff + len] = mulWord(len, x[xOff], y, yOff, zz, zzOff); + + for (int i = 1; i < len; ++i) + { + zz[zzOff + i + len] = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i); + } + } + + public static int mulAddTo(int len, int[] x, int[] y, int[] zz) + { + long zc = 0; + for (int i = 0; i < len; ++i) + { + long c = mulWordAddTo(len, x[i], y, 0, zz, i) & M; + c += zc + (zz[i + len] & M); + zz[i + len] = (int)c; + zc = c >>> 32; + } + return (int)zc; + } + + public static int mulAddTo(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long zc = 0; + for (int i = 0; i < len; ++i) + { + long c = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff) & M; + c += zc + (zz[zzOff + len] & M); + zz[zzOff + len] = (int)c; + zc = c >>> 32; + ++zzOff; + } + return (int)zc; + } + + public static int mul31BothAdd(int len, int a, int[] x, int b, int[] y, int[] z, int zOff) + { + long c = 0, aVal = a & M, bVal = b & M; + int i = 0; + do + { + c += aVal * (x[i] & M) + bVal * (y[i] & M) + (z[zOff + i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + while (++i < len); + return (int)c; + } + + public static int mulWord(int len, int x, int[] y, int[] z) + { + long c = 0, xVal = x & M; + int i = 0; + do + { + c += xVal * (y[i] & M); + z[i] = (int)c; + c >>>= 32; + } + while (++i < len); + return (int)c; + } + + public static int mulWord(int len, int x, int[] y, int yOff, int[] z, int zOff) + { + long c = 0, xVal = x & M; + int i = 0; + do + { + c += xVal * (y[yOff + i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + while (++i < len); + return (int)c; + } + + public static int mulWordAddTo(int len, int x, int[] y, int yOff, int[] z, int zOff) + { + long c = 0, xVal = x & M; + int i = 0; + do + { + c += xVal * (y[yOff + i] & M) + (z[zOff + i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + while (++i < len); + return (int)c; + } + + public static int mulWordDwordAddAt(int len, int x, long y, int[] z, int zPos) + { + // assert zPos <= (len - 3); + long c = 0, xVal = x & M; + c += xVal * (y & M) + (z[zPos + 0] & M); + z[zPos + 0] = (int)c; + c >>>= 32; + c += xVal * (y >>> 32) + (z[zPos + 1] & M); + z[zPos + 1] = (int)c; + c >>>= 32; + c += (z[zPos + 2] & M); + z[zPos + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zPos + 3); + } + + public static int shiftDownBit(int len, int[] z, int c) + { + int i = len; + while (--i >= 0) + { + int next = z[i]; + z[i] = (next >>> 1) | (c << 31); + c = next; + } + return c << 31; + } + + public static int shiftDownBit(int len, int[] z, int zOff, int c) + { + int i = len; + while (--i >= 0) + { + int next = z[zOff + i]; + z[zOff + i] = (next >>> 1) | (c << 31); + c = next; + } + return c << 31; + } + + public static int shiftDownBit(int len, int[] x, int c, int[] z) + { + int i = len; + while (--i >= 0) + { + int next = x[i]; + z[i] = (next >>> 1) | (c << 31); + c = next; + } + return c << 31; + } + + public static int shiftDownBit(int len, int[] x, int xOff, int c, int[] z, int zOff) + { + int i = len; + while (--i >= 0) + { + int next = x[xOff + i]; + z[zOff + i] = (next >>> 1) | (c << 31); + c = next; + } + return c << 31; + } + + public static int shiftDownBits(int len, int[] z, int bits, int c) + { +// assert bits > 0 && bits < 32; + int i = len; + while (--i >= 0) + { + int next = z[i]; + z[i] = (next >>> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + + public static int shiftDownBits(int len, int[] z, int zOff, int bits, int c) + { +// assert bits > 0 && bits < 32; + int i = len; + while (--i >= 0) + { + int next = z[zOff + i]; + z[zOff + i] = (next >>> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + + public static int shiftDownBits(int len, int[] x, int bits, int c, int[] z) + { +// assert bits > 0 && bits < 32; + int i = len; + while (--i >= 0) + { + int next = x[i]; + z[i] = (next >>> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + + public static int shiftDownBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff) + { +// assert bits > 0 && bits < 32; + int i = len; + while (--i >= 0) + { + int next = x[xOff + i]; + z[zOff + i] = (next >>> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + + public static int shiftDownWord(int len, int[] z, int c) + { + int i = len; + while (--i >= 0) + { + int next = z[i]; + z[i] = c; + c = next; + } + return c; + } + + public static int shiftUpBit(int len, int[] z, int c) + { + for (int i = 0; i < len; ++i) + { + int next = z[i]; + z[i] = (next << 1) | (c >>> 31); + c = next; + } + return c >>> 31; + } + + public static int shiftUpBit(int len, int[] z, int zOff, int c) + { + for (int i = 0; i < len; ++i) + { + int next = z[zOff + i]; + z[zOff + i] = (next << 1) | (c >>> 31); + c = next; + } + return c >>> 31; + } + + public static int shiftUpBit(int len, int[] x, int c, int[] z) + { + for (int i = 0; i < len; ++i) + { + int next = x[i]; + z[i] = (next << 1) | (c >>> 31); + c = next; + } + return c >>> 31; + } + + public static int shiftUpBit(int len, int[] x, int xOff, int c, int[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + int next = x[xOff + i]; + z[zOff + i] = (next << 1) | (c >>> 31); + c = next; + } + return c >>> 31; + } + + public static long shiftUpBit64(int len, long[] x, int xOff, long c, long[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + long next = x[xOff + i]; + z[zOff + i] = (next << 1) | (c >>> 63); + c = next; + } + return c >>> 63; + } + + public static int shiftUpBits(int len, int[] z, int bits, int c) + { +// assert bits > 0 && bits < 32; + for (int i = 0; i < len; ++i) + { + int next = z[i]; + z[i] = (next << bits) | (c >>> -bits); + c = next; + } + return c >>> -bits; + } + + public static int shiftUpBits(int len, int[] z, int zOff, int bits, int c) + { +// assert bits > 0 && bits < 32; + for (int i = 0; i < len; ++i) + { + int next = z[zOff + i]; + z[zOff + i] = (next << bits) | (c >>> -bits); + c = next; + } + return c >>> -bits; + } + + public static long shiftUpBits64(int len, long[] z, int zOff, int bits, long c) + { +// assert bits > 0 && bits < 64; + for (int i = 0; i < len; ++i) + { + long next = z[zOff + i]; + z[zOff + i] = (next << bits) | (c >>> -bits); + c = next; + } + return c >>> -bits; + } + + public static int shiftUpBits(int len, int[] x, int bits, int c, int[] z) + { +// assert bits > 0 && bits < 32; + for (int i = 0; i < len; ++i) + { + int next = x[i]; + z[i] = (next << bits) | (c >>> -bits); + c = next; + } + return c >>> -bits; + } + + public static int shiftUpBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff) + { +// assert bits > 0 && bits < 32; + for (int i = 0; i < len; ++i) + { + int next = x[xOff + i]; + z[zOff + i] = (next << bits) | (c >>> -bits); + c = next; + } + return c >>> -bits; + } + + public static long shiftUpBits64(int len, long[] x, int xOff, int bits, long c, long[] z, int zOff) + { +// assert bits > 0 && bits < 64; + for (int i = 0; i < len; ++i) + { + long next = x[xOff + i]; + z[zOff + i] = (next << bits) | (c >>> -bits); + c = next; + } + return c >>> -bits; + } + + public static void square(int len, int[] x, int[] zz) + { + int extLen = len << 1; + int c = 0; + int j = len, k = extLen; + do + { + long xVal = (x[--j] & M); + long p = xVal * xVal; + zz[--k] = (c << 31) | (int)(p >>> 33); + zz[--k] = (int)(p >>> 1); + c = (int)p; + } + while (j > 0); + + for (int i = 1; i < len; ++i) + { + c = squareWordAdd(x, i, zz); + addWordAt(extLen, c, zz, i << 1); + } + + shiftUpBit(extLen, zz, x[0] << 31); + } + + public static void square(int len, int[] x, int xOff, int[] zz, int zzOff) + { + int extLen = len << 1; + int c = 0; + int j = len, k = extLen; + do + { + long xVal = (x[xOff + --j] & M); + long p = xVal * xVal; + zz[zzOff + --k] = (c << 31) | (int)(p >>> 33); + zz[zzOff + --k] = (int)(p >>> 1); + c = (int)p; + } + while (j > 0); + + for (int i = 1; i < len; ++i) + { + c = squareWordAdd(x, xOff, i, zz, zzOff); + addWordAt(extLen, c, zz, zzOff, i << 1); + } + + shiftUpBit(extLen, zz, zzOff, x[xOff] << 31); + } + + public static int squareWordAdd(int[] x, int xPos, int[] z) + { + long c = 0, xVal = x[xPos] & M; + int i = 0; + do + { + c += xVal * (x[i] & M) + (z[xPos + i] & M); + z[xPos + i] = (int)c; + c >>>= 32; + } + while (++i < xPos); + return (int)c; + } + + public static int squareWordAdd(int[] x, int xOff, int xPos, int[] z, int zOff) + { + long c = 0, xVal = x[xOff + xPos] & M; + int i = 0; + do + { + c += xVal * (x[xOff + i] & M) + (z[xPos + zOff] & M); + z[xPos + zOff] = (int)c; + c >>>= 32; + ++zOff; + } + while (++i < xPos); + return (int)c; + } + + public static int sub(int len, int[] x, int[] y, int[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[i] & M) - (y[i] & M); + z[i] = (int)c; + c >>= 32; + } + return (int)c; + } + + public static int sub(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[xOff + i] & M) - (y[yOff + i] & M); + z[zOff + i] = (int)c; + c >>= 32; + } + return (int)c; + } + + public static int sub33At(int len, int x, int[] z, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zPos + 0] & M) - (x & M); + z[zPos + 0] = (int)c; + c >>= 32; + c += (z[zPos + 1] & M) - 1; + z[zPos + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zPos + 2); + } + + public static int sub33At(int len, int x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zOff + zPos] & M) - (x & M); + z[zOff + zPos] = (int)c; + c >>= 32; + c += (z[zOff + zPos + 1] & M) - 1; + z[zOff + zPos + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, zPos + 2); + } + + public static int sub33From(int len, int x, int[] z) + { + long c = (z[0] & M) - (x & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - 1; + z[1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, 2); + } + + public static int sub33From(int len, int x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) - (x & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (z[zOff + 1] & M) - 1; + z[zOff + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, 2); + } + + public static int subBothFrom(int len, int[] x, int[] y, int[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (z[i] & M) - (x[i] & M) - (y[i] & M); + z[i] = (int)c; + c >>= 32; + } + return (int)c; + } + + public static int subBothFrom(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (z[zOff + i] & M) - (x[xOff + i] & M) - (y[yOff + i] & M); + z[zOff + i] = (int)c; + c >>= 32; + } + return (int)c; + } + + public static int subDWordAt(int len, long x, int[] z, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zPos + 0] & M) - (x & M); + z[zPos + 0] = (int)c; + c >>= 32; + c += (z[zPos + 1] & M) - (x >>> 32); + z[zPos + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zPos + 2); + } + + public static int subDWordAt(int len, long x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zOff + zPos] & M) - (x & M); + z[zOff + zPos] = (int)c; + c >>= 32; + c += (z[zOff + zPos + 1] & M) - (x >>> 32); + z[zOff + zPos + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, zPos + 2); + } + + public static int subDWordFrom(int len, long x, int[] z) + { + long c = (z[0] & M) - (x & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - (x >>> 32); + z[1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, 2); + } + + public static int subDWordFrom(int len, long x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) - (x & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (z[zOff + 1] & M) - (x >>> 32); + z[zOff + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, 2); + } + + public static int subFrom(int len, int[] x, int[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (z[i] & M) - (x[i] & M); + z[i] = (int)c; + c >>= 32; + } + return (int)c; + } + + public static int subFrom(int len, int[] x, int xOff, int[] z, int zOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (z[zOff + i] & M) - (x[xOff + i] & M); + z[zOff + i] = (int)c; + c >>= 32; + } + return (int)c; + } + + public static int subWordAt(int len, int x, int[] z, int zPos) + { + // assert zPos <= (len - 1); + long c = (z[zPos] & M) - (x & M); + z[zPos] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zPos + 1); + } + + public static int subWordAt(int len, int x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 1); + long c = (z[zOff + zPos] & M) - (x & M); + z[zOff + zPos] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, zPos + 1); + } + + public static int subWordFrom(int len, int x, int[] z) + { + long c = (z[0] & M) - (x & M); + z[0] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, 1); + } + + public static int subWordFrom(int len, int x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) - (x & M); + z[zOff + 0] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, 1); + } + + public static BigInteger toBigInteger(int len, int[] x) + { + byte[] bs = new byte[len << 2]; + for (int i = 0; i < len; ++i) + { + int x_i = x[i]; + if (x_i != 0) + { + Pack.intToBigEndian(x_i, bs, (len - 1 - i) << 2); + } + } + return new BigInteger(1, bs); + } + + public static void zero(int len, int[] z) + { + for (int i = 0; i < len; ++i) + { + z[i] = 0; + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java new file mode 100644 index 0000000..421883e --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat192.java @@ -0,0 +1,1056 @@ +package org.bouncycastle.math.raw; + +import java.math.BigInteger; + +import org.bouncycastle.util.Pack; + +public abstract class Nat192 +{ + private static final long M = 0xFFFFFFFFL; + + public static int add(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) + (y[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (y[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (y[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (y[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (y[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (y[5] & M); + z[5] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addBothTo(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) + (y[0] & M) + (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (y[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (y[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (y[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (y[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (y[5] & M) + (z[5] & M); + z[5] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addTo(int[] x, int[] z) + { + long c = 0; + c += (x[0] & M) + (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (z[5] & M); + z[5] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn) + { + long c = cIn & M; + c += (x[xOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addToEachOther(int[] u, int uOff, int[] v, int vOff) + { + long c = 0; + c += (u[uOff + 0] & M) + (v[vOff + 0] & M); + u[uOff + 0] = (int)c; + v[vOff + 0] = (int)c; + c >>>= 32; + c += (u[uOff + 1] & M) + (v[vOff + 1] & M); + u[uOff + 1] = (int)c; + v[vOff + 1] = (int)c; + c >>>= 32; + c += (u[uOff + 2] & M) + (v[vOff + 2] & M); + u[uOff + 2] = (int)c; + v[vOff + 2] = (int)c; + c >>>= 32; + c += (u[uOff + 3] & M) + (v[vOff + 3] & M); + u[uOff + 3] = (int)c; + v[vOff + 3] = (int)c; + c >>>= 32; + c += (u[uOff + 4] & M) + (v[vOff + 4] & M); + u[uOff + 4] = (int)c; + v[vOff + 4] = (int)c; + c >>>= 32; + c += (u[uOff + 5] & M) + (v[vOff + 5] & M); + u[uOff + 5] = (int)c; + v[vOff + 5] = (int)c; + c >>>= 32; + return (int)c; + } + + public static void copy(int[] x, int[] z) + { + z[0] = x[0]; + z[1] = x[1]; + z[2] = x[2]; + z[3] = x[3]; + z[4] = x[4]; + z[5] = x[5]; + } + + public static void copy64(long[] x, long[] z) + { + z[0] = x[0]; + z[1] = x[1]; + z[2] = x[2]; + } + + public static int[] create() + { + return new int[6]; + } + + public static long[] create64() + { + return new long[3]; + } + + public static int[] createExt() + { + return new int[12]; + } + + public static long[] createExt64() + { + return new long[6]; + } + + public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + boolean pos = gte(x, xOff, y, yOff); + if (pos) + { + sub(x, xOff, y, yOff, z, zOff); + } + else + { + sub(y, yOff, x, xOff, z, zOff); + } + return pos; + } + + public static boolean eq(int[] x, int[] y) + { + for (int i = 5; i >= 0; --i) + { + if (x[i] != y[i]) + { + return false; + } + } + return true; + } + + public static boolean eq64(long[] x, long[] y) + { + for (int i = 2; i >= 0; --i) + { + if (x[i] != y[i]) + { + return false; + } + } + return true; + } + + public static int[] fromBigInteger(BigInteger x) + { + if (x.signum() < 0 || x.bitLength() > 192) + { + throw new IllegalArgumentException(); + } + + int[] z = create(); + int i = 0; + while (x.signum() != 0) + { + z[i++] = x.intValue(); + x = x.shiftRight(32); + } + return z; + } + + public static long[] fromBigInteger64(BigInteger x) + { + if (x.signum() < 0 || x.bitLength() > 192) + { + throw new IllegalArgumentException(); + } + + long[] z = create64(); + int i = 0; + while (x.signum() != 0) + { + z[i++] = x.longValue(); + x = x.shiftRight(64); + } + return z; + } + + public static int getBit(int[] x, int bit) + { + if (bit == 0) + { + return x[0] & 1; + } + int w = bit >> 5; + if (w < 0 || w >= 6) + { + return 0; + } + int b = bit & 31; + return (x[w] >>> b) & 1; + } + + public static boolean gte(int[] x, int[] y) + { + for (int i = 5; i >= 0; --i) + { + int x_i = x[i] ^ Integer.MIN_VALUE; + int y_i = y[i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static boolean gte(int[] x, int xOff, int[] y, int yOff) + { + for (int i = 5; i >= 0; --i) + { + int x_i = x[xOff + i] ^ Integer.MIN_VALUE; + int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static boolean isOne(int[] x) + { + if (x[0] != 1) + { + return false; + } + for (int i = 1; i < 6; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static boolean isOne64(long[] x) + { + if (x[0] != 1L) + { + return false; + } + for (int i = 1; i < 3; ++i) + { + if (x[i] != 0L) + { + return false; + } + } + return true; + } + + public static boolean isZero(int[] x) + { + for (int i = 0; i < 6; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static boolean isZero64(long[] x) + { + for (int i = 0; i < 3; ++i) + { + if (x[i] != 0L) + { + return false; + } + } + return true; + } + + public static void mul(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + + { + long c = 0, x_0 = x[0] & M; + c += x_0 * y_0; + zz[0] = (int)c; + c >>>= 32; + c += x_0 * y_1; + zz[1] = (int)c; + c >>>= 32; + c += x_0 * y_2; + zz[2] = (int)c; + c >>>= 32; + c += x_0 * y_3; + zz[3] = (int)c; + c >>>= 32; + c += x_0 * y_4; + zz[4] = (int)c; + c >>>= 32; + c += x_0 * y_5; + zz[5] = (int)c; + c >>>= 32; + zz[6] = (int)c; + } + + for (int i = 1; i < 6; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + zz[i + 6] = (int)c; + } + } + + public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + + { + long c = 0, x_0 = x[xOff + 0] & M; + c += x_0 * y_0; + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_0 * y_1; + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_0 * y_2; + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_0 * y_3; + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_0 * y_4; + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_0 * y_5; + zz[zzOff + 5] = (int)c; + c >>>= 32; + zz[zzOff + 6] = (int)c; + } + + for (int i = 1; i < 6; ++i) + { + ++zzOff; + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + zz[zzOff + 6] = (int)c; + } + } + + public static int mulAddTo(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + + long zc = 0; + for (int i = 0; i < 6; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + c += zc + (zz[i + 6] & M); + zz[i + 6] = (int)c; + zc = c >>> 32; + } + return (int)zc; + } + + public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + + long zc = 0; + for (int i = 0; i < 6; ++i) + { + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += zc + (zz[zzOff + 6] & M); + zz[zzOff + 6] = (int)c; + zc = c >>> 32; + ++zzOff; + } + return (int)zc; + } + + public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + // assert w >>> 31 == 0; + + long c = 0, wVal = w & M; + long x0 = x[xOff + 0] & M; + c += wVal * x0 + (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + long x1 = x[xOff + 1] & M; + c += wVal * x1 + x0 + (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + long x2 = x[xOff + 2] & M; + c += wVal * x2 + x1 + (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + long x3 = x[xOff + 3] & M; + c += wVal * x3 + x2 + (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + long x4 = x[xOff + 4] & M; + c += wVal * x4 + x3 + (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + long x5 = x[xOff + 5] & M; + c += wVal * x5 + x4 + (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += x5; + return c; + } + + public static int mulWordAddExt(int x, int[] yy, int yyOff, int[] zz, int zzOff) + { + // assert yyOff <= 6; + // assert zzOff <= 6; + long c = 0, xVal = x & M; + c += xVal * (yy[yyOff + 0] & M) + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += xVal * (yy[yyOff + 1] & M) + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += xVal * (yy[yyOff + 2] & M) + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += xVal * (yy[yyOff + 3] & M) + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += xVal * (yy[yyOff + 4] & M) + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += xVal * (yy[yyOff + 5] & M) + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mul33DWordAdd(int x, long y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 2; + + long c = 0, xVal = x & M; + long y00 = y & M; + c += xVal * y00 + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + long y01 = y >>> 32; + c += xVal * y01 + y00 + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += y01 + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(6, z, zOff, 4); + } + + public static int mul33WordAdd(int x, int y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 3; + + long c = 0, xVal = x & M, yVal = y & M; + c += yVal * xVal + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += yVal + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(6, z, zOff, 3); + } + + public static int mulWordDwordAdd(int x, long y, int[] z, int zOff) + { + // assert zOff <= 3; + long c = 0, xVal = x & M; + c += xVal * (y & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += xVal * (y >>> 32) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(6, z, zOff, 3); + } + + public static int mulWord(int x, int[] y, int[] z, int zOff) + { + long c = 0, xVal = x & M; + int i = 0; + do + { + c += xVal * (y[i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + while (++i < 6); + return (int)c; + } + + public static void square(int[] x, int[] zz) + { + long x_0 = x[0] & M; + long zz_1; + + int c = 0, w; + { + int i = 5, j = 12; + do + { + long xVal = (x[i--] & M); + long p = xVal * xVal; + zz[--j] = (c << 31) | (int)(p >>> 33); + zz[--j] = (int)(p >>> 1); + c = (int)p; + } + while (i > 0); + + { + long p = x_0 * x_0; + zz_1 = ((c << 31) & M) | (p >>> 33); + zz[0] = (int)p; + c = (int)(p >>> 32) & 1; + } + } + + long x_1 = x[1] & M; + long zz_2 = zz[2] & M; + + { + zz_1 += x_1 * x_0; + w = (int)zz_1; + zz[1] = (w << 1) | c; + c = w >>> 31; + zz_2 += zz_1 >>> 32; + } + + long x_2 = x[2] & M; + long zz_3 = zz[3] & M; + long zz_4 = zz[4] & M; + { + zz_2 += x_2 * x_0; + w = (int)zz_2; + zz[2] = (w << 1) | c; + c = w >>> 31; + zz_3 += (zz_2 >>> 32) + x_2 * x_1; + zz_4 += zz_3 >>> 32; + zz_3 &= M; + } + + long x_3 = x[3] & M; + long zz_5 = zz[5] & M; + long zz_6 = zz[6] & M; + { + zz_3 += x_3 * x_0; + w = (int)zz_3; + zz[3] = (w << 1) | c; + c = w >>> 31; + zz_4 += (zz_3 >>> 32) + x_3 * x_1; + zz_5 += (zz_4 >>> 32) + x_3 * x_2; + zz_4 &= M; + zz_6 += zz_5 >>> 32; + zz_5 &= M; + } + + long x_4 = x[4] & M; + long zz_7 = zz[7] & M; + long zz_8 = zz[8] & M; + { + zz_4 += x_4 * x_0; + w = (int)zz_4; + zz[4] = (w << 1) | c; + c = w >>> 31; + zz_5 += (zz_4 >>> 32) + x_4 * x_1; + zz_6 += (zz_5 >>> 32) + x_4 * x_2; + zz_5 &= M; + zz_7 += (zz_6 >>> 32) + x_4 * x_3; + zz_6 &= M; + zz_8 += zz_7 >>> 32; + zz_7 &= M; + } + + long x_5 = x[5] & M; + long zz_9 = zz[9] & M; + long zz_10 = zz[10] & M; + { + zz_5 += x_5 * x_0; + w = (int)zz_5; + zz[5] = (w << 1) | c; + c = w >>> 31; + zz_6 += (zz_5 >>> 32) + x_5 * x_1; + zz_7 += (zz_6 >>> 32) + x_5 * x_2; + zz_8 += (zz_7 >>> 32) + x_5 * x_3; + zz_9 += (zz_8 >>> 32) + x_5 * x_4; + zz_10 += zz_9 >>> 32; + } + + w = (int)zz_6; + zz[6] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_7; + zz[7] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_8; + zz[8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[10] = (w << 1) | c; + c = w >>> 31; + w = zz[11] + (int)(zz_10 >> 32); + zz[11] = (w << 1) | c; + } + + public static void square(int[] x, int xOff, int[] zz, int zzOff) + { + long x_0 = x[xOff + 0] & M; + long zz_1; + + int c = 0, w; + { + int i = 5, j = 12; + do + { + long xVal = (x[xOff + i--] & M); + long p = xVal * xVal; + zz[zzOff + --j] = (c << 31) | (int)(p >>> 33); + zz[zzOff + --j] = (int)(p >>> 1); + c = (int)p; + } + while (i > 0); + + { + long p = x_0 * x_0; + zz_1 = ((c << 31) & M) | (p >>> 33); + zz[zzOff + 0] = (int)p; + c = (int)(p >>> 32) & 1; + } + } + + long x_1 = x[xOff + 1] & M; + long zz_2 = zz[zzOff + 2] & M; + + { + zz_1 += x_1 * x_0; + w = (int)zz_1; + zz[zzOff + 1] = (w << 1) | c; + c = w >>> 31; + zz_2 += zz_1 >>> 32; + } + + long x_2 = x[xOff + 2] & M; + long zz_3 = zz[zzOff + 3] & M; + long zz_4 = zz[zzOff + 4] & M; + { + zz_2 += x_2 * x_0; + w = (int)zz_2; + zz[zzOff + 2] = (w << 1) | c; + c = w >>> 31; + zz_3 += (zz_2 >>> 32) + x_2 * x_1; + zz_4 += zz_3 >>> 32; + zz_3 &= M; + } + + long x_3 = x[xOff + 3] & M; + long zz_5 = zz[zzOff + 5] & M; + long zz_6 = zz[zzOff + 6] & M; + { + zz_3 += x_3 * x_0; + w = (int)zz_3; + zz[zzOff + 3] = (w << 1) | c; + c = w >>> 31; + zz_4 += (zz_3 >>> 32) + x_3 * x_1; + zz_5 += (zz_4 >>> 32) + x_3 * x_2; + zz_4 &= M; + zz_6 += zz_5 >>> 32; + zz_5 &= M; + } + + long x_4 = x[xOff + 4] & M; + long zz_7 = zz[zzOff + 7] & M; + long zz_8 = zz[zzOff + 8] & M; + { + zz_4 += x_4 * x_0; + w = (int)zz_4; + zz[zzOff + 4] = (w << 1) | c; + c = w >>> 31; + zz_5 += (zz_4 >>> 32) + x_4 * x_1; + zz_6 += (zz_5 >>> 32) + x_4 * x_2; + zz_5 &= M; + zz_7 += (zz_6 >>> 32) + x_4 * x_3; + zz_6 &= M; + zz_8 += zz_7 >>> 32; + zz_7 &= M; + } + + long x_5 = x[xOff + 5] & M; + long zz_9 = zz[zzOff + 9] & M; + long zz_10 = zz[zzOff + 10] & M; + { + zz_5 += x_5 * x_0; + w = (int)zz_5; + zz[zzOff + 5] = (w << 1) | c; + c = w >>> 31; + zz_6 += (zz_5 >>> 32) + x_5 * x_1; + zz_7 += (zz_6 >>> 32) + x_5 * x_2; + zz_8 += (zz_7 >>> 32) + x_5 * x_3; + zz_9 += (zz_8 >>> 32) + x_5 * x_4; + zz_10 += zz_9 >>> 32; + } + + w = (int)zz_6; + zz[zzOff + 6] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_7; + zz[zzOff + 7] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_8; + zz[zzOff + 8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[zzOff + 9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[zzOff + 10] = (w << 1) | c; + c = w >>> 31; + w = zz[zzOff + 11] + (int)(zz_10 >> 32); + zz[zzOff + 11] = (w << 1) | c; + } + + public static int sub(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) - (y[0] & M); + z[0] = (int)c; + c >>= 32; + c += (x[1] & M) - (y[1] & M); + z[1] = (int)c; + c >>= 32; + c += (x[2] & M) - (y[2] & M); + z[2] = (int)c; + c >>= 32; + c += (x[3] & M) - (y[3] & M); + z[3] = (int)c; + c >>= 32; + c += (x[4] & M) - (y[4] & M); + z[4] = (int)c; + c >>= 32; + c += (x[5] & M) - (y[5] & M); + z[5] = (int)c; + c >>= 32; + return (int)c; + } + + public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) - (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (x[xOff + 1] & M) - (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>= 32; + c += (x[xOff + 2] & M) - (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>= 32; + c += (x[xOff + 3] & M) - (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>= 32; + c += (x[xOff + 4] & M) - (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>= 32; + c += (x[xOff + 5] & M) - (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subBothFrom(int[] x, int[] y, int[] z) + { + long c = 0; + c += (z[0] & M) - (x[0] & M) - (y[0] & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - (x[1] & M) - (y[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M) - (x[2] & M) - (y[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M) - (y[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M) - (y[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M) - (y[5] & M); + z[5] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subFrom(int[] x, int[] z) + { + long c = 0; + c += (z[0] & M) - (x[0] & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - (x[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M) - (x[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M); + z[5] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subFrom(int[] x, int xOff, int[] z, int zOff) + { + long c = 0; + c += (z[zOff + 0] & M) - (x[xOff + 0] & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (z[zOff + 1] & M) - (x[xOff + 1] & M); + z[zOff + 1] = (int)c; + c >>= 32; + c += (z[zOff + 2] & M) - (x[xOff + 2] & M); + z[zOff + 2] = (int)c; + c >>= 32; + c += (z[zOff + 3] & M) - (x[xOff + 3] & M); + z[zOff + 3] = (int)c; + c >>= 32; + c += (z[zOff + 4] & M) - (x[xOff + 4] & M); + z[zOff + 4] = (int)c; + c >>= 32; + c += (z[zOff + 5] & M) - (x[xOff + 5] & M); + z[zOff + 5] = (int)c; + c >>= 32; + return (int)c; + } + + public static BigInteger toBigInteger(int[] x) + { + byte[] bs = new byte[24]; + for (int i = 0; i < 6; ++i) + { + int x_i = x[i]; + if (x_i != 0) + { + Pack.intToBigEndian(x_i, bs, (5 - i) << 2); + } + } + return new BigInteger(1, bs); + } + + public static BigInteger toBigInteger64(long[] x) + { + byte[] bs = new byte[24]; + for (int i = 0; i < 3; ++i) + { + long x_i = x[i]; + if (x_i != 0L) + { + Pack.longToBigEndian(x_i, bs, (2 - i) << 3); + } + } + return new BigInteger(1, bs); + } + + public static void zero(int[] z) + { + z[0] = 0; + z[1] = 0; + z[2] = 0; + z[3] = 0; + z[4] = 0; + z[5] = 0; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java new file mode 100644 index 0000000..bbe81ca --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat224.java @@ -0,0 +1,1182 @@ +package org.bouncycastle.math.raw; + +import java.math.BigInteger; + +import org.bouncycastle.util.Pack; + +public abstract class Nat224 +{ + private static final long M = 0xFFFFFFFFL; + + public static int add(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) + (y[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (y[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (y[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (y[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (y[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (y[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (y[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int add(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) + (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += (x[xOff + 6] & M) + (y[yOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addBothTo(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) + (y[0] & M) + (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (y[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (y[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (y[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (y[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (y[5] & M) + (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (y[6] & M) + (z[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addBothTo(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) + (y[yOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (y[yOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (y[yOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (y[yOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (y[yOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (y[yOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += (x[xOff + 6] & M) + (y[yOff + 6] & M) + (z[zOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addTo(int[] x, int[] z) + { + long c = 0; + c += (x[0] & M) + (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (z[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn) + { + long c = cIn & M; + c += (x[xOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += (x[xOff + 6] & M) + (z[zOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addToEachOther(int[] u, int uOff, int[] v, int vOff) + { + long c = 0; + c += (u[uOff + 0] & M) + (v[vOff + 0] & M); + u[uOff + 0] = (int)c; + v[vOff + 0] = (int)c; + c >>>= 32; + c += (u[uOff + 1] & M) + (v[vOff + 1] & M); + u[uOff + 1] = (int)c; + v[vOff + 1] = (int)c; + c >>>= 32; + c += (u[uOff + 2] & M) + (v[vOff + 2] & M); + u[uOff + 2] = (int)c; + v[vOff + 2] = (int)c; + c >>>= 32; + c += (u[uOff + 3] & M) + (v[vOff + 3] & M); + u[uOff + 3] = (int)c; + v[vOff + 3] = (int)c; + c >>>= 32; + c += (u[uOff + 4] & M) + (v[vOff + 4] & M); + u[uOff + 4] = (int)c; + v[vOff + 4] = (int)c; + c >>>= 32; + c += (u[uOff + 5] & M) + (v[vOff + 5] & M); + u[uOff + 5] = (int)c; + v[vOff + 5] = (int)c; + c >>>= 32; + c += (u[uOff + 6] & M) + (v[vOff + 6] & M); + u[uOff + 6] = (int)c; + v[vOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static void copy(int[] x, int[] z) + { + z[0] = x[0]; + z[1] = x[1]; + z[2] = x[2]; + z[3] = x[3]; + z[4] = x[4]; + z[5] = x[5]; + z[6] = x[6]; + } + + public static int[] create() + { + return new int[7]; + } + + public static int[] createExt() + { + return new int[14]; + } + + public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + boolean pos = gte(x, xOff, y, yOff); + if (pos) + { + sub(x, xOff, y, yOff, z, zOff); + } + else + { + sub(y, yOff, x, xOff, z, zOff); + } + return pos; + } + + public static boolean eq(int[] x, int[] y) + { + for (int i = 6; i >= 0; --i) + { + if (x[i] != y[i]) + { + return false; + } + } + return true; + } + + public static int[] fromBigInteger(BigInteger x) + { + if (x.signum() < 0 || x.bitLength() > 224) + { + throw new IllegalArgumentException(); + } + + int[] z = create(); + int i = 0; + while (x.signum() != 0) + { + z[i++] = x.intValue(); + x = x.shiftRight(32); + } + return z; + } + + public static int getBit(int[] x, int bit) + { + if (bit == 0) + { + return x[0] & 1; + } + int w = bit >> 5; + if (w < 0 || w >= 7) + { + return 0; + } + int b = bit & 31; + return (x[w] >>> b) & 1; + } + + public static boolean gte(int[] x, int[] y) + { + for (int i = 6; i >= 0; --i) + { + int x_i = x[i] ^ Integer.MIN_VALUE; + int y_i = y[i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static boolean gte(int[] x, int xOff, int[] y, int yOff) + { + for (int i = 6; i >= 0; --i) + { + int x_i = x[xOff + i] ^ Integer.MIN_VALUE; + int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static boolean isOne(int[] x) + { + if (x[0] != 1) + { + return false; + } + for (int i = 1; i < 7; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static boolean isZero(int[] x) + { + for (int i = 0; i < 7; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static void mul(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + long y_6 = y[6] & M; + + { + long c = 0, x_0 = x[0] & M; + c += x_0 * y_0; + zz[0] = (int)c; + c >>>= 32; + c += x_0 * y_1; + zz[1] = (int)c; + c >>>= 32; + c += x_0 * y_2; + zz[2] = (int)c; + c >>>= 32; + c += x_0 * y_3; + zz[3] = (int)c; + c >>>= 32; + c += x_0 * y_4; + zz[4] = (int)c; + c >>>= 32; + c += x_0 * y_5; + zz[5] = (int)c; + c >>>= 32; + c += x_0 * y_6; + zz[6] = (int)c; + c >>>= 32; + zz[7] = (int)c; + } + + for (int i = 1; i < 7; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[i + 6] & M); + zz[i + 6] = (int)c; + c >>>= 32; + zz[i + 7] = (int)c; + } + } + + public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + long y_6 = y[yOff + 6] & M; + + { + long c = 0, x_0 = x[xOff + 0] & M; + c += x_0 * y_0; + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_0 * y_1; + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_0 * y_2; + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_0 * y_3; + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_0 * y_4; + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_0 * y_5; + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += x_0 * y_6; + zz[zzOff + 6] = (int)c; + c >>>= 32; + zz[zzOff + 7] = (int)c; + } + + for (int i = 1; i < 7; ++i) + { + ++zzOff; + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[zzOff + 6] & M); + zz[zzOff + 6] = (int)c; + c >>>= 32; + zz[zzOff + 7] = (int)c; + } + } + + public static int mulAddTo(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + long y_6 = y[6] & M; + + long zc = 0; + for (int i = 0; i < 7; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[i + 6] & M); + zz[i + 6] = (int)c; + c >>>= 32; + c += zc + (zz[i + 7] & M); + zz[i + 7] = (int)c; + zc = c >>> 32; + } + return (int)zc; + } + + public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + long y_6 = y[yOff + 6] & M; + + long zc = 0; + for (int i = 0; i < 7; ++i) + { + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[zzOff + 6] & M); + zz[zzOff + 6] = (int)c; + c >>>= 32; + c += zc + (zz[zzOff + 7] & M); + zz[zzOff + 7] = (int)c; + zc = c >>> 32; + ++zzOff; + } + return (int)zc; + } + + public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + // assert w >>> 31 == 0; + + long c = 0, wVal = w & M; + long x0 = x[xOff + 0] & M; + c += wVal * x0 + (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + long x1 = x[xOff + 1] & M; + c += wVal * x1 + x0 + (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + long x2 = x[xOff + 2] & M; + c += wVal * x2 + x1 + (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + long x3 = x[xOff + 3] & M; + c += wVal * x3 + x2 + (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + long x4 = x[xOff + 4] & M; + c += wVal * x4 + x3 + (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + long x5 = x[xOff + 5] & M; + c += wVal * x5 + x4 + (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + long x6 = x[xOff + 6] & M; + c += wVal * x6 + x5 + (y[yOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + c += x6; + return c; + } + + public static int mulByWord(int x, int[] z) + { + long c = 0, xVal = x & M; + c += xVal * (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += xVal * (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += xVal * (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += xVal * (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += xVal * (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += xVal * (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += xVal * (z[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mulByWordAddTo(int x, int[] y, int[] z) + { + long c = 0, xVal = x & M; + c += xVal * (z[0] & M) + (y[0] & M); + z[0] = (int)c; + c >>>= 32; + c += xVal * (z[1] & M) + (y[1] & M); + z[1] = (int)c; + c >>>= 32; + c += xVal * (z[2] & M) + (y[2] & M); + z[2] = (int)c; + c >>>= 32; + c += xVal * (z[3] & M) + (y[3] & M); + z[3] = (int)c; + c >>>= 32; + c += xVal * (z[4] & M) + (y[4] & M); + z[4] = (int)c; + c >>>= 32; + c += xVal * (z[5] & M) + (y[5] & M); + z[5] = (int)c; + c >>>= 32; + c += xVal * (z[6] & M) + (y[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mulWordAddTo(int x, int[] y, int yOff, int[] z, int zOff) + { + long c = 0, xVal = x & M; + c += xVal * (y[yOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 6] & M) + (z[zOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mul33DWordAdd(int x, long y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 3; + + long c = 0, xVal = x & M; + long y00 = y & M; + c += xVal * y00 + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + long y01 = y >>> 32; + c += xVal * y01 + y00 + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += y01 + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(7, z, zOff, 4); + } + + public static int mul33WordAdd(int x, int y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 4; + + long c = 0, xVal = x & M, yVal = y & M; + c += yVal * xVal + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += yVal + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(7, z, zOff, 3); + } + + public static int mulWordDwordAdd(int x, long y, int[] z, int zOff) + { + // assert zOff <= 4; + long c = 0, xVal = x & M; + c += xVal * (y & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += xVal * (y >>> 32) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(7, z, zOff, 3); + } + + public static int mulWord(int x, int[] y, int[] z, int zOff) + { + long c = 0, xVal = x & M; + int i = 0; + do + { + c += xVal * (y[i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + while (++i < 7); + return (int)c; + } + + public static void square(int[] x, int[] zz) + { + long x_0 = x[0] & M; + long zz_1; + + int c = 0, w; + { + int i = 6, j = 14; + do + { + long xVal = (x[i--] & M); + long p = xVal * xVal; + zz[--j] = (c << 31) | (int)(p >>> 33); + zz[--j] = (int)(p >>> 1); + c = (int)p; + } + while (i > 0); + + { + long p = x_0 * x_0; + zz_1 = ((c << 31) & M) | (p >>> 33); + zz[0] = (int)p; + c = (int)(p >>> 32) & 1; + } + } + + long x_1 = x[1] & M; + long zz_2 = zz[2] & M; + + { + zz_1 += x_1 * x_0; + w = (int)zz_1; + zz[1] = (w << 1) | c; + c = w >>> 31; + zz_2 += zz_1 >>> 32; + } + + long x_2 = x[2] & M; + long zz_3 = zz[3] & M; + long zz_4 = zz[4] & M; + { + zz_2 += x_2 * x_0; + w = (int)zz_2; + zz[2] = (w << 1) | c; + c = w >>> 31; + zz_3 += (zz_2 >>> 32) + x_2 * x_1; + zz_4 += zz_3 >>> 32; + zz_3 &= M; + } + + long x_3 = x[3] & M; + long zz_5 = zz[5] & M; + long zz_6 = zz[6] & M; + { + zz_3 += x_3 * x_0; + w = (int)zz_3; + zz[3] = (w << 1) | c; + c = w >>> 31; + zz_4 += (zz_3 >>> 32) + x_3 * x_1; + zz_5 += (zz_4 >>> 32) + x_3 * x_2; + zz_4 &= M; + zz_6 += zz_5 >>> 32; + zz_5 &= M; + } + + long x_4 = x[4] & M; + long zz_7 = zz[7] & M; + long zz_8 = zz[8] & M; + { + zz_4 += x_4 * x_0; + w = (int)zz_4; + zz[4] = (w << 1) | c; + c = w >>> 31; + zz_5 += (zz_4 >>> 32) + x_4 * x_1; + zz_6 += (zz_5 >>> 32) + x_4 * x_2; + zz_5 &= M; + zz_7 += (zz_6 >>> 32) + x_4 * x_3; + zz_6 &= M; + zz_8 += zz_7 >>> 32; + zz_7 &= M; + } + + long x_5 = x[5] & M; + long zz_9 = zz[9] & M; + long zz_10 = zz[10] & M; + { + zz_5 += x_5 * x_0; + w = (int)zz_5; + zz[5] = (w << 1) | c; + c = w >>> 31; + zz_6 += (zz_5 >>> 32) + x_5 * x_1; + zz_7 += (zz_6 >>> 32) + x_5 * x_2; + zz_6 &= M; + zz_8 += (zz_7 >>> 32) + x_5 * x_3; + zz_7 &= M; + zz_9 += (zz_8 >>> 32) + x_5 * x_4; + zz_8 &= M; + zz_10 += zz_9 >>> 32; + zz_9 &= M; + } + + long x_6 = x[6] & M; + long zz_11 = zz[11] & M; + long zz_12 = zz[12] & M; + { + zz_6 += x_6 * x_0; + w = (int)zz_6; + zz[6] = (w << 1) | c; + c = w >>> 31; + zz_7 += (zz_6 >>> 32) + x_6 * x_1; + zz_8 += (zz_7 >>> 32) + x_6 * x_2; + zz_9 += (zz_8 >>> 32) + x_6 * x_3; + zz_10 += (zz_9 >>> 32) + x_6 * x_4; + zz_11 += (zz_10 >>> 32) + x_6 * x_5; + zz_12 += zz_11 >>> 32; + } + + w = (int)zz_7; + zz[7] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_8; + zz[8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[10] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_11; + zz[11] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_12; + zz[12] = (w << 1) | c; + c = w >>> 31; + w = zz[13] + (int)(zz_12 >> 32); + zz[13] = (w << 1) | c; + } + + public static void square(int[] x, int xOff, int[] zz, int zzOff) + { + long x_0 = x[xOff + 0] & M; + long zz_1; + + int c = 0, w; + { + int i = 6, j = 14; + do + { + long xVal = (x[xOff + i--] & M); + long p = xVal * xVal; + zz[zzOff + --j] = (c << 31) | (int)(p >>> 33); + zz[zzOff + --j] = (int)(p >>> 1); + c = (int)p; + } + while (i > 0); + + { + long p = x_0 * x_0; + zz_1 = ((c << 31) & M) | (p >>> 33); + zz[zzOff + 0] = (int)p; + c = (int)(p >>> 32) & 1; + } + } + + long x_1 = x[xOff + 1] & M; + long zz_2 = zz[zzOff + 2] & M; + + { + zz_1 += x_1 * x_0; + w = (int)zz_1; + zz[zzOff + 1] = (w << 1) | c; + c = w >>> 31; + zz_2 += zz_1 >>> 32; + } + + long x_2 = x[xOff + 2] & M; + long zz_3 = zz[zzOff + 3] & M; + long zz_4 = zz[zzOff + 4] & M; + { + zz_2 += x_2 * x_0; + w = (int)zz_2; + zz[zzOff + 2] = (w << 1) | c; + c = w >>> 31; + zz_3 += (zz_2 >>> 32) + x_2 * x_1; + zz_4 += zz_3 >>> 32; + zz_3 &= M; + } + + long x_3 = x[xOff + 3] & M; + long zz_5 = zz[zzOff + 5] & M; + long zz_6 = zz[zzOff + 6] & M; + { + zz_3 += x_3 * x_0; + w = (int)zz_3; + zz[zzOff + 3] = (w << 1) | c; + c = w >>> 31; + zz_4 += (zz_3 >>> 32) + x_3 * x_1; + zz_5 += (zz_4 >>> 32) + x_3 * x_2; + zz_4 &= M; + zz_6 += zz_5 >>> 32; + zz_5 &= M; + } + + long x_4 = x[xOff + 4] & M; + long zz_7 = zz[zzOff + 7] & M; + long zz_8 = zz[zzOff + 8] & M; + { + zz_4 += x_4 * x_0; + w = (int)zz_4; + zz[zzOff + 4] = (w << 1) | c; + c = w >>> 31; + zz_5 += (zz_4 >>> 32) + x_4 * x_1; + zz_6 += (zz_5 >>> 32) + x_4 * x_2; + zz_5 &= M; + zz_7 += (zz_6 >>> 32) + x_4 * x_3; + zz_6 &= M; + zz_8 += zz_7 >>> 32; + zz_7 &= M; + } + + long x_5 = x[xOff + 5] & M; + long zz_9 = zz[zzOff + 9] & M; + long zz_10 = zz[zzOff + 10] & M; + { + zz_5 += x_5 * x_0; + w = (int)zz_5; + zz[zzOff + 5] = (w << 1) | c; + c = w >>> 31; + zz_6 += (zz_5 >>> 32) + x_5 * x_1; + zz_7 += (zz_6 >>> 32) + x_5 * x_2; + zz_6 &= M; + zz_8 += (zz_7 >>> 32) + x_5 * x_3; + zz_7 &= M; + zz_9 += (zz_8 >>> 32) + x_5 * x_4; + zz_8 &= M; + zz_10 += zz_9 >>> 32; + zz_9 &= M; + } + + long x_6 = x[xOff + 6] & M; + long zz_11 = zz[zzOff + 11] & M; + long zz_12 = zz[zzOff + 12] & M; + { + zz_6 += x_6 * x_0; + w = (int)zz_6; + zz[zzOff + 6] = (w << 1) | c; + c = w >>> 31; + zz_7 += (zz_6 >>> 32) + x_6 * x_1; + zz_8 += (zz_7 >>> 32) + x_6 * x_2; + zz_9 += (zz_8 >>> 32) + x_6 * x_3; + zz_10 += (zz_9 >>> 32) + x_6 * x_4; + zz_11 += (zz_10 >>> 32) + x_6 * x_5; + zz_12 += zz_11 >>> 32; + } + + w = (int)zz_7; + zz[zzOff + 7] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_8; + zz[zzOff + 8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[zzOff + 9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[zzOff + 10] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_11; + zz[zzOff + 11] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_12; + zz[zzOff + 12] = (w << 1) | c; + c = w >>> 31; + w = zz[zzOff + 13] + (int)(zz_12 >> 32); + zz[zzOff + 13] = (w << 1) | c; + } + + public static int sub(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) - (y[0] & M); + z[0] = (int)c; + c >>= 32; + c += (x[1] & M) - (y[1] & M); + z[1] = (int)c; + c >>= 32; + c += (x[2] & M) - (y[2] & M); + z[2] = (int)c; + c >>= 32; + c += (x[3] & M) - (y[3] & M); + z[3] = (int)c; + c >>= 32; + c += (x[4] & M) - (y[4] & M); + z[4] = (int)c; + c >>= 32; + c += (x[5] & M) - (y[5] & M); + z[5] = (int)c; + c >>= 32; + c += (x[6] & M) - (y[6] & M); + z[6] = (int)c; + c >>= 32; + return (int)c; + } + + public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) - (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (x[xOff + 1] & M) - (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>= 32; + c += (x[xOff + 2] & M) - (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>= 32; + c += (x[xOff + 3] & M) - (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>= 32; + c += (x[xOff + 4] & M) - (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>= 32; + c += (x[xOff + 5] & M) - (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>= 32; + c += (x[xOff + 6] & M) - (y[yOff + 6] & M); + z[zOff + 6] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subBothFrom(int[] x, int[] y, int[] z) + { + long c = 0; + c += (z[0] & M) - (x[0] & M) - (y[0] & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - (x[1] & M) - (y[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M) - (x[2] & M) - (y[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M) - (y[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M) - (y[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M) - (y[5] & M); + z[5] = (int)c; + c >>= 32; + c += (z[6] & M) - (x[6] & M) - (y[6] & M); + z[6] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subFrom(int[] x, int[] z) + { + long c = 0; + c += (z[0] & M) - (x[0] & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - (x[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M) - (x[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M); + z[5] = (int)c; + c >>= 32; + c += (z[6] & M) - (x[6] & M); + z[6] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subFrom(int[] x, int xOff, int[] z, int zOff) + { + long c = 0; + c += (z[zOff + 0] & M) - (x[xOff + 0] & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (z[zOff + 1] & M) - (x[xOff + 1] & M); + z[zOff + 1] = (int)c; + c >>= 32; + c += (z[zOff + 2] & M) - (x[xOff + 2] & M); + z[zOff + 2] = (int)c; + c >>= 32; + c += (z[zOff + 3] & M) - (x[xOff + 3] & M); + z[zOff + 3] = (int)c; + c >>= 32; + c += (z[zOff + 4] & M) - (x[xOff + 4] & M); + z[zOff + 4] = (int)c; + c >>= 32; + c += (z[zOff + 5] & M) - (x[xOff + 5] & M); + z[zOff + 5] = (int)c; + c >>= 32; + c += (z[zOff + 6] & M) - (x[xOff + 6] & M); + z[zOff + 6] = (int)c; + c >>= 32; + return (int)c; + } + + public static BigInteger toBigInteger(int[] x) + { + byte[] bs = new byte[28]; + for (int i = 0; i < 7; ++i) + { + int x_i = x[i]; + if (x_i != 0) + { + Pack.intToBigEndian(x_i, bs, (6 - i) << 2); + } + } + return new BigInteger(1, bs); + } + + public static void zero(int[] z) + { + z[0] = 0; + z[1] = 0; + z[2] = 0; + z[3] = 0; + z[4] = 0; + z[5] = 0; + z[6] = 0; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java new file mode 100644 index 0000000..db1daac --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat256.java @@ -0,0 +1,1395 @@ +package org.bouncycastle.math.raw; + +import java.math.BigInteger; + +import org.bouncycastle.util.Pack; + +public abstract class Nat256 +{ + private static final long M = 0xFFFFFFFFL; + + public static int add(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) + (y[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (y[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (y[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (y[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (y[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (y[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (y[6] & M); + z[6] = (int)c; + c >>>= 32; + c += (x[7] & M) + (y[7] & M); + z[7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int add(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) + (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += (x[xOff + 6] & M) + (y[yOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + c += (x[xOff + 7] & M) + (y[yOff + 7] & M); + z[zOff + 7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addBothTo(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) + (y[0] & M) + (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (y[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (y[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (y[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (y[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (y[5] & M) + (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (y[6] & M) + (z[6] & M); + z[6] = (int)c; + c >>>= 32; + c += (x[7] & M) + (y[7] & M) + (z[7] & M); + z[7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addBothTo(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) + (y[yOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (y[yOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (y[yOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (y[yOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (y[yOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (y[yOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += (x[xOff + 6] & M) + (y[yOff + 6] & M) + (z[zOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + c += (x[xOff + 7] & M) + (y[yOff + 7] & M) + (z[zOff + 7] & M); + z[zOff + 7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addTo(int[] x, int[] z) + { + long c = 0; + c += (x[0] & M) + (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (z[6] & M); + z[6] = (int)c; + c >>>= 32; + c += (x[7] & M) + (z[7] & M); + z[7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn) + { + long c = cIn & M; + c += (x[xOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += (x[xOff + 6] & M) + (z[zOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + c += (x[xOff + 7] & M) + (z[zOff + 7] & M); + z[zOff + 7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addToEachOther(int[] u, int uOff, int[] v, int vOff) + { + long c = 0; + c += (u[uOff + 0] & M) + (v[vOff + 0] & M); + u[uOff + 0] = (int)c; + v[vOff + 0] = (int)c; + c >>>= 32; + c += (u[uOff + 1] & M) + (v[vOff + 1] & M); + u[uOff + 1] = (int)c; + v[vOff + 1] = (int)c; + c >>>= 32; + c += (u[uOff + 2] & M) + (v[vOff + 2] & M); + u[uOff + 2] = (int)c; + v[vOff + 2] = (int)c; + c >>>= 32; + c += (u[uOff + 3] & M) + (v[vOff + 3] & M); + u[uOff + 3] = (int)c; + v[vOff + 3] = (int)c; + c >>>= 32; + c += (u[uOff + 4] & M) + (v[vOff + 4] & M); + u[uOff + 4] = (int)c; + v[vOff + 4] = (int)c; + c >>>= 32; + c += (u[uOff + 5] & M) + (v[vOff + 5] & M); + u[uOff + 5] = (int)c; + v[vOff + 5] = (int)c; + c >>>= 32; + c += (u[uOff + 6] & M) + (v[vOff + 6] & M); + u[uOff + 6] = (int)c; + v[vOff + 6] = (int)c; + c >>>= 32; + c += (u[uOff + 7] & M) + (v[vOff + 7] & M); + u[uOff + 7] = (int)c; + v[vOff + 7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static void copy(int[] x, int[] z) + { + z[0] = x[0]; + z[1] = x[1]; + z[2] = x[2]; + z[3] = x[3]; + z[4] = x[4]; + z[5] = x[5]; + z[6] = x[6]; + z[7] = x[7]; + } + + public static void copy64(long[] x, long[] z) + { + z[0] = x[0]; + z[1] = x[1]; + z[2] = x[2]; + z[3] = x[3]; + } + + public static int[] create() + { + return new int[8]; + } + + public static long[] create64() + { + return new long[4]; + } + + public static int[] createExt() + { + return new int[16]; + } + + public static long[] createExt64() + { + return new long[8]; + } + + public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + boolean pos = gte(x, xOff, y, yOff); + if (pos) + { + sub(x, xOff, y, yOff, z, zOff); + } + else + { + sub(y, yOff, x, xOff, z, zOff); + } + return pos; + } + + public static boolean eq(int[] x, int[] y) + { + for (int i = 7; i >= 0; --i) + { + if (x[i] != y[i]) + { + return false; + } + } + return true; + } + + public static boolean eq64(long[] x, long[] y) + { + for (int i = 3; i >= 0; --i) + { + if (x[i] != y[i]) + { + return false; + } + } + return true; + } + + public static int[] fromBigInteger(BigInteger x) + { + if (x.signum() < 0 || x.bitLength() > 256) + { + throw new IllegalArgumentException(); + } + + int[] z = create(); + int i = 0; + while (x.signum() != 0) + { + z[i++] = x.intValue(); + x = x.shiftRight(32); + } + return z; + } + + public static long[] fromBigInteger64(BigInteger x) + { + if (x.signum() < 0 || x.bitLength() > 256) + { + throw new IllegalArgumentException(); + } + + long[] z = create64(); + int i = 0; + while (x.signum() != 0) + { + z[i++] = x.longValue(); + x = x.shiftRight(64); + } + return z; + } + + public static int getBit(int[] x, int bit) + { + if (bit == 0) + { + return x[0] & 1; + } + if ((bit & 255) != bit) + { + return 0; + } + int w = bit >>> 5; + int b = bit & 31; + return (x[w] >>> b) & 1; + } + + public static boolean gte(int[] x, int[] y) + { + for (int i = 7; i >= 0; --i) + { + int x_i = x[i] ^ Integer.MIN_VALUE; + int y_i = y[i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static boolean gte(int[] x, int xOff, int[] y, int yOff) + { + for (int i = 7; i >= 0; --i) + { + int x_i = x[xOff + i] ^ Integer.MIN_VALUE; + int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static boolean isOne(int[] x) + { + if (x[0] != 1) + { + return false; + } + for (int i = 1; i < 8; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static boolean isOne64(long[] x) + { + if (x[0] != 1L) + { + return false; + } + for (int i = 1; i < 4; ++i) + { + if (x[i] != 0L) + { + return false; + } + } + return true; + } + + public static boolean isZero(int[] x) + { + for (int i = 0; i < 8; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static boolean isZero64(long[] x) + { + for (int i = 0; i < 4; ++i) + { + if (x[i] != 0L) + { + return false; + } + } + return true; + } + + public static void mul(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + long y_6 = y[6] & M; + long y_7 = y[7] & M; + + { + long c = 0, x_0 = x[0] & M; + c += x_0 * y_0; + zz[0] = (int)c; + c >>>= 32; + c += x_0 * y_1; + zz[1] = (int)c; + c >>>= 32; + c += x_0 * y_2; + zz[2] = (int)c; + c >>>= 32; + c += x_0 * y_3; + zz[3] = (int)c; + c >>>= 32; + c += x_0 * y_4; + zz[4] = (int)c; + c >>>= 32; + c += x_0 * y_5; + zz[5] = (int)c; + c >>>= 32; + c += x_0 * y_6; + zz[6] = (int)c; + c >>>= 32; + c += x_0 * y_7; + zz[7] = (int)c; + c >>>= 32; + zz[8] = (int)c; + } + + for (int i = 1; i < 8; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[i + 6] & M); + zz[i + 6] = (int)c; + c >>>= 32; + c += x_i * y_7 + (zz[i + 7] & M); + zz[i + 7] = (int)c; + c >>>= 32; + zz[i + 8] = (int)c; + } + } + + public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + long y_6 = y[yOff + 6] & M; + long y_7 = y[yOff + 7] & M; + + { + long c = 0, x_0 = x[xOff + 0] & M; + c += x_0 * y_0; + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_0 * y_1; + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_0 * y_2; + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_0 * y_3; + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_0 * y_4; + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_0 * y_5; + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += x_0 * y_6; + zz[zzOff + 6] = (int)c; + c >>>= 32; + c += x_0 * y_7; + zz[zzOff + 7] = (int)c; + c >>>= 32; + zz[zzOff + 8] = (int)c; + } + + for (int i = 1; i < 8; ++i) + { + ++zzOff; + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[zzOff + 6] & M); + zz[zzOff + 6] = (int)c; + c >>>= 32; + c += x_i * y_7 + (zz[zzOff + 7] & M); + zz[zzOff + 7] = (int)c; + c >>>= 32; + zz[zzOff + 8] = (int)c; + } + } + + public static int mulAddTo(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + long y_6 = y[6] & M; + long y_7 = y[7] & M; + + long zc = 0; + for (int i = 0; i < 8; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[i + 6] & M); + zz[i + 6] = (int)c; + c >>>= 32; + c += x_i * y_7 + (zz[i + 7] & M); + zz[i + 7] = (int)c; + c >>>= 32; + c += zc + (zz[i + 8] & M); + zz[i + 8] = (int)c; + zc = c >>> 32; + } + return (int)zc; + } + + public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + long y_6 = y[yOff + 6] & M; + long y_7 = y[yOff + 7] & M; + + long zc = 0; + for (int i = 0; i < 8; ++i) + { + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[zzOff + 6] & M); + zz[zzOff + 6] = (int)c; + c >>>= 32; + c += x_i * y_7 + (zz[zzOff + 7] & M); + zz[zzOff + 7] = (int)c; + c >>>= 32; + c += zc + (zz[zzOff + 8] & M); + zz[zzOff + 8] = (int)c; + zc = c >>> 32; + ++zzOff; + } + return (int)zc; + } + + public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + // assert w >>> 31 == 0; + + long c = 0, wVal = w & M; + long x0 = x[xOff + 0] & M; + c += wVal * x0 + (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + long x1 = x[xOff + 1] & M; + c += wVal * x1 + x0 + (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + long x2 = x[xOff + 2] & M; + c += wVal * x2 + x1 + (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + long x3 = x[xOff + 3] & M; + c += wVal * x3 + x2 + (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + long x4 = x[xOff + 4] & M; + c += wVal * x4 + x3 + (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + long x5 = x[xOff + 5] & M; + c += wVal * x5 + x4 + (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + long x6 = x[xOff + 6] & M; + c += wVal * x6 + x5 + (y[yOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + long x7 = x[xOff + 7] & M; + c += wVal * x7 + x6 + (y[yOff + 7] & M); + z[zOff + 7] = (int)c; + c >>>= 32; + c += x7; + return c; + } + + public static int mulByWord(int x, int[] z) + { + long c = 0, xVal = x & M; + c += xVal * (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += xVal * (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += xVal * (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += xVal * (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += xVal * (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += xVal * (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += xVal * (z[6] & M); + z[6] = (int)c; + c >>>= 32; + c += xVal * (z[7] & M); + z[7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mulByWordAddTo(int x, int[] y, int[] z) + { + long c = 0, xVal = x & M; + c += xVal * (z[0] & M) + (y[0] & M); + z[0] = (int)c; + c >>>= 32; + c += xVal * (z[1] & M) + (y[1] & M); + z[1] = (int)c; + c >>>= 32; + c += xVal * (z[2] & M) + (y[2] & M); + z[2] = (int)c; + c >>>= 32; + c += xVal * (z[3] & M) + (y[3] & M); + z[3] = (int)c; + c >>>= 32; + c += xVal * (z[4] & M) + (y[4] & M); + z[4] = (int)c; + c >>>= 32; + c += xVal * (z[5] & M) + (y[5] & M); + z[5] = (int)c; + c >>>= 32; + c += xVal * (z[6] & M) + (y[6] & M); + z[6] = (int)c; + c >>>= 32; + c += xVal * (z[7] & M) + (y[7] & M); + z[7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mulWordAddTo(int x, int[] y, int yOff, int[] z, int zOff) + { + long c = 0, xVal = x & M; + c += xVal * (y[yOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 6] & M) + (z[zOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 7] & M) + (z[zOff + 7] & M); + z[zOff + 7] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mul33DWordAdd(int x, long y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 4; + + long c = 0, xVal = x & M; + long y00 = y & M; + c += xVal * y00 + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + long y01 = y >>> 32; + c += xVal * y01 + y00 + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += y01 + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(8, z, zOff, 4); + } + + public static int mul33WordAdd(int x, int y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 5; + + long c = 0, xVal = x & M, yVal = y & M; + c += yVal * xVal + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += yVal + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(8, z, zOff, 3); + } + + public static int mulWordDwordAdd(int x, long y, int[] z, int zOff) + { + // assert zOff <= 5; + long c = 0, xVal = x & M; + c += xVal * (y & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += xVal * (y >>> 32) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(8, z, zOff, 3); + } + + public static int mulWord(int x, int[] y, int[] z, int zOff) + { + long c = 0, xVal = x & M; + int i = 0; + do + { + c += xVal * (y[i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + while (++i < 8); + return (int)c; + } + + public static void square(int[] x, int[] zz) + { + long x_0 = x[0] & M; + long zz_1; + + int c = 0, w; + { + int i = 7, j = 16; + do + { + long xVal = (x[i--] & M); + long p = xVal * xVal; + zz[--j] = (c << 31) | (int)(p >>> 33); + zz[--j] = (int)(p >>> 1); + c = (int)p; + } + while (i > 0); + + { + long p = x_0 * x_0; + zz_1 = ((c << 31) & M) | (p >>> 33); + zz[0] = (int)p; + c = (int)(p >>> 32) & 1; + } + } + + long x_1 = x[1] & M; + long zz_2 = zz[2] & M; + + { + zz_1 += x_1 * x_0; + w = (int)zz_1; + zz[1] = (w << 1) | c; + c = w >>> 31; + zz_2 += zz_1 >>> 32; + } + + long x_2 = x[2] & M; + long zz_3 = zz[3] & M; + long zz_4 = zz[4] & M; + { + zz_2 += x_2 * x_0; + w = (int)zz_2; + zz[2] = (w << 1) | c; + c = w >>> 31; + zz_3 += (zz_2 >>> 32) + x_2 * x_1; + zz_4 += zz_3 >>> 32; + zz_3 &= M; + } + + long x_3 = x[3] & M; + long zz_5 = zz[5] & M; + long zz_6 = zz[6] & M; + { + zz_3 += x_3 * x_0; + w = (int)zz_3; + zz[3] = (w << 1) | c; + c = w >>> 31; + zz_4 += (zz_3 >>> 32) + x_3 * x_1; + zz_5 += (zz_4 >>> 32) + x_3 * x_2; + zz_4 &= M; + zz_6 += zz_5 >>> 32; + zz_5 &= M; + } + + long x_4 = x[4] & M; + long zz_7 = zz[7] & M; + long zz_8 = zz[8] & M; + { + zz_4 += x_4 * x_0; + w = (int)zz_4; + zz[4] = (w << 1) | c; + c = w >>> 31; + zz_5 += (zz_4 >>> 32) + x_4 * x_1; + zz_6 += (zz_5 >>> 32) + x_4 * x_2; + zz_5 &= M; + zz_7 += (zz_6 >>> 32) + x_4 * x_3; + zz_6 &= M; + zz_8 += zz_7 >>> 32; + zz_7 &= M; + } + + long x_5 = x[5] & M; + long zz_9 = zz[9] & M; + long zz_10 = zz[10] & M; + { + zz_5 += x_5 * x_0; + w = (int)zz_5; + zz[5] = (w << 1) | c; + c = w >>> 31; + zz_6 += (zz_5 >>> 32) + x_5 * x_1; + zz_7 += (zz_6 >>> 32) + x_5 * x_2; + zz_6 &= M; + zz_8 += (zz_7 >>> 32) + x_5 * x_3; + zz_7 &= M; + zz_9 += (zz_8 >>> 32) + x_5 * x_4; + zz_8 &= M; + zz_10 += zz_9 >>> 32; + zz_9 &= M; + } + + long x_6 = x[6] & M; + long zz_11 = zz[11] & M; + long zz_12 = zz[12] & M; + { + zz_6 += x_6 * x_0; + w = (int)zz_6; + zz[6] = (w << 1) | c; + c = w >>> 31; + zz_7 += (zz_6 >>> 32) + x_6 * x_1; + zz_8 += (zz_7 >>> 32) + x_6 * x_2; + zz_7 &= M; + zz_9 += (zz_8 >>> 32) + x_6 * x_3; + zz_8 &= M; + zz_10 += (zz_9 >>> 32) + x_6 * x_4; + zz_9 &= M; + zz_11 += (zz_10 >>> 32) + x_6 * x_5; + zz_10 &= M; + zz_12 += zz_11 >>> 32; + zz_11 &= M; + } + + long x_7 = x[7] & M; + long zz_13 = zz[13] & M; + long zz_14 = zz[14] & M; + { + zz_7 += x_7 * x_0; + w = (int)zz_7; + zz[7] = (w << 1) | c; + c = w >>> 31; + zz_8 += (zz_7 >>> 32) + x_7 * x_1; + zz_9 += (zz_8 >>> 32) + x_7 * x_2; + zz_10 += (zz_9 >>> 32) + x_7 * x_3; + zz_11 += (zz_10 >>> 32) + x_7 * x_4; + zz_12 += (zz_11 >>> 32) + x_7 * x_5; + zz_13 += (zz_12 >>> 32) + x_7 * x_6; + zz_14 += zz_13 >>> 32; + } + + w = (int)zz_8; + zz[8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[10] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_11; + zz[11] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_12; + zz[12] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_13; + zz[13] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_14; + zz[14] = (w << 1) | c; + c = w >>> 31; + w = zz[15] + (int)(zz_14 >> 32); + zz[15] = (w << 1) | c; + } + + public static void square(int[] x, int xOff, int[] zz, int zzOff) + { + long x_0 = x[xOff + 0] & M; + long zz_1; + + int c = 0, w; + { + int i = 7, j = 16; + do + { + long xVal = (x[xOff + i--] & M); + long p = xVal * xVal; + zz[zzOff + --j] = (c << 31) | (int)(p >>> 33); + zz[zzOff + --j] = (int)(p >>> 1); + c = (int)p; + } + while (i > 0); + + { + long p = x_0 * x_0; + zz_1 = ((c << 31) & M) | (p >>> 33); + zz[zzOff + 0] = (int)p; + c = (int)(p >>> 32) & 1; + } + } + + long x_1 = x[xOff + 1] & M; + long zz_2 = zz[zzOff + 2] & M; + + { + zz_1 += x_1 * x_0; + w = (int)zz_1; + zz[zzOff + 1] = (w << 1) | c; + c = w >>> 31; + zz_2 += zz_1 >>> 32; + } + + long x_2 = x[xOff + 2] & M; + long zz_3 = zz[zzOff + 3] & M; + long zz_4 = zz[zzOff + 4] & M; + { + zz_2 += x_2 * x_0; + w = (int)zz_2; + zz[zzOff + 2] = (w << 1) | c; + c = w >>> 31; + zz_3 += (zz_2 >>> 32) + x_2 * x_1; + zz_4 += zz_3 >>> 32; + zz_3 &= M; + } + + long x_3 = x[xOff + 3] & M; + long zz_5 = zz[zzOff + 5] & M; + long zz_6 = zz[zzOff + 6] & M; + { + zz_3 += x_3 * x_0; + w = (int)zz_3; + zz[zzOff + 3] = (w << 1) | c; + c = w >>> 31; + zz_4 += (zz_3 >>> 32) + x_3 * x_1; + zz_5 += (zz_4 >>> 32) + x_3 * x_2; + zz_4 &= M; + zz_6 += zz_5 >>> 32; + zz_5 &= M; + } + + long x_4 = x[xOff + 4] & M; + long zz_7 = zz[zzOff + 7] & M; + long zz_8 = zz[zzOff + 8] & M; + { + zz_4 += x_4 * x_0; + w = (int)zz_4; + zz[zzOff + 4] = (w << 1) | c; + c = w >>> 31; + zz_5 += (zz_4 >>> 32) + x_4 * x_1; + zz_6 += (zz_5 >>> 32) + x_4 * x_2; + zz_5 &= M; + zz_7 += (zz_6 >>> 32) + x_4 * x_3; + zz_6 &= M; + zz_8 += zz_7 >>> 32; + zz_7 &= M; + } + + long x_5 = x[xOff + 5] & M; + long zz_9 = zz[zzOff + 9] & M; + long zz_10 = zz[zzOff + 10] & M; + { + zz_5 += x_5 * x_0; + w = (int)zz_5; + zz[zzOff + 5] = (w << 1) | c; + c = w >>> 31; + zz_6 += (zz_5 >>> 32) + x_5 * x_1; + zz_7 += (zz_6 >>> 32) + x_5 * x_2; + zz_6 &= M; + zz_8 += (zz_7 >>> 32) + x_5 * x_3; + zz_7 &= M; + zz_9 += (zz_8 >>> 32) + x_5 * x_4; + zz_8 &= M; + zz_10 += zz_9 >>> 32; + zz_9 &= M; + } + + long x_6 = x[xOff + 6] & M; + long zz_11 = zz[zzOff + 11] & M; + long zz_12 = zz[zzOff + 12] & M; + { + zz_6 += x_6 * x_0; + w = (int)zz_6; + zz[zzOff + 6] = (w << 1) | c; + c = w >>> 31; + zz_7 += (zz_6 >>> 32) + x_6 * x_1; + zz_8 += (zz_7 >>> 32) + x_6 * x_2; + zz_7 &= M; + zz_9 += (zz_8 >>> 32) + x_6 * x_3; + zz_8 &= M; + zz_10 += (zz_9 >>> 32) + x_6 * x_4; + zz_9 &= M; + zz_11 += (zz_10 >>> 32) + x_6 * x_5; + zz_10 &= M; + zz_12 += zz_11 >>> 32; + zz_11 &= M; + } + + long x_7 = x[xOff + 7] & M; + long zz_13 = zz[zzOff + 13] & M; + long zz_14 = zz[zzOff + 14] & M; + { + zz_7 += x_7 * x_0; + w = (int)zz_7; + zz[zzOff + 7] = (w << 1) | c; + c = w >>> 31; + zz_8 += (zz_7 >>> 32) + x_7 * x_1; + zz_9 += (zz_8 >>> 32) + x_7 * x_2; + zz_10 += (zz_9 >>> 32) + x_7 * x_3; + zz_11 += (zz_10 >>> 32) + x_7 * x_4; + zz_12 += (zz_11 >>> 32) + x_7 * x_5; + zz_13 += (zz_12 >>> 32) + x_7 * x_6; + zz_14 += zz_13 >>> 32; + } + + w = (int)zz_8; + zz[zzOff + 8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[zzOff + 9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[zzOff + 10] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_11; + zz[zzOff + 11] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_12; + zz[zzOff + 12] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_13; + zz[zzOff + 13] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_14; + zz[zzOff + 14] = (w << 1) | c; + c = w >>> 31; + w = zz[zzOff + 15] + (int)(zz_14 >> 32); + zz[zzOff + 15] = (w << 1) | c; + } + + public static int sub(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) - (y[0] & M); + z[0] = (int)c; + c >>= 32; + c += (x[1] & M) - (y[1] & M); + z[1] = (int)c; + c >>= 32; + c += (x[2] & M) - (y[2] & M); + z[2] = (int)c; + c >>= 32; + c += (x[3] & M) - (y[3] & M); + z[3] = (int)c; + c >>= 32; + c += (x[4] & M) - (y[4] & M); + z[4] = (int)c; + c >>= 32; + c += (x[5] & M) - (y[5] & M); + z[5] = (int)c; + c >>= 32; + c += (x[6] & M) - (y[6] & M); + z[6] = (int)c; + c >>= 32; + c += (x[7] & M) - (y[7] & M); + z[7] = (int)c; + c >>= 32; + return (int)c; + } + + public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) - (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (x[xOff + 1] & M) - (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>= 32; + c += (x[xOff + 2] & M) - (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>= 32; + c += (x[xOff + 3] & M) - (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>= 32; + c += (x[xOff + 4] & M) - (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>= 32; + c += (x[xOff + 5] & M) - (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>= 32; + c += (x[xOff + 6] & M) - (y[yOff + 6] & M); + z[zOff + 6] = (int)c; + c >>= 32; + c += (x[xOff + 7] & M) - (y[yOff + 7] & M); + z[zOff + 7] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subBothFrom(int[] x, int[] y, int[] z) + { + long c = 0; + c += (z[0] & M) - (x[0] & M) - (y[0] & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - (x[1] & M) - (y[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M) - (x[2] & M) - (y[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M) - (y[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M) - (y[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M) - (y[5] & M); + z[5] = (int)c; + c >>= 32; + c += (z[6] & M) - (x[6] & M) - (y[6] & M); + z[6] = (int)c; + c >>= 32; + c += (z[7] & M) - (x[7] & M) - (y[7] & M); + z[7] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subFrom(int[] x, int[] z) + { + long c = 0; + c += (z[0] & M) - (x[0] & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - (x[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M) - (x[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M); + z[5] = (int)c; + c >>= 32; + c += (z[6] & M) - (x[6] & M); + z[6] = (int)c; + c >>= 32; + c += (z[7] & M) - (x[7] & M); + z[7] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subFrom(int[] x, int xOff, int[] z, int zOff) + { + long c = 0; + c += (z[zOff + 0] & M) - (x[xOff + 0] & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (z[zOff + 1] & M) - (x[xOff + 1] & M); + z[zOff + 1] = (int)c; + c >>= 32; + c += (z[zOff + 2] & M) - (x[xOff + 2] & M); + z[zOff + 2] = (int)c; + c >>= 32; + c += (z[zOff + 3] & M) - (x[xOff + 3] & M); + z[zOff + 3] = (int)c; + c >>= 32; + c += (z[zOff + 4] & M) - (x[xOff + 4] & M); + z[zOff + 4] = (int)c; + c >>= 32; + c += (z[zOff + 5] & M) - (x[xOff + 5] & M); + z[zOff + 5] = (int)c; + c >>= 32; + c += (z[zOff + 6] & M) - (x[xOff + 6] & M); + z[zOff + 6] = (int)c; + c >>= 32; + c += (z[zOff + 7] & M) - (x[xOff + 7] & M); + z[zOff + 7] = (int)c; + c >>= 32; + return (int)c; + } + + public static BigInteger toBigInteger(int[] x) + { + byte[] bs = new byte[32]; + for (int i = 0; i < 8; ++i) + { + int x_i = x[i]; + if (x_i != 0) + { + Pack.intToBigEndian(x_i, bs, (7 - i) << 2); + } + } + return new BigInteger(1, bs); + } + + public static BigInteger toBigInteger64(long[] x) + { + byte[] bs = new byte[32]; + for (int i = 0; i < 4; ++i) + { + long x_i = x[i]; + if (x_i != 0L) + { + Pack.longToBigEndian(x_i, bs, (3 - i) << 3); + } + } + return new BigInteger(1, bs); + } + + public static void zero(int[] z) + { + z[0] = 0; + z[1] = 0; + z[2] = 0; + z[3] = 0; + z[4] = 0; + z[5] = 0; + z[6] = 0; + z[7] = 0; + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat384.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat384.java new file mode 100644 index 0000000..889550e --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat384.java @@ -0,0 +1,43 @@ +package org.bouncycastle.math.raw; + + +public abstract class Nat384 +{ + public static void mul(int[] x, int[] y, int[] zz) + { + Nat192.mul(x, y, zz); + Nat192.mul(x, 6, y, 6, zz, 12); + + int c18 = Nat192.addToEachOther(zz, 6, zz, 12); + int c12 = c18 + Nat192.addTo(zz, 0, zz, 6, 0); + c18 += Nat192.addTo(zz, 18, zz, 12, c12); + + int[] dx = Nat192.create(), dy = Nat192.create(); + boolean neg = Nat192.diff(x, 6, x, 0, dx, 0) != Nat192.diff(y, 6, y, 0, dy, 0); + + int[] tt = Nat192.createExt(); + Nat192.mul(dx, dy, tt); + + c18 += neg ? Nat.addTo(12, tt, 0, zz, 6) : Nat.subFrom(12, tt, 0, zz, 6); + Nat.addWordAt(24, c18, zz, 18); + } + + public static void square(int[] x, int[] zz) + { + Nat192.square(x, zz); + Nat192.square(x, 6, zz, 12); + + int c18 = Nat192.addToEachOther(zz, 6, zz, 12); + int c12 = c18 + Nat192.addTo(zz, 0, zz, 6, 0); + c18 += Nat192.addTo(zz, 18, zz, 12, c12); + + int[] dx = Nat192.create(); + Nat192.diff(x, 6, x, 0, dx, 0); + + int[] tt = Nat192.createExt(); + Nat192.square(dx, tt); + + c18 += Nat.subFrom(12, tt, 0, zz, 6); + Nat.addWordAt(24, c18, zz, 18); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat512.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat512.java new file mode 100644 index 0000000..594e8f5 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/math/raw/Nat512.java @@ -0,0 +1,43 @@ +package org.bouncycastle.math.raw; + + +public abstract class Nat512 +{ + public static void mul(int[] x, int[] y, int[] zz) + { + Nat256.mul(x, y, zz); + Nat256.mul(x, 8, y, 8, zz, 16); + + int c24 = Nat256.addToEachOther(zz, 8, zz, 16); + int c16 = c24 + Nat256.addTo(zz, 0, zz, 8, 0); + c24 += Nat256.addTo(zz, 24, zz, 16, c16); + + int[] dx = Nat256.create(), dy = Nat256.create(); + boolean neg = Nat256.diff(x, 8, x, 0, dx, 0) != Nat256.diff(y, 8, y, 0, dy, 0); + + int[] tt = Nat256.createExt(); + Nat256.mul(dx, dy, tt); + + c24 += neg ? Nat.addTo(16, tt, 0, zz, 8) : Nat.subFrom(16, tt, 0, zz, 8); + Nat.addWordAt(32, c24, zz, 24); + } + + public static void square(int[] x, int[] zz) + { + Nat256.square(x, zz); + Nat256.square(x, 8, zz, 16); + + int c24 = Nat256.addToEachOther(zz, 8, zz, 16); + int c16 = c24 + Nat256.addTo(zz, 0, zz, 8, 0); + c24 += Nat256.addTo(zz, 24, zz, 16, c16); + + int[] dx = Nat256.create(); + Nat256.diff(x, 8, x, 0, dx, 0); + + int[] tt = Nat256.createExt(); + Nat256.square(dx, tt); + + c24 += Nat.subFrom(16, tt, 0, zz, 8); + Nat.addWordAt(32, c24, zz, 24); + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Arrays.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Arrays.java index 3f7677c..99325a9 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Arrays.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Arrays.java @@ -1,6 +1,7 @@ package org.bouncycastle.util; import java.math.BigInteger; +import java.util.NoSuchElementException; /** * General array utilities. @@ -324,6 +325,25 @@ public final class Arrays return hc; } + public static int hashCode(byte[] data, int off, int len) + { + if (data == null) + { + return 0; + } + + int i = len; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= data[off + i]; + } + + return hc; + } + public static int hashCode(char[] data) { if (data == null) @@ -374,6 +394,69 @@ public final class Arrays return hc; } + public static int hashCode(int[] data, int off, int len) + { + if (data == null) + { + return 0; + } + + int i = len; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= data[off + i]; + } + + return hc; + } + + public static int hashCode(long[] data) + { + if (data == null) + { + return 0; + } + + int i = data.length; + int hc = i + 1; + + while (--i >= 0) + { + long di = data[i]; + hc *= 257; + hc ^= (int)di; + hc *= 257; + hc ^= (int)(di >>> 32); + } + + return hc; + } + + public static int hashCode(long[] data, int off, int len) + { + if (data == null) + { + return 0; + } + + int i = len; + int hc = i + 1; + + while (--i >= 0) + { + long di = data[off + i]; + hc *= 257; + hc ^= (int)di; + hc *= 257; + hc ^= (int)(di >>> 32); + } + + return hc; + } + public static int hashCode(short[][][] shorts) { int hc = 0; @@ -449,6 +532,19 @@ public final class Arrays return copy; } + public static char[] clone(char[] data) + { + if (data == null) + { + return null; + } + char[] copy = new char[data.length]; + + System.arraycopy(data, 0, copy, 0, data.length); + + return copy; + } + public static byte[] clone(byte[] data, byte[] existing) { if (data == null) @@ -752,6 +848,20 @@ public final class Arrays return result; } + public static short[] append(short[] a, short b) + { + if (a == null) + { + return new short[]{ b }; + } + + int length = a.length; + short[] result = new short[length + 1]; + System.arraycopy(a, 0, result, 0, length); + result[length] = b; + return result; + } + public static int[] append(int[] a, int b) { if (a == null) @@ -799,6 +909,10 @@ public final class Arrays return rv; } + else if (a == null) + { + return concatenate(b, c); + } else if (b == null) { return concatenate(a, c); @@ -840,6 +954,23 @@ public final class Arrays } } + public static int[] concatenate(int[] a, int[] b) + { + if (a == null) + { + return clone(b); + } + if (b == null) + { + return clone(a); + } + + int[] c = new int[a.length + b.length]; + System.arraycopy(a, 0, c, 0, a.length); + System.arraycopy(b, 0, c, a.length, b.length); + return c; + } + public static byte[] prepend(byte[] a, byte b) { if (a == null) @@ -853,4 +984,112 @@ public final class Arrays result[0] = b; return result; } + + public static short[] prepend(short[] a, short b) + { + if (a == null) + { + return new short[]{ b }; + } + + int length = a.length; + short[] result = new short[length + 1]; + System.arraycopy(a, 0, result, 1, length); + result[0] = b; + return result; + } + + public static int[] prepend(int[] a, int b) + { + if (a == null) + { + return new int[]{ b }; + } + + int length = a.length; + int[] result = new int[length + 1]; + System.arraycopy(a, 0, result, 1, length); + result[0] = b; + return result; + } + + public static byte[] reverse(byte[] a) + { + if (a == null) + { + return null; + } + + int p1 = 0, p2 = a.length; + byte[] result = new byte[p2]; + + while (--p2 >= 0) + { + result[p2] = a[p1++]; + } + + return result; + } + + public static int[] reverse(int[] a) + { + if (a == null) + { + return null; + } + + int p1 = 0, p2 = a.length; + int[] result = new int[p2]; + + while (--p2 >= 0) + { + result[p2] = a[p1++]; + } + + return result; + } + + /** + * Iterator backed by a specific array. + */ + public static class Iterator + implements java.util.Iterator + { + private final T[] dataArray; + + private int position = 0; + + /** + * Base constructor. + *

    + * Note: the array is not cloned, changes to it will affect the values returned by next(). + *

    + * + * @param dataArray array backing the iterator. + */ + public Iterator(T[] dataArray) + { + this.dataArray = dataArray; + } + + public boolean hasNext() + { + return position < dataArray.length; + } + + public T next() + { + if (position == dataArray.length) + { + throw new NoSuchElementException("Out of elements: " + position); + } + + return dataArray[position++]; + } + + public void remove() + { + throw new UnsupportedOperationException("Cannot remove element from an Array."); + } + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/CollectionStore.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/CollectionStore.java index 91aba14..1cc9641 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/CollectionStore.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/CollectionStore.java @@ -8,10 +8,10 @@ import java.util.List; /** * A simple collection backed store. */ -public class CollectionStore - implements Store +public class CollectionStore + implements Store, Iterable { - private Collection _local; + private Collection _local; /** * Basic constructor. @@ -19,9 +19,9 @@ public class CollectionStore * @param collection - initial contents for the store, this is copied. */ public CollectionStore( - Collection collection) + Collection collection) { - _local = new ArrayList(collection); + _local = new ArrayList(collection); } /** @@ -30,20 +30,20 @@ public class CollectionStore * @param selector the selector to match against. * @return a possibly empty collection of matching objects. */ - public Collection getMatches(Selector selector) + public Collection getMatches(Selector selector) { if (selector == null) { - return new ArrayList(_local); + return new ArrayList(_local); } else { - List col = new ArrayList(); - Iterator iter = _local.iterator(); + List col = new ArrayList(); + Iterator iter = _local.iterator(); while (iter.hasNext()) { - Object obj = iter.next(); + T obj = iter.next(); if (selector.match(obj)) { @@ -54,4 +54,9 @@ public class CollectionStore return col; } } + + public Iterator iterator() + { + return getMatches(null).iterator(); + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Encodable.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Encodable.java new file mode 100644 index 0000000..67258fb --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Encodable.java @@ -0,0 +1,18 @@ +package org.bouncycastle.util; + +import java.io.IOException; + +/** + * Interface implemented by objects that can be converted into byte arrays. + */ +public interface Encodable +{ + /** + * Return a byte array representing the implementing object. + * + * @return a byte array representing the encoding. + * @throws java.io.IOException if an issue arises generation the encoding. + */ + byte[] getEncoded() + throws IOException; +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java index 9f5d1cb..8af1709 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java @@ -1,5 +1,8 @@ package org.bouncycastle.util; +/** + * Utility methods for processing String objects containing IP addresses. + */ public class IPAddress { /** diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Integers.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Integers.java index 599a9e0..cbae4a3 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Integers.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Integers.java @@ -1,7 +1,20 @@ package org.bouncycastle.util; +/** + * Utility methods for ints. + */ public class Integers { + public static int rotateLeft(int i, int distance) + { + return Integer.rotateLeft(i, distance); + } + + public static int rotateRight(int i, int distance) + { + return Integer.rotateRight(i, distance); + } + public static Integer valueOf(int value) { return Integer.valueOf(value); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Iterable.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Iterable.java new file mode 100644 index 0000000..a0fa9dc --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Iterable.java @@ -0,0 +1,17 @@ +package org.bouncycastle.util; + +import java.util.Iterator; + +/** + * Utility class to allow use of Iterable feature in JDK 1.5+ + */ +public interface Iterable + extends java.lang.Iterable +{ + /** + * Returns an iterator over a set of elements of type T. + * + * @return an Iterator. + */ + Iterator iterator(); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Memoable.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Memoable.java index 0be9171..bf40f4e 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Memoable.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Memoable.java @@ -1,23 +1,27 @@ package org.bouncycastle.util; +/** + * Interface for Memoable objects. Memoable objects allow the taking of a snapshot of their internal state + * via the copy() method and then reseting the object back to that state later using the reset() method. + */ public interface Memoable { /** * Produce a copy of this object with its configuration and in its current state. - *

    + *

    * The returned object may be used simply to store the state, or may be used as a similar object * starting from the copied state. */ - public Memoable copy(); + Memoable copy(); /** * Restore a copied object state into this object. - *

    + *

    * Implementations of this method should try to avoid or minimise memory allocation to perform the reset. * * @param other an object originally {@link #copy() copied} from an object of the same type as this instance. * @throws ClassCastException if the provided object is not of the correct type. * @throws MemoableResetException if the other parameter is in some other way invalid. */ - public void reset(Memoable other); + void reset(Memoable other); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Pack.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Pack.java new file mode 100644 index 0000000..94ba17b --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Pack.java @@ -0,0 +1,204 @@ +package org.bouncycastle.util; + +/** + * Utility methods for converting byte arrays into ints and longs, and back again. + */ +public abstract class Pack +{ + public static int bigEndianToInt(byte[] bs, int off) + { + int n = bs[ off] << 24; + n |= (bs[++off] & 0xff) << 16; + n |= (bs[++off] & 0xff) << 8; + n |= (bs[++off] & 0xff); + return n; + } + + public static void bigEndianToInt(byte[] bs, int off, int[] ns) + { + for (int i = 0; i < ns.length; ++i) + { + ns[i] = bigEndianToInt(bs, off); + off += 4; + } + } + + public static byte[] intToBigEndian(int n) + { + byte[] bs = new byte[4]; + intToBigEndian(n, bs, 0); + return bs; + } + + public static void intToBigEndian(int n, byte[] bs, int off) + { + bs[ off] = (byte)(n >>> 24); + bs[++off] = (byte)(n >>> 16); + bs[++off] = (byte)(n >>> 8); + bs[++off] = (byte)(n ); + } + + public static byte[] intToBigEndian(int[] ns) + { + byte[] bs = new byte[4 * ns.length]; + intToBigEndian(ns, bs, 0); + return bs; + } + + public static void intToBigEndian(int[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.length; ++i) + { + intToBigEndian(ns[i], bs, off); + off += 4; + } + } + + public static long bigEndianToLong(byte[] bs, int off) + { + int hi = bigEndianToInt(bs, off); + int lo = bigEndianToInt(bs, off + 4); + return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL); + } + + public static void bigEndianToLong(byte[] bs, int off, long[] ns) + { + for (int i = 0; i < ns.length; ++i) + { + ns[i] = bigEndianToLong(bs, off); + off += 8; + } + } + + public static byte[] longToBigEndian(long n) + { + byte[] bs = new byte[8]; + longToBigEndian(n, bs, 0); + return bs; + } + + public static void longToBigEndian(long n, byte[] bs, int off) + { + intToBigEndian((int)(n >>> 32), bs, off); + intToBigEndian((int)(n & 0xffffffffL), bs, off + 4); + } + + public static byte[] longToBigEndian(long[] ns) + { + byte[] bs = new byte[8 * ns.length]; + longToBigEndian(ns, bs, 0); + return bs; + } + + public static void longToBigEndian(long[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.length; ++i) + { + longToBigEndian(ns[i], bs, off); + off += 8; + } + } + + public static int littleEndianToInt(byte[] bs, int off) + { + int n = bs[ off] & 0xff; + n |= (bs[++off] & 0xff) << 8; + n |= (bs[++off] & 0xff) << 16; + n |= bs[++off] << 24; + return n; + } + + public static void littleEndianToInt(byte[] bs, int off, int[] ns) + { + for (int i = 0; i < ns.length; ++i) + { + ns[i] = littleEndianToInt(bs, off); + off += 4; + } + } + + public static void littleEndianToInt(byte[] bs, int bOff, int[] ns, int nOff, int count) + { + for (int i = 0; i < count; ++i) + { + ns[nOff + i] = littleEndianToInt(bs, bOff); + bOff += 4; + } + } + + public static byte[] intToLittleEndian(int n) + { + byte[] bs = new byte[4]; + intToLittleEndian(n, bs, 0); + return bs; + } + + public static void intToLittleEndian(int n, byte[] bs, int off) + { + bs[ off] = (byte)(n ); + bs[++off] = (byte)(n >>> 8); + bs[++off] = (byte)(n >>> 16); + bs[++off] = (byte)(n >>> 24); + } + + public static byte[] intToLittleEndian(int[] ns) + { + byte[] bs = new byte[4 * ns.length]; + intToLittleEndian(ns, bs, 0); + return bs; + } + + public static void intToLittleEndian(int[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.length; ++i) + { + intToLittleEndian(ns[i], bs, off); + off += 4; + } + } + + public static long littleEndianToLong(byte[] bs, int off) + { + int lo = littleEndianToInt(bs, off); + int hi = littleEndianToInt(bs, off + 4); + return ((long)(hi & 0xffffffffL) << 32) | (long)(lo & 0xffffffffL); + } + + public static void littleEndianToLong(byte[] bs, int off, long[] ns) + { + for (int i = 0; i < ns.length; ++i) + { + ns[i] = littleEndianToLong(bs, off); + off += 8; + } + } + + public static byte[] longToLittleEndian(long n) + { + byte[] bs = new byte[8]; + longToLittleEndian(n, bs, 0); + return bs; + } + + public static void longToLittleEndian(long n, byte[] bs, int off) + { + intToLittleEndian((int)(n & 0xffffffffL), bs, off); + intToLittleEndian((int)(n >>> 32), bs, off + 4); + } + + public static byte[] longToLittleEndian(long[] ns) + { + byte[] bs = new byte[8 * ns.length]; + longToLittleEndian(ns, bs, 0); + return bs; + } + + public static void longToLittleEndian(long[] ns, byte[] bs, int off) + { + for (int i = 0; i < ns.length; ++i) + { + longToLittleEndian(ns[i], bs, off); + off += 8; + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Properties.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Properties.java new file mode 100644 index 0000000..96cef35 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Properties.java @@ -0,0 +1,36 @@ +package org.bouncycastle.util; + +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Utility method for accessing system properties. + */ +public class Properties +{ + public static boolean isOverrideSet(final String propertyName) + { + try + { + return "true".equals(AccessController.doPrivileged(new PrivilegedAction() + { + // JDK 1.4 compatibility + public Object run() + { + String value = System.getProperty(propertyName); + if (value == null) + { + return null; + } + + return Strings.toLowerCase(value); + } + })); + } + catch (AccessControlException e) + { + return false; + } + } +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Selector.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Selector.java index 7ad86bf..f3366c7 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Selector.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Selector.java @@ -1,9 +1,20 @@ package org.bouncycastle.util; -public interface Selector +/** + * Interface a selector from a store should conform to. + * + * @param the type stored in the store. + */ +public interface Selector extends Cloneable { - boolean match(Object obj); + /** + * Match the passed in object, returning true if it would be selected by this selector, false otherwise. + * + * @param obj the object to be matched. + * @return true if the object is a match for this selector, false otherwise. + */ + boolean match(T obj); Object clone(); } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Store.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Store.java index b994c92..0f55039 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Store.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Store.java @@ -2,8 +2,21 @@ package org.bouncycastle.util; import java.util.Collection; -public interface Store +/** + * A generic interface describing a simple store of objects. + * + * @param the object type stored. + */ +public interface Store { - Collection getMatches(Selector selector) + /** + * Return a possibly empty collection of objects that match the criteria implemented + * in the passed in Selector. + * + * @param selector the selector defining the match criteria. + * @return a collection of matching objects, empty if none available. + * @throws StoreException if there is a failure during matching. + */ + Collection getMatches(Selector selector) throws StoreException; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/StoreException.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/StoreException.java index 5ea09e8..7cca271 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/StoreException.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/StoreException.java @@ -1,14 +1,23 @@ package org.bouncycastle.util; +/** + * Exception thrown if there's an issue doing a match in store. + */ public class StoreException extends RuntimeException { private Throwable _e; - public StoreException(String s, Throwable e) + /** + * Basic Constructor. + * + * @param msg message to be associated with this exception. + * @param cause the throwable that caused this exception to be raised. + */ + public StoreException(String msg, Throwable cause) { - super(s); - _e = e; + super(msg); + _e = cause; } public Throwable getCause() diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/StringList.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/StringList.java new file mode 100644 index 0000000..4eb8514 --- /dev/null +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/StringList.java @@ -0,0 +1,42 @@ +package org.bouncycastle.util; + +/** + * An interface defining a list of strings. + */ +public interface StringList + extends Iterable +{ + /** + * Add a String to the list. + * + * @param s the String to add. + * @return true + */ + boolean add(String s); + + /** + * Get the string at index index. + * + * @param index the index position of the String of interest. + * @return the String at position index. + */ + String get(int index); + + int size(); + + /** + * Return the contents of the list as an array. + * + * @return an array of String. + */ + String[] toStringArray(); + + /** + * Return a section of the contents of the list. If the list is too short the array is filled with nulls. + * + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * @return an array of length to - from + */ + String[] toStringArray(int from, int to); +} diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Strings.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Strings.java index 7f67404..a42830b 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Strings.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/Strings.java @@ -3,10 +3,46 @@ package org.bouncycastle.util; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.Vector; +/** + * String utilities. + */ public final class Strings { + private static String LINE_SEPARATOR; + + static + { + try + { + LINE_SEPARATOR = AccessController.doPrivileged(new PrivilegedAction() + { + public String run() + { + // the easy way + return System.getProperty("line.separator"); + } + }); + + } + catch (Exception e) + { + try + { + // the harder way + LINE_SEPARATOR = String.format("%n"); + } + catch (Exception ef) + { + LINE_SEPARATOR = "\n"; // we're desperate use this... + } + } + } + public static String fromUTF8ByteArray(byte[] bytes) { int i = 0; @@ -46,7 +82,7 @@ public final class Strings if ((bytes[i] & 0xf0) == 0xf0) { - int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i+1] & 0x3F) << 12) | ((bytes[i+2] & 0x3F) << 6) | (bytes[i+3] & 0x3F); + int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i + 1] & 0x3F) << 12) | ((bytes[i + 2] & 0x3F) << 6) | (bytes[i + 3] & 0x3F); int U = codePoint - 0x10000; char W1 = (char)(0xD800 | (U >> 10)); char W2 = (char)(0xDC00 | (U & 0x3FF)); @@ -57,7 +93,7 @@ public final class Strings else if ((bytes[i] & 0xe0) == 0xe0) { ch = (char)(((bytes[i] & 0x0f) << 12) - | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f)); + | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f)); i += 3; } else if ((bytes[i] & 0xd0) == 0xd0) @@ -81,7 +117,7 @@ public final class Strings return new String(cs); } - + public static byte[] toUTF8ByteArray(String string) { return toUTF8ByteArray(string.toCharArray()); @@ -99,7 +135,7 @@ public final class Strings { throw new IllegalStateException("cannot encode string to byte array!"); } - + return bOut.toByteArray(); } @@ -159,7 +195,7 @@ public final class Strings /** * A locale independent version of toUpperCase. - * + * * @param string input to be converted * @return a US Ascii uppercase version */ @@ -167,7 +203,7 @@ public final class Strings { boolean changed = false; char[] chars = string.toCharArray(); - + for (int i = 0; i != chars.length; i++) { char ch = chars[i]; @@ -177,18 +213,18 @@ public final class Strings chars[i] = (char)(ch - 'a' + 'A'); } } - + if (changed) { return new String(chars); } - + return string; } - + /** * A locale independent version of toLowerCase. - * + * * @param string input to be converted * @return a US ASCII lowercase version */ @@ -196,7 +232,7 @@ public final class Strings { boolean changed = false; char[] chars = string.toCharArray(); - + for (int i = 0; i != chars.length; i++) { char ch = chars[i]; @@ -206,12 +242,12 @@ public final class Strings chars[i] = (char)(ch - 'A' + 'a'); } } - + if (changed) { return new String(chars); } - + return string; } @@ -241,6 +277,17 @@ public final class Strings return bytes; } + public static int toByteArray(String s, byte[] buf, int off) + { + int count = s.length(); + for (int i = 0; i < count; ++i) + { + char c = s.charAt(i); + buf[off + i] = (byte)c; + } + return count; + } + /** * Convert an array of 8 bit characters into a string. * @@ -272,7 +319,7 @@ public final class Strings public static String[] split(String input, char delimiter) { - Vector v = new Vector(); + Vector v = new Vector(); boolean moreTokens = true; String subString; @@ -300,4 +347,58 @@ public final class Strings } return res; } + + public static StringList newList() + { + return new StringListImpl(); + } + + public static String lineSeparator() + { + return LINE_SEPARATOR; + } + + private static class StringListImpl + extends ArrayList + implements StringList + { + public boolean add(String s) + { + return super.add(s); + } + + public String set(int index, String element) + { + return super.set(index, element); + } + + public void add(int index, String element) + { + super.add(index, element); + } + + public String[] toStringArray() + { + String[] strs = new String[this.size()]; + + for (int i = 0; i != strs.length; i++) + { + strs[i] = this.get(i); + } + + return strs; + } + + public String[] toStringArray(int from, int to) + { + String[] strs = new String[to - from]; + + for (int i = from; i != this.size() && i != to; i++) + { + strs[i - from] = this.get(i); + } + + return strs; + } + } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64.java index 8380629..c04a8cc 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64.java @@ -6,6 +6,9 @@ import java.io.OutputStream; import org.bouncycastle.util.Strings; +/** + * Utility class for converting Base64 data to bytes and back again. + */ public class Base64 { private static final Encoder encoder = new Base64Encoder(); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java index 1ef8f51..abad02c 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java @@ -3,24 +3,27 @@ package org.bouncycastle.util.encoders; import java.io.IOException; import java.io.OutputStream; +/** + * A streaming Base64 encoder. + */ public class Base64Encoder implements Encoder { protected final byte[] encodingTable = - { - (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', - (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', - (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', - (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', - (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', - (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', - (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', - (byte)'v', - (byte)'w', (byte)'x', (byte)'y', (byte)'z', - (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', - (byte)'7', (byte)'8', (byte)'9', - (byte)'+', (byte)'/' - }; + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', + (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', + (byte)'7', (byte)'8', (byte)'9', + (byte)'+', (byte)'/' + }; protected byte padding = (byte)'='; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/DecoderException.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/DecoderException.java index d9914a2..1e6782a 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/DecoderException.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/DecoderException.java @@ -1,5 +1,8 @@ package org.bouncycastle.util.encoders; +/** + * Exception thrown if an attempt is made to decode invalid data, or some other failure occurs. + */ public class DecoderException extends IllegalStateException { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/EncoderException.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/EncoderException.java index 2d09a63..a1eb411 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/EncoderException.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/EncoderException.java @@ -1,5 +1,8 @@ package org.bouncycastle.util.encoders; +/** + * Exception thrown if an attempt is made to encode invalid data, or some other failure occurs. + */ public class EncoderException extends IllegalStateException { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Hex.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Hex.java index d49f1ef..63e9c71 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Hex.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/Hex.java @@ -6,6 +6,9 @@ import java.io.OutputStream; import org.bouncycastle.util.Strings; +/** + * Utility class for converting hex data to bytes and back again. + */ public class Hex { private static final Encoder encoder = new HexEncoder(); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java index 3bb594b..52f8fa6 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java @@ -3,15 +3,18 @@ package org.bouncycastle.util.encoders; import java.io.IOException; import java.io.OutputStream; +/** + * A streaming Hex encoder. + */ public class HexEncoder implements Encoder { protected final byte[] encodingTable = - { - (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', - (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' - }; - + { + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', + (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' + }; + /* * set up the decoding table. */ diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/StreamOverflowException.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/StreamOverflowException.java index 01af8da..ed5518d 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/StreamOverflowException.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/StreamOverflowException.java @@ -2,6 +2,9 @@ package org.bouncycastle.util.io; import java.io.IOException; +/** + * Exception thrown when too much data is written to an InputStream + */ public class StreamOverflowException extends IOException { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java index 41560b5..f39e026 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java @@ -5,10 +5,19 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +/** + * Utility methods to assist with stream processing. + */ public final class Streams { - private static int BUFFER_SIZE = 512; + private static int BUFFER_SIZE = 4096; + /** + * Read stream till EOF is encountered. + * + * @param inStr stream to be emptied. + * @throws IOException in case of underlying IOException. + */ public static void drain(InputStream inStr) throws IOException { @@ -18,6 +27,13 @@ public final class Streams } } + /** + * Read stream fully, returning contents in a byte array. + * + * @param inStr stream to be read. + * @return a byte array representing the contents of inStr. + * @throws IOException in case of underlying IOException. + */ public static byte[] readAll(InputStream inStr) throws IOException { @@ -26,6 +42,15 @@ public final class Streams return buf.toByteArray(); } + /** + * Read from inStr up to a maximum number of bytes, throwing an exception if more the maximum amount + * of requested data is available. + * + * @param inStr stream to be read. + * @param limit maximum number of bytes that can be read. + * @return a byte array representing the contents of inStr. + * @throws IOException in case of underlying IOException, or if limit is reached on inStr still has data in it. + */ public static byte[] readAllLimited(InputStream inStr, int limit) throws IOException { @@ -34,12 +59,30 @@ public final class Streams return buf.toByteArray(); } + /** + * Fully read in buf's length in data, or up to EOF, whichever occurs first, + * + * @param inStr the stream to be read. + * @param buf the buffer to be read into. + * @return the number of bytes read into the buffer. + * @throws IOException in case of underlying IOException. + */ public static int readFully(InputStream inStr, byte[] buf) throws IOException { return readFully(inStr, buf, 0, buf.length); } + /** + * Fully read in len's bytes of data into buf, or up to EOF, whichever occurs first, + * + * @param inStr the stream to be read. + * @param buf the buffer to be read into. + * @param off offset into buf to start putting bytes into. + * @param len the number of bytes to be read. + * @return the number of bytes read into the buffer. + * @throws IOException in case of underlying IOException. + */ public static int readFully(InputStream inStr, byte[] buf, int off, int len) throws IOException { @@ -56,6 +99,13 @@ public final class Streams return totalRead; } + /** + * Write the full contents of inStr to the destination stream outStr. + * + * @param inStr source input stream. + * @param outStr destination output stream. + * @throws IOException in case of underlying IOException. + */ public static void pipeAll(InputStream inStr, OutputStream outStr) throws IOException { @@ -67,6 +117,14 @@ public final class Streams } } + /** + * Write up to limit bytes of data from inStr to the destination stream outStr. + * + * @param inStr source input stream. + * @param limit the maximum number of bytes allowed to be read. + * @param outStr destination output stream. + * @throws IOException in case of underlying IOException, or if limit is reached on inStr still has data in it. + */ public static long pipeAllLimited(InputStream inStr, long limit, OutputStream outStr) throws IOException { @@ -75,11 +133,11 @@ public final class Streams int numRead; while ((numRead = inStr.read(bs, 0, bs.length)) >= 0) { - total += numRead; - if (total > limit) + if ((limit - total) < numRead) { throw new StreamOverflowException("Data Overflow"); } + total += numRead; outStr.write(bs, 0, numRead); } return total; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/TeeInputStream.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/TeeInputStream.java index 9154246..96da169 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/TeeInputStream.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/TeeInputStream.java @@ -4,12 +4,21 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +/** + * An input stream which copies anything read through it to another stream. + */ public class TeeInputStream extends InputStream { private final InputStream input; private final OutputStream output; + /** + * Base constructor. + * + * @param input input stream to be wrapped. + * @param output output stream to copy any input read to. + */ public TeeInputStream(InputStream input, OutputStream output) { this.input = input; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java index a4919cd..05b2b56 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java @@ -3,12 +3,22 @@ package org.bouncycastle.util.io; import java.io.IOException; import java.io.OutputStream; + +/** + * An output stream which copies anything written into it to another stream. + */ public class TeeOutputStream extends OutputStream { private OutputStream output1; private OutputStream output2; + /** + * Base constructor. + * + * @param output1 the output stream that is wrapped. + * @param output2 a secondary stream that anything written to output1 is also written to. + */ public TeeOutputStream(OutputStream output1, OutputStream output2) { this.output1 = output1; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java index 69a773e..63f61f2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java @@ -2,6 +2,9 @@ package org.bouncycastle.util.io.pem; import java.io.IOException; +/** + * Exception thrown on failure to generate a PEM object. + */ public class PemGenerationException extends IOException { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java index b201c13..bbc6108 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java @@ -1,10 +1,19 @@ package org.bouncycastle.util.io.pem; +/** + * Class representing a PEM header (name, value) pair. + */ public class PemHeader { private String name; private String value; + /** + * Base constructor. + * + * @param name name of the header property. + * @param value value of the header property. + */ public PemHeader(String name, String value) { this.name = name; diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObject.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObject.java index 2199520..606330d 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObject.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObject.java @@ -4,6 +4,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +/** + * A generic PEM object - type, header properties, and byte content. + */ public class PemObject implements PemObjectGenerator { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java index 6fffdc5..9664639 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java @@ -1,7 +1,16 @@ package org.bouncycastle.util.io.pem; +/** + * Base interface for generators of PEM objects. + */ public interface PemObjectGenerator { + /** + * Generate a PEM object. + * + * @return the generated object. + * @throws PemGenerationException on failure. + */ PemObject generate() throws PemGenerationException; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java index b18b550..933da6a 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java @@ -2,8 +2,18 @@ package org.bouncycastle.util.io.pem; import java.io.IOException; +/** + * Base interface for parsers to convert PEM objects into specific objects. + */ public interface PemObjectParser { + /** + * Parse an object out of the PEM object passed in. + * + * @param obj the PEM object containing the details for the specific object. + * @return a specific object represented by the PEM object. + * @throws IOException on a parsing error. + */ Object parseObject(PemObject obj) throws IOException; } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java index 7664725..3045b4d 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java @@ -8,6 +8,9 @@ import java.util.List; import org.bouncycastle.util.encoders.Base64; +/** + * A generic PEM reader, based on the format outlined in RFC 1421 + */ public class PemReader extends BufferedReader { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java index ccefa36..b496447 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.io.Writer; import java.util.Iterator; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Base64; /** @@ -27,7 +28,7 @@ public class PemWriter { super(out); - String nl = System.getProperty("line.separator"); + String nl = Strings.lineSeparator(); if (nl != null) { nlLength = nl.length(); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java index b00cd1d..15375ab 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java @@ -126,7 +126,7 @@ public class AttributeCertificateHolder String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest) { holder = new Holder(new ObjectDigestInfo(digestedObjectType, - new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(digestAlgorithm), Arrays + new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(new ASN1ObjectIdentifier(digestAlgorithm)), Arrays .clone(objectDigest))); } @@ -164,7 +164,7 @@ public class AttributeCertificateHolder { if (holder.getObjectDigestInfo() != null) { - return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId() + return holder.getObjectDigestInfo().getDigestAlgorithm().getAlgorithm() .getId(); } return null; @@ -322,7 +322,7 @@ public class AttributeCertificateHolder public Object clone() { return new AttributeCertificateHolder((ASN1Sequence)holder - .toASN1Object()); + .toASN1Primitive()); } public boolean match(Certificate cert) diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java index 51831d0..386fc3d 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java @@ -17,6 +17,7 @@ import java.util.Set; * * @see java.security.cert.PKIXBuilderParameters * @see org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi + * @deprecated use PKIXExtendedBuilderParameters */ public class ExtendedPKIXBuilderParameters extends ExtendedPKIXParameters { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java index 6386618..952f775 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java @@ -18,6 +18,8 @@ import java.util.Set; /** * This class extends the PKIXParameters with a validity model parameter. + * + * @deprecated use PKIXExtendedParameters */ public class ExtendedPKIXParameters extends PKIXParameters @@ -42,8 +44,11 @@ public class ExtendedPKIXParameters /** * Creates an instance of PKIXParameters with the specified * Set of most-trusted CAs. Each element of the set is a - * {@link TrustAnchor TrustAnchor}.

    Note that the Set + * {@link TrustAnchor TrustAnchor}. + *

    + * Note that the Set * is copied to protect against subsequent modifications. + *

    * * @param trustAnchors a Set of TrustAnchors * @throws InvalidAlgorithmParameterException if the specified @@ -154,8 +159,11 @@ public class ExtendedPKIXParameters * when the end certificate was signed. The CA (or Root CA) certificate must * have been valid, when the CA certificate was signed and so on. So the * {@link PKIXParameters#setDate(java.util.Date)} method sets the time, when - * the end certificate must have been valid.

    It is used e.g. + * the end certificate must have been valid. + *

    + * It is used e.g. * in the German signature law. + *

    */ public static final int CHAIN_VALIDITY_MODEL = 1; @@ -278,6 +286,7 @@ public class ExtendedPKIXParameters * * @param store The store to add. * @see #getStores() + * @deprectaed use addStore(). */ public void addAdditionalStore(Store store) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509Attribute.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509Attribute.java index 95da292..f5e9531 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509Attribute.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509Attribute.java @@ -11,6 +11,7 @@ import org.bouncycastle.asn1.x509.Attribute; /** * Class for carrying the values in an X.509 Attribute. + * @deprecated see X509CertificateHolder class in the PKIX package. */ public class X509Attribute extends ASN1Object diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java index 48a825f..d65ec78 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java @@ -15,6 +15,7 @@ import java.util.Date; /** * Interface for an X.509 Attribute Certificate. + * @deprecated use X509CertificateHolder class in the PKIX package. */ public interface X509AttributeCertificate extends X509Extension diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java index cc50b8f..2486d20 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java @@ -1,17 +1,17 @@ package org.bouncycastle.x509; -import org.bouncycastle.asn1.DERInteger; -import org.bouncycastle.asn1.x509.X509Extensions; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Selector; -import org.bouncycastle.x509.extension.X509ExtensionUtil; - import java.io.IOException; import java.math.BigInteger; import java.security.cert.CRL; import java.security.cert.X509CRL; import java.security.cert.X509CRLSelector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Selector; +import org.bouncycastle.x509.extension.X509ExtensionUtil; + /** * This class is a Selector implementation for X.509 certificate revocation * lists. @@ -96,14 +96,14 @@ public class X509CRLStoreSelector return false; } X509CRL crl = (X509CRL)obj; - DERInteger dci = null; + ASN1Integer dci = null; try { byte[] bytes = crl .getExtensionValue(X509Extensions.DeltaCRLIndicator.getId()); if (bytes != null) { - dci = DERInteger.getInstance(X509ExtensionUtil + dci = ASN1Integer.getInstance(X509ExtensionUtil .fromExtensionValue(bytes)); } } diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509CertStoreSelector.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509CertStoreSelector.java index b272649..6535328 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509CertStoreSelector.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509CertStoreSelector.java @@ -1,18 +1,19 @@ package org.bouncycastle.x509; -import org.bouncycastle.util.Selector; - import java.io.IOException; import java.security.cert.Certificate; import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate; +import org.bouncycastle.util.Selector; + /** * This class is a Selector implementation for X.509 certificates. * * @see org.bouncycastle.util.Selector * @see org.bouncycastle.x509.X509Store * @see org.bouncycastle.jce.provider.X509StoreCertCollection + * @deprecated use the classes under org.bouncycastle.cert.selector */ public class X509CertStoreSelector extends X509CertSelector diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java index 7cf2e9d..ecf910f 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java @@ -23,8 +23,8 @@ import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERObjectIdentifier; // BEGIN android-removed // import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; // END android-removed @@ -148,21 +148,21 @@ class X509Util new ASN1Integer(1)); } - static DERObjectIdentifier getAlgorithmOID( + static ASN1ObjectIdentifier getAlgorithmOID( String algorithmName) { algorithmName = Strings.toUpperCase(algorithmName); if (algorithms.containsKey(algorithmName)) { - return (DERObjectIdentifier)algorithms.get(algorithmName); + return (ASN1ObjectIdentifier)algorithms.get(algorithmName); } - return new DERObjectIdentifier(algorithmName); + return new ASN1ObjectIdentifier(algorithmName); } static AlgorithmIdentifier getSigAlgID( - DERObjectIdentifier sigOid, + ASN1ObjectIdentifier sigOid, String algorithmName) { if (noParams.contains(sigOid)) @@ -218,7 +218,7 @@ class X509Util } static byte[] calculateSignature( - DERObjectIdentifier sigOid, + ASN1ObjectIdentifier sigOid, String sigName, PrivateKey key, SecureRandom random, @@ -249,7 +249,7 @@ class X509Util } static byte[] calculateSignature( - DERObjectIdentifier sigOid, + ASN1ObjectIdentifier sigOid, String sigName, String provider, PrivateKey key, diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java index ac44d73..01f4469 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java @@ -1,6 +1,5 @@ package org.bouncycastle.x509; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.math.BigInteger; import java.security.GeneralSecurityException; @@ -20,11 +19,9 @@ import java.util.Iterator; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.Certificate; @@ -43,7 +40,7 @@ import org.bouncycastle.jce.provider.X509CertificateObject; public class X509V1CertificateGenerator { private V1TBSCertificateGenerator tbsGen; - private DERObjectIdentifier sigOID; + private ASN1ObjectIdentifier sigOID; private AlgorithmIdentifier sigAlgId; private String signatureAlgorithm; @@ -143,8 +140,7 @@ public class X509V1CertificateGenerator { try { - tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream( - new ByteArrayInputStream(key.getEncoded())).readObject())); + tbsGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(key.getEncoded())); } catch (Exception e) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java index 14db8ea..61319a8 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java @@ -103,7 +103,7 @@ public class X509V2AttributeCertificate public AttributeCertificateHolder getHolder() { - return new AttributeCertificateHolder((ASN1Sequence)cert.getAcinfo().getHolder().toASN1Object()); + return new AttributeCertificateHolder((ASN1Sequence)cert.getAcinfo().getHolder().toASN1Primitive()); } public AttributeCertificateIssuer getIssuer() @@ -164,7 +164,7 @@ public class X509V2AttributeCertificate public byte[] getSignature() { - return cert.getSignatureValue().getBytes(); + return cert.getSignatureValue().getOctets(); } public final void verify( @@ -180,7 +180,7 @@ public class X509V2AttributeCertificate throw new CertificateException("Signature algorithm in certificate info not same as outer certificate"); } - signature = Signature.getInstance(cert.getSignatureAlgorithm().getObjectId().getId(), provider); + signature = Signature.getInstance(cert.getSignatureAlgorithm().getAlgorithm().getId(), provider); signature.initVerify(key); diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java index d216295..c422cb2 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java @@ -24,7 +24,6 @@ import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.Certificate; @@ -45,7 +44,7 @@ import org.bouncycastle.x509.extension.X509ExtensionUtil; public class X509V3CertificateGenerator { private V3TBSCertificateGenerator tbsGen; - private DERObjectIdentifier sigOID; + private ASN1ObjectIdentifier sigOID; private AlgorithmIdentifier sigAlgId; private String signatureAlgorithm; private X509ExtensionsGenerator extGenerator; @@ -228,14 +227,14 @@ public class X509V3CertificateGenerator boolean critical, ASN1Encodable value) { - this.addExtension(new DERObjectIdentifier(oid), critical, value); + this.addExtension(new ASN1ObjectIdentifier(oid), critical, value); } /** * add a given extension field for the standard extensions tag (tag 3) */ public void addExtension( - DERObjectIdentifier oid, + ASN1ObjectIdentifier oid, boolean critical, ASN1Encodable value) { @@ -252,14 +251,14 @@ public class X509V3CertificateGenerator boolean critical, byte[] value) { - this.addExtension(new DERObjectIdentifier(oid), critical, value); + this.addExtension(new ASN1ObjectIdentifier(oid), critical, value); } /** * add a given extension field for the standard extensions tag (tag 3) */ public void addExtension( - DERObjectIdentifier oid, + ASN1ObjectIdentifier oid, boolean critical, byte[] value) { @@ -302,7 +301,7 @@ public class X509V3CertificateGenerator * @throws CertificateParsingException if the extension cannot be extracted. */ public void copyAndAddExtension( - DERObjectIdentifier oid, + ASN1ObjectIdentifier oid, boolean critical, X509Certificate cert) throws CertificateParsingException diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java index 2164d1f..bcd5993 100644 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java +++ b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java @@ -6,7 +6,6 @@ import java.security.PublicKey; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; -import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; @@ -15,7 +14,6 @@ import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.X509Extension; -import org.bouncycastle.asn1.x509.X509Extensions; import org.bouncycastle.jce.PrincipalUtil; /** @@ -70,32 +68,30 @@ public class AuthorityKeyIdentifierStructure if (certificate.getVersion() != 3) { GeneralName genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate)); - SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( - (ASN1Sequence)new ASN1InputStream(certificate.getPublicKey().getEncoded()).readObject()); + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(certificate.getPublicKey().getEncoded()); return (ASN1Sequence)new AuthorityKeyIdentifier( - info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object(); + info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Primitive(); } else { GeneralName genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate)); - byte[] ext = certificate.getExtensionValue(X509Extensions.SubjectKeyIdentifier.getId()); + byte[] ext = certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId()); if (ext != null) { ASN1OctetString str = (ASN1OctetString)X509ExtensionUtil.fromExtensionValue(ext); return (ASN1Sequence)new AuthorityKeyIdentifier( - str.getOctets(), new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object(); + str.getOctets(), new GeneralNames(genName), certificate.getSerialNumber()).toASN1Primitive(); } else { - SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( - (ASN1Sequence)new ASN1InputStream(certificate.getPublicKey().getEncoded()).readObject()); + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(certificate.getPublicKey().getEncoded()); return (ASN1Sequence)new AuthorityKeyIdentifier( - info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object(); + info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Primitive(); } } } @@ -111,10 +107,9 @@ public class AuthorityKeyIdentifierStructure { try { - SubjectPublicKeyInfo info = new SubjectPublicKeyInfo( - (ASN1Sequence)new ASN1InputStream(pubKey.getEncoded()).readObject()); + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()); - return (ASN1Sequence)new AuthorityKeyIdentifier(info).toASN1Object(); + return (ASN1Sequence)new AuthorityKeyIdentifier(info).toASN1Primitive(); } catch (Exception e) { diff --git a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java b/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java deleted file mode 100644 index 2c7afd3..0000000 --- a/bouncycastle/bcprov/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.bouncycastle.x509.extension; - -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.PublicKey; - -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; - -/** - * A high level subject key identifier. - * @deprecated use JcaX509ExtensionUtils andSubjectKeyIdentifier.getInstance() - */ -public class SubjectKeyIdentifierStructure - extends SubjectKeyIdentifier -{ - /** - * Constructor which will take the byte[] returned from getExtensionValue() - * - * @param encodedValue a DER octet encoded string with the extension structure in it. - * @throws IOException on parsing errors. - */ - public SubjectKeyIdentifierStructure( - byte[] encodedValue) - throws IOException - { - super((ASN1OctetString)X509ExtensionUtil.fromExtensionValue(encodedValue)); - } - - private static ASN1OctetString fromPublicKey( - PublicKey pubKey) - throws InvalidKeyException - { - try - { - SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()); - - return (ASN1OctetString)(new SubjectKeyIdentifier(info).toASN1Object()); - } - catch (Exception e) - { - throw new InvalidKeyException("Exception extracting key details: " + e.toString()); - } - } - - public SubjectKeyIdentifierStructure( - PublicKey pubKey) - throws InvalidKeyException - { - super(fromPublicKey(pubKey)); - } -} diff --git a/build.gradle b/build.gradle index 84bcd5c..7d0354c 100644 --- a/build.gradle +++ b/build.gradle @@ -31,19 +31,6 @@ model { } } } - - components { - libmincrypt(NativeLibrarySpec) { - binaries.all { - } - } - mkbootimg(NativeExecutableSpec) { - binaries.all { - cCompiler.args '-std=c11' - lib library: "libmincrypt", linkage: 'static' - } - } - } } @@ -127,14 +114,14 @@ task pack_ramdisk_and_gz { Task task -> } pack_ramdisk_and_gz.dependsOn('mkbootfsExecutable') -task pack_clear(type: Exec, dependsOn: [pack_ramdisk_and_gz, 'mkbootimgExecutable']) { +task pack_clear(type: Exec, dependsOn: [pack_ramdisk_and_gz]) { def theCmdLine = getRamdiskConfig(workdir, 'cmdline') if (gDebug) { theCmdLine = "androidboot.selinux=disabled " + theCmdLine } def theBaseAddr = getBaseAddress(workdir) workingDir '.' - executable 'build/exe/mkbootimg/mkbootimg' + executable 'src/mkbootimg/mkbootimg' args = [ '--kernel', workdir + "/kernel", '--ramdisk', workdir + "/ramdisk.img.gz", diff --git a/security/README b/security/README index 24f984c..15f2e93 100644 --- a/security/README +++ b/security/README @@ -1,3 +1,14 @@ +For detailed information on key types and image signing, please see: + +https://source.android.com/devices/tech/ota/sign_builds.html + +The test keys in this directory are used in development only and should +NEVER be used to sign packages in publicly released images (as that would +open a major security hole). + +key generation +-------------- + The following commands were used to generate the test key pairs: development/tools/make_key testkey '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com' @@ -5,18 +16,6 @@ The following commands were used to generate the test key pairs: development/tools/make_key shared '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com' development/tools/make_key media '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com' -The following standard test keys are currently included: - -testkey -- a generic key for packages that do not otherwise specify a key. -platform -- a test key for packages that are part of the core platform. -shared -- a test key for things that are shared in the home/contacts process. -media -- a test key for packages that are part of the media/download system. - -These test keys are used strictly in development, and should never be assumed -to convey any sort of validity. When $BUILD_SECURE=true, the code should not -honor these keys in any context. - - signing using the openssl commandline (for boot/system images) -------------------------------------------------------------- @@ -28,7 +27,12 @@ signing using the openssl commandline (for boot/system images) extracting public keys for embedding ------------------------------------ -it's a Java tool -but it generates C code -take a look at commands/recovery/Android.mk -you'll see it running $(HOST_OUT_JAVA_LIBRARIES)/dumpkey.jar + +dumpkey.jar is a Java tool that takes an x.509 certificate in PEM format as +input and prints a C structure to standard output: + + $ java -jar out/host/linux-x86/framework/dumpkey.jar build/target/product/security/testkey.x509.pem + {64,0xc926ad21,{1795090719,2141396315,950055447,2581568430,4268923165,1920809988,546586521,3498997798,1776797858,3740060814,1805317999,1429410244,129622599,1422441418,1783893377,1222374759,2563319927,323993566,28517732,609753416,1826472888,215237850,4261642700,4049082591,3228462402,774857746,154822455,2497198897,2758199418,3019015328,2794777644,87251430,2534927978,120774784,571297800,3695899472,2479925187,3811625450,3401832990,2394869647,3267246207,950095497,555058928,414729973,1136544882,3044590084,465547824,4058146728,2731796054,1689838846,3890756939,1048029507,895090649,247140249,178744550,3547885223,3165179243,109881576,3944604415,1044303212,3772373029,2985150306,3737520932,3599964420},{3437017481,3784475129,2800224972,3086222688,251333580,2131931323,512774938,325948880,2657486437,2102694287,3820568226,792812816,1026422502,2053275343,2800889200,3113586810,165549746,4273519969,4065247892,1902789247,772932719,3941848426,3652744109,216871947,3164400649,1942378755,3996765851,1055777370,964047799,629391717,2232744317,3910558992,191868569,2758883837,3682816752,2997714732,2702529250,3570700455,3776873832,3924067546,3555689545,2758825434,1323144535,61311905,1997411085,376844204,213777604,4077323584,9135381,1625809335,2804742137,2952293945,1117190829,4237312782,1825108855,3013147971,1111251351,2568837572,1684324211,2520978805,367251975,810756730,2353784344,1175080310}} + +This is called by build/core/Makefile to incorporate the OTA signing keys +into the recovery image. diff --git a/src/libmincrypt/c/dsa_sig.c b/src/libmincrypt/c/dsa_sig.c deleted file mode 100644 index 101314b..0000000 --- a/src/libmincrypt/c/dsa_sig.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include "mincrypt/dsa_sig.h" -#include "mincrypt/p256.h" - -/** - * Trims off the leading zero bytes and copy it to a buffer aligning it to the end. - */ -static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src, - int src_len) { - int dst_offset; - while (*src == '\0' && src_len > 0) { - src++; - src_len--; - } - if (src_len > P256_NBYTES || src_len < 1) { - return 0; - } - dst_offset = P256_NBYTES - src_len; - memset(dst, 0, dst_offset); - memcpy(dst + dst_offset, src, src_len); - return 1; -} - -/** - * Unpacks the ASN.1 DSA signature sequence. - */ -int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) { - /* - * Structure is: - * 0x30 0xNN SEQUENCE + s_length - * 0x02 0xNN INTEGER + r_length - * 0xAA 0xBB .. r_length bytes of "r" (offset 4) - * 0x02 0xNN INTEGER + s_length - * 0xMM 0xNN .. s_length bytes of "s" (offset 6 + r_len) - */ - int seq_len; - unsigned char r_bytes[P256_NBYTES]; - unsigned char s_bytes[P256_NBYTES]; - int r_len; - int s_len; - - memset(r_bytes, 0, sizeof(r_bytes)); - memset(s_bytes, 0, sizeof(s_bytes)); - - /* - * Must have at least: - * 2 bytes sequence header and length - * 2 bytes R integer header and length - * 1 byte of R - * 2 bytes S integer header and length - * 1 byte of S - * - * 8 bytes total - */ - if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) { - return 0; - } - - seq_len = sig[1]; - if ((seq_len <= 0) || (seq_len + 2 != sig_len)) { - return 0; - } - - r_len = sig[3]; - /* - * Must have at least: - * 2 bytes for R header and length - * 2 bytes S integer header and length - * 1 byte of S - */ - if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) { - return 0; - } - s_len = sig[5 + r_len]; - - /** - * Must have: - * 2 bytes for R header and length - * r_len bytes for R - * 2 bytes S integer header and length - */ - if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) { - return 0; - } - - /* - * ASN.1 encoded integers are zero-padded for positive integers. Make sure we have - * a correctly-sized buffer and that the resulting integer isn't too large. - */ - if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len) - || !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) { - return 0; - } - - p256_from_bin(r_bytes, r_int); - p256_from_bin(s_bytes, s_int); - - return 1; -} diff --git a/src/libmincrypt/c/p256.c b/src/libmincrypt/c/p256.c deleted file mode 100644 index 555a07a..0000000 --- a/src/libmincrypt/c/p256.c +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// This is an implementation of the P256 elliptic curve group. It's written to -// be portable 32-bit, although it's still constant-time. -// -// WARNING: Implementing these functions in a constant-time manner is far from -// obvious. Be careful when touching this code. -// -// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. - -#include -#include -#include -#include - -#include "mincrypt/p256.h" - -const p256_int SECP256r1_n = // curve order - {{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}}; - -const p256_int SECP256r1_p = // curve field size - {{-1, -1, -1, 0, 0, 0, 1, -1 }}; - -const p256_int SECP256r1_b = // curve b - {{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0, - 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}}; - -void p256_init(p256_int* a) { - memset(a, 0, sizeof(*a)); -} - -void p256_clear(p256_int* a) { p256_init(a); } - -int p256_get_bit(const p256_int* scalar, int bit) { - return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT) - >> (bit & (P256_BITSPERDIGIT - 1))) & 1; -} - -int p256_is_zero(const p256_int* a) { - int i, result = 0; - for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i); - return !result; -} - -// top, c[] += a[] * b -// Returns new top -static p256_digit mulAdd(const p256_int* a, - p256_digit b, - p256_digit top, - p256_digit* c) { - int i; - p256_ddigit carry = 0; - - for (i = 0; i < P256_NDIGITS; ++i) { - carry += *c; - carry += (p256_ddigit)P256_DIGIT(a, i) * b; - *c++ = (p256_digit)carry; - carry >>= P256_BITSPERDIGIT; - } - return top + (p256_digit)carry; -} - -// top, c[] -= top_a, a[] -static p256_digit subTop(p256_digit top_a, - const p256_digit* a, - p256_digit top_c, - p256_digit* c) { - int i; - p256_sddigit borrow = 0; - - for (i = 0; i < P256_NDIGITS; ++i) { - borrow += *c; - borrow -= *a++; - *c++ = (p256_digit)borrow; - borrow >>= P256_BITSPERDIGIT; - } - borrow += top_c; - borrow -= top_a; - top_c = (p256_digit)borrow; - assert((borrow >> P256_BITSPERDIGIT) == 0); - return top_c; -} - -// top, c[] -= MOD[] & mask (0 or -1) -// returns new top. -static p256_digit subM(const p256_int* MOD, - p256_digit top, - p256_digit* c, - p256_digit mask) { - int i; - p256_sddigit borrow = 0; - for (i = 0; i < P256_NDIGITS; ++i) { - borrow += *c; - borrow -= P256_DIGIT(MOD, i) & mask; - *c++ = (p256_digit)borrow; - borrow >>= P256_BITSPERDIGIT; - } - return top + (p256_digit)borrow; -} - -// top, c[] += MOD[] & mask (0 or -1) -// returns new top. -static p256_digit addM(const p256_int* MOD, - p256_digit top, - p256_digit* c, - p256_digit mask) { - int i; - p256_ddigit carry = 0; - for (i = 0; i < P256_NDIGITS; ++i) { - carry += *c; - carry += P256_DIGIT(MOD, i) & mask; - *c++ = (p256_digit)carry; - carry >>= P256_BITSPERDIGIT; - } - return top + (p256_digit)carry; -} - -// c = a * b mod MOD. c can be a and/or b. -void p256_modmul(const p256_int* MOD, - const p256_int* a, - const p256_digit top_b, - const p256_int* b, - p256_int* c) { - p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 }; - p256_digit top = 0; - int i; - - // Multiply/add into tmp. - for (i = 0; i < P256_NDIGITS; ++i) { - if (i) tmp[i + P256_NDIGITS - 1] = top; - top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i); - } - - // Multiply/add top digit - tmp[i + P256_NDIGITS - 1] = top; - top = mulAdd(a, top_b, 0, tmp + i); - - // Reduce tmp, digit by digit. - for (; i >= 0; --i) { - p256_digit reducer[P256_NDIGITS] = { 0 }; - p256_digit top_reducer; - - // top can be any value at this point. - // Guestimate reducer as top * MOD, since msw of MOD is -1. - top_reducer = mulAdd(MOD, top, 0, reducer); - - // Subtract reducer from top | tmp. - top = subTop(top_reducer, reducer, top, tmp + i); - - // top is now either 0 or 1. Make it 0, fixed-timing. - assert(top <= 1); - - top = subM(MOD, top, tmp + i, ~(top - 1)); - - assert(top == 0); - - // We have now reduced the top digit off tmp. Fetch new top digit. - top = tmp[i + P256_NDIGITS - 1]; - } - - // tmp might still be larger than MOD, yet same bit length. - // Make sure it is less, fixed-timing. - addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1)); - - memcpy(c, tmp, P256_NBYTES); -} -int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; } -int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); } - -p256_digit p256_shl(const p256_int* a, int n, p256_int* b) { - int i; - p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1); - - n %= P256_BITSPERDIGIT; - for (i = P256_NDIGITS - 1; i > 0; --i) { - p256_digit accu = (P256_DIGIT(a, i) << n); - accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n)); - P256_DIGIT(b, i) = accu; - } - P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n); - - top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT); - - return top; -} - -void p256_shr(const p256_int* a, int n, p256_int* b) { - int i; - - n %= P256_BITSPERDIGIT; - for (i = 0; i < P256_NDIGITS - 1; ++i) { - p256_digit accu = (P256_DIGIT(a, i) >> n); - accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n)); - P256_DIGIT(b, i) = accu; - } - P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n); -} - -static void p256_shr1(const p256_int* a, int highbit, p256_int* b) { - int i; - - for (i = 0; i < P256_NDIGITS - 1; ++i) { - p256_digit accu = (P256_DIGIT(a, i) >> 1); - accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1)); - P256_DIGIT(b, i) = accu; - } - P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) | - (highbit << (P256_BITSPERDIGIT - 1)); -} - -// Return -1, 0, 1 for a < b, a == b or a > b respectively. -int p256_cmp(const p256_int* a, const p256_int* b) { - int i; - p256_sddigit borrow = 0; - p256_digit notzero = 0; - - for (i = 0; i < P256_NDIGITS; ++i) { - borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i); - // Track whether any result digit is ever not zero. - // Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1. - notzero |= !!((p256_digit)borrow); - borrow >>= P256_BITSPERDIGIT; - } - return (int)borrow | notzero; -} - -// c = a - b. Returns borrow: 0 or -1. -int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) { - int i; - p256_sddigit borrow = 0; - - for (i = 0; i < P256_NDIGITS; ++i) { - borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i); - if (c) P256_DIGIT(c, i) = (p256_digit)borrow; - borrow >>= P256_BITSPERDIGIT; - } - return (int)borrow; -} - -// c = a + b. Returns carry: 0 or 1. -int p256_add(const p256_int* a, const p256_int* b, p256_int* c) { - int i; - p256_ddigit carry = 0; - - for (i = 0; i < P256_NDIGITS; ++i) { - carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i); - if (c) P256_DIGIT(c, i) = (p256_digit)carry; - carry >>= P256_BITSPERDIGIT; - } - return (int)carry; -} - -// b = a + d. Returns carry, 0 or 1. -int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) { - int i; - p256_ddigit carry = d; - - for (i = 0; i < P256_NDIGITS; ++i) { - carry += (p256_ddigit)P256_DIGIT(a, i); - if (b) P256_DIGIT(b, i) = (p256_digit)carry; - carry >>= P256_BITSPERDIGIT; - } - return (int)carry; -} - -// b = 1/a mod MOD, binary euclid. -void p256_modinv_vartime(const p256_int* MOD, - const p256_int* a, - p256_int* b) { - p256_int R = P256_ZERO; - p256_int S = P256_ONE; - p256_int U = *MOD; - p256_int V = *a; - - for (;;) { - if (p256_is_even(&U)) { - p256_shr1(&U, 0, &U); - if (p256_is_even(&R)) { - p256_shr1(&R, 0, &R); - } else { - // R = (R+MOD)/2 - p256_shr1(&R, p256_add(&R, MOD, &R), &R); - } - } else if (p256_is_even(&V)) { - p256_shr1(&V, 0, &V); - if (p256_is_even(&S)) { - p256_shr1(&S, 0, &S); - } else { - // S = (S+MOD)/2 - p256_shr1(&S, p256_add(&S, MOD, &S) , &S); - } - } else { // U,V both odd. - if (!p256_sub(&V, &U, NULL)) { - p256_sub(&V, &U, &V); - if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S); - if (p256_is_zero(&V)) break; // done. - } else { - p256_sub(&U, &V, &U); - if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R); - } - } - } - - p256_mod(MOD, &R, b); -} - -void p256_mod(const p256_int* MOD, - const p256_int* in, - p256_int* out) { - if (out != in) *out = *in; - addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1)); -} - -// Verify y^2 == x^3 - 3x + b mod p -// and 0 < x < p and 0 < y < p -int p256_is_valid_point(const p256_int* x, const p256_int* y) { - p256_int y2, x3; - - if (p256_cmp(&SECP256r1_p, x) <= 0 || - p256_cmp(&SECP256r1_p, y) <= 0 || - p256_is_zero(x) || - p256_is_zero(y)) return 0; - - p256_modmul(&SECP256r1_p, y, 0, y, &y2); // y^2 - - p256_modmul(&SECP256r1_p, x, 0, x, &x3); // x^2 - p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); // x^3 - if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - x - if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 2x - if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 3x - if (p256_add(&x3, &SECP256r1_b, &x3)) // x^3 - 3x + b - p256_sub(&x3, &SECP256r1_p, &x3); - - return p256_cmp(&y2, &x3) == 0; -} - -void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) { - int i; - const uint8_t* p = &src[0]; - - for (i = P256_NDIGITS - 1; i >= 0; --i) { - P256_DIGIT(dst, i) = - (p[0] << 24) | - (p[1] << 16) | - (p[2] << 8) | - p[3]; - p += 4; - } -} diff --git a/src/libmincrypt/c/p256_ec.c b/src/libmincrypt/c/p256_ec.c deleted file mode 100644 index 90262cc..0000000 --- a/src/libmincrypt/c/p256_ec.c +++ /dev/null @@ -1,1279 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -// This is an implementation of the P256 elliptic curve group. It's written to -// be portable 32-bit, although it's still constant-time. -// -// WARNING: Implementing these functions in a constant-time manner is far from -// obvious. Be careful when touching this code. -// -// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. - -#include -#include - -#include -#include - -#include "mincrypt/p256.h" - -typedef uint8_t u8; -typedef uint32_t u32; -typedef int32_t s32; -typedef uint64_t u64; - -/* Our field elements are represented as nine 32-bit limbs. - * - * The value of an felem (field element) is: - * x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228) - * - * That is, each limb is alternately 29 or 28-bits wide in little-endian - * order. - * - * This means that an felem hits 2**257, rather than 2**256 as we would like. A - * 28, 29, ... pattern would cause us to hit 2**256, but that causes problems - * when multiplying as terms end up one bit short of a limb which would require - * much bit-shifting to correct. - * - * Finally, the values stored in an felem are in Montgomery form. So the value - * |y| is stored as (y*R) mod p, where p is the P-256 prime and R is 2**257. - */ -typedef u32 limb; -#define NLIMBS 9 -typedef limb felem[NLIMBS]; - -static const limb kBottom28Bits = 0xfffffff; -static const limb kBottom29Bits = 0x1fffffff; - -/* kOne is the number 1 as an felem. It's 2**257 mod p split up into 29 and - * 28-bit words. */ -static const felem kOne = { - 2, 0, 0, 0xffff800, - 0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff, - 0 -}; -static const felem kZero = {0}; -static const felem kP = { - 0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff, - 0, 0, 0x200000, 0xf000000, - 0xfffffff -}; -static const felem k2P = { - 0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff, - 0, 0, 0x400000, 0xe000000, - 0x1fffffff -}; -/* kPrecomputed contains precomputed values to aid the calculation of scalar - * multiples of the base point, G. It's actually two, equal length, tables - * concatenated. - * - * The first table contains (x,y) felem pairs for 16 multiples of the base - * point, G. - * - * Index | Index (binary) | Value - * 0 | 0000 | 0G (all zeros, omitted) - * 1 | 0001 | G - * 2 | 0010 | 2**64G - * 3 | 0011 | 2**64G + G - * 4 | 0100 | 2**128G - * 5 | 0101 | 2**128G + G - * 6 | 0110 | 2**128G + 2**64G - * 7 | 0111 | 2**128G + 2**64G + G - * 8 | 1000 | 2**192G - * 9 | 1001 | 2**192G + G - * 10 | 1010 | 2**192G + 2**64G - * 11 | 1011 | 2**192G + 2**64G + G - * 12 | 1100 | 2**192G + 2**128G - * 13 | 1101 | 2**192G + 2**128G + G - * 14 | 1110 | 2**192G + 2**128G + 2**64G - * 15 | 1111 | 2**192G + 2**128G + 2**64G + G - * - * The second table follows the same style, but the terms are 2**32G, - * 2**96G, 2**160G, 2**224G. - * - * This is ~2KB of data. */ -static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = { - 0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee, - 0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3, - 0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c, - 0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22, - 0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050, - 0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b, - 0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa, - 0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2, - 0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609, - 0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581, - 0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca, - 0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33, - 0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6, - 0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd, - 0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0, - 0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881, - 0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a, - 0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26, - 0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b, - 0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023, - 0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133, - 0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa, - 0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29, - 0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc, - 0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8, - 0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59, - 0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39, - 0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689, - 0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa, - 0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3, - 0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1, - 0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f, - 0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72, - 0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d, - 0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b, - 0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a, - 0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a, - 0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f, - 0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb, - 0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc, - 0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9, - 0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce, - 0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2, - 0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca, - 0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229, - 0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57, - 0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c, - 0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa, - 0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651, - 0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec, - 0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7, - 0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c, - 0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927, - 0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298, - 0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8, - 0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2, - 0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d, - 0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4, - 0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8, - 0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78, -}; - - -/* Field element operations: */ - -/* NON_ZERO_TO_ALL_ONES returns: - * 0xffffffff for 0 < x <= 2**31 - * 0 for x == 0 or x > 2**31. - * - * x must be a u32 or an equivalent type such as limb. */ -#define NON_ZERO_TO_ALL_ONES(x) ((((u32)(x) - 1) >> 31) - 1) - -/* felem_reduce_carry adds a multiple of p in order to cancel |carry|, - * which is a term at 2**257. - * - * On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28. - * On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. */ -static void felem_reduce_carry(felem inout, limb carry) { - const u32 carry_mask = NON_ZERO_TO_ALL_ONES(carry); - - inout[0] += carry << 1; - inout[3] += 0x10000000 & carry_mask; - /* carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the - * previous line therefore this doesn't underflow. */ - inout[3] -= carry << 11; - inout[4] += (0x20000000 - 1) & carry_mask; - inout[5] += (0x10000000 - 1) & carry_mask; - inout[6] += (0x20000000 - 1) & carry_mask; - inout[6] -= carry << 22; - /* This may underflow if carry is non-zero but, if so, we'll fix it in the - * next line. */ - inout[7] -= 1 & carry_mask; - inout[7] += carry << 25; -} - -/* felem_sum sets out = in+in2. - * - * On entry, in[i]+in2[i] must not overflow a 32-bit word. - * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */ -static void felem_sum(felem out, const felem in, const felem in2) { - limb carry = 0; - unsigned i; - - for (i = 0;; i++) { - out[i] = in[i] + in2[i]; - out[i] += carry; - carry = out[i] >> 29; - out[i] &= kBottom29Bits; - - i++; - if (i == NLIMBS) - break; - - out[i] = in[i] + in2[i]; - out[i] += carry; - carry = out[i] >> 28; - out[i] &= kBottom28Bits; - } - - felem_reduce_carry(out, carry); -} - -#define two31m3 (((limb)1) << 31) - (((limb)1) << 3) -#define two30m2 (((limb)1) << 30) - (((limb)1) << 2) -#define two30p13m2 (((limb)1) << 30) + (((limb)1) << 13) - (((limb)1) << 2) -#define two31m2 (((limb)1) << 31) - (((limb)1) << 2) -#define two31p24m2 (((limb)1) << 31) + (((limb)1) << 24) - (((limb)1) << 2) -#define two30m27m2 (((limb)1) << 30) - (((limb)1) << 27) - (((limb)1) << 2) - -/* zero31 is 0 mod p. */ -static const felem zero31 = { two31m3, two30m2, two31m2, two30p13m2, two31m2, two30m2, two31p24m2, two30m27m2, two31m2 }; - -/* felem_diff sets out = in-in2. - * - * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and - * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29. - * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ -static void felem_diff(felem out, const felem in, const felem in2) { - limb carry = 0; - unsigned i; - - for (i = 0;; i++) { - out[i] = in[i] - in2[i]; - out[i] += zero31[i]; - out[i] += carry; - carry = out[i] >> 29; - out[i] &= kBottom29Bits; - - i++; - if (i == NLIMBS) - break; - - out[i] = in[i] - in2[i]; - out[i] += zero31[i]; - out[i] += carry; - carry = out[i] >> 28; - out[i] &= kBottom28Bits; - } - - felem_reduce_carry(out, carry); -} - -/* felem_reduce_degree sets out = tmp/R mod p where tmp contains 64-bit words - * with the same 29,28,... bit positions as an felem. - * - * The values in felems are in Montgomery form: x*R mod p where R = 2**257. - * Since we just multiplied two Montgomery values together, the result is - * x*y*R*R mod p. We wish to divide by R in order for the result also to be - * in Montgomery form. - * - * On entry: tmp[i] < 2**64 - * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */ -static void felem_reduce_degree(felem out, u64 tmp[17]) { - /* The following table may be helpful when reading this code: - * - * Limb number: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10... - * Width (bits): 29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29 - * Start bit: 0 | 29| 57| 86|114|143|171|200|228|257|285 - * (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 */ - limb tmp2[18], carry, x, xMask; - unsigned i; - - /* tmp contains 64-bit words with the same 29,28,29-bit positions as an - * felem. So the top of an element of tmp might overlap with another - * element two positions down. The following loop eliminates this - * overlap. */ - tmp2[0] = (limb)(tmp[0] & kBottom29Bits); - - /* In the following we use "(limb) tmp[x]" and "(limb) (tmp[x]>>32)" to try - * and hint to the compiler that it can do a single-word shift by selecting - * the right register rather than doing a double-word shift and truncating - * afterwards. */ - tmp2[1] = ((limb) tmp[0]) >> 29; - tmp2[1] |= (((limb)(tmp[0] >> 32)) << 3) & kBottom28Bits; - tmp2[1] += ((limb) tmp[1]) & kBottom28Bits; - carry = tmp2[1] >> 28; - tmp2[1] &= kBottom28Bits; - - for (i = 2; i < 17; i++) { - tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25; - tmp2[i] += ((limb)(tmp[i - 1])) >> 28; - tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 4) & kBottom29Bits; - tmp2[i] += ((limb) tmp[i]) & kBottom29Bits; - tmp2[i] += carry; - carry = tmp2[i] >> 29; - tmp2[i] &= kBottom29Bits; - - i++; - if (i == 17) - break; - tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25; - tmp2[i] += ((limb)(tmp[i - 1])) >> 29; - tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 3) & kBottom28Bits; - tmp2[i] += ((limb) tmp[i]) & kBottom28Bits; - tmp2[i] += carry; - carry = tmp2[i] >> 28; - tmp2[i] &= kBottom28Bits; - } - - tmp2[17] = ((limb)(tmp[15] >> 32)) >> 25; - tmp2[17] += ((limb)(tmp[16])) >> 29; - tmp2[17] += (((limb)(tmp[16] >> 32)) << 3); - tmp2[17] += carry; - - /* Montgomery elimination of terms. - * - * Since R is 2**257, we can divide by R with a bitwise shift if we can - * ensure that the right-most 257 bits are all zero. We can make that true by - * adding multiplies of p without affecting the value. - * - * So we eliminate limbs from right to left. Since the bottom 29 bits of p - * are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0. - * We can do that for 8 further limbs and then right shift to eliminate the - * extra factor of R. */ - for (i = 0;; i += 2) { - tmp2[i + 1] += tmp2[i] >> 29; - x = tmp2[i] & kBottom29Bits; - xMask = NON_ZERO_TO_ALL_ONES(x); - tmp2[i] = 0; - - /* The bounds calculations for this loop are tricky. Each iteration of - * the loop eliminates two words by adding values to words to their - * right. - * - * The following table contains the amounts added to each word (as an - * offset from the value of i at the top of the loop). The amounts are - * accounted for from the first and second half of the loop separately - * and are written as, for example, 28 to mean a value <2**28. - * - * Word: 3 4 5 6 7 8 9 10 - * Added in top half: 28 11 29 21 29 28 - * 28 29 - * 29 - * Added in bottom half: 29 10 28 21 28 28 - * 29 - * - * The value that is currently offset 7 will be offset 5 for the next - * iteration and then offset 3 for the iteration after that. Therefore - * the total value added will be the values added at 7, 5 and 3. - * - * The following table accumulates these values. The sums at the bottom - * are written as, for example, 29+28, to mean a value < 2**29+2**28. - * - * Word: 3 4 5 6 7 8 9 10 11 12 13 - * 28 11 10 29 21 29 28 28 28 28 28 - * 29 28 11 28 29 28 29 28 29 28 - * 29 28 21 21 29 21 29 21 - * 10 29 28 21 28 21 28 - * 28 29 28 29 28 29 28 - * 11 10 29 10 29 10 - * 29 28 11 28 11 - * 29 29 - * -------------------------------------------- - * 30+ 31+ 30+ 31+ 30+ - * 28+ 29+ 28+ 29+ 21+ - * 21+ 28+ 21+ 28+ 10 - * 10 21+ 10 21+ - * 11 11 - * - * So the greatest amount is added to tmp2[10] and tmp2[12]. If - * tmp2[10/12] has an initial value of <2**29, then the maximum value - * will be < 2**31 + 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32, - * as required. */ - tmp2[i + 3] += (x << 10) & kBottom28Bits; - tmp2[i + 4] += (x >> 18); - - tmp2[i + 6] += (x << 21) & kBottom29Bits; - tmp2[i + 7] += x >> 8; - - /* At position 200, which is the starting bit position for word 7, we - * have a factor of 0xf000000 = 2**28 - 2**24. */ - tmp2[i + 7] += 0x10000000 & xMask; - /* Word 7 is 28 bits wide, so the 2**28 term exactly hits word 8. */ - tmp2[i + 8] += (x - 1) & xMask; - tmp2[i + 7] -= (x << 24) & kBottom28Bits; - tmp2[i + 8] -= x >> 4; - - tmp2[i + 8] += 0x20000000 & xMask; - tmp2[i + 8] -= x; - tmp2[i + 8] += (x << 28) & kBottom29Bits; - tmp2[i + 9] += ((x >> 1) - 1) & xMask; - - if (i+1 == NLIMBS) - break; - tmp2[i + 2] += tmp2[i + 1] >> 28; - x = tmp2[i + 1] & kBottom28Bits; - xMask = NON_ZERO_TO_ALL_ONES(x); - tmp2[i + 1] = 0; - - tmp2[i + 4] += (x << 11) & kBottom29Bits; - tmp2[i + 5] += (x >> 18); - - tmp2[i + 7] += (x << 21) & kBottom28Bits; - tmp2[i + 8] += x >> 7; - - /* At position 199, which is the starting bit of the 8th word when - * dealing with a context starting on an odd word, we have a factor of - * 0x1e000000 = 2**29 - 2**25. Since we have not updated i, the 8th - * word from i+1 is i+8. */ - tmp2[i + 8] += 0x20000000 & xMask; - tmp2[i + 9] += (x - 1) & xMask; - tmp2[i + 8] -= (x << 25) & kBottom29Bits; - tmp2[i + 9] -= x >> 4; - - tmp2[i + 9] += 0x10000000 & xMask; - tmp2[i + 9] -= x; - tmp2[i + 10] += (x - 1) & xMask; - } - - /* We merge the right shift with a carry chain. The words above 2**257 have - * widths of 28,29,... which we need to correct when copying them down. */ - carry = 0; - for (i = 0; i < 8; i++) { - /* The maximum value of tmp2[i + 9] occurs on the first iteration and - * is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is - * therefore safe. */ - out[i] = tmp2[i + 9]; - out[i] += carry; - out[i] += (tmp2[i + 10] << 28) & kBottom29Bits; - carry = out[i] >> 29; - out[i] &= kBottom29Bits; - - i++; - out[i] = tmp2[i + 9] >> 1; - out[i] += carry; - carry = out[i] >> 28; - out[i] &= kBottom28Bits; - } - - out[8] = tmp2[17]; - out[8] += carry; - carry = out[8] >> 29; - out[8] &= kBottom29Bits; - - felem_reduce_carry(out, carry); -} - -/* felem_square sets out=in*in. - * - * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29. - * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ -static void felem_square(felem out, const felem in) { - u64 tmp[17]; - - tmp[0] = ((u64) in[0]) * in[0]; - tmp[1] = ((u64) in[0]) * (in[1] << 1); - tmp[2] = ((u64) in[0]) * (in[2] << 1) + - ((u64) in[1]) * (in[1] << 1); - tmp[3] = ((u64) in[0]) * (in[3] << 1) + - ((u64) in[1]) * (in[2] << 1); - tmp[4] = ((u64) in[0]) * (in[4] << 1) + - ((u64) in[1]) * (in[3] << 2) + ((u64) in[2]) * in[2]; - tmp[5] = ((u64) in[0]) * (in[5] << 1) + ((u64) in[1]) * - (in[4] << 1) + ((u64) in[2]) * (in[3] << 1); - tmp[6] = ((u64) in[0]) * (in[6] << 1) + ((u64) in[1]) * - (in[5] << 2) + ((u64) in[2]) * (in[4] << 1) + - ((u64) in[3]) * (in[3] << 1); - tmp[7] = ((u64) in[0]) * (in[7] << 1) + ((u64) in[1]) * - (in[6] << 1) + ((u64) in[2]) * (in[5] << 1) + - ((u64) in[3]) * (in[4] << 1); - /* tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60, - * which is < 2**64 as required. */ - tmp[8] = ((u64) in[0]) * (in[8] << 1) + ((u64) in[1]) * - (in[7] << 2) + ((u64) in[2]) * (in[6] << 1) + - ((u64) in[3]) * (in[5] << 2) + ((u64) in[4]) * in[4]; - tmp[9] = ((u64) in[1]) * (in[8] << 1) + ((u64) in[2]) * - (in[7] << 1) + ((u64) in[3]) * (in[6] << 1) + - ((u64) in[4]) * (in[5] << 1); - tmp[10] = ((u64) in[2]) * (in[8] << 1) + ((u64) in[3]) * - (in[7] << 2) + ((u64) in[4]) * (in[6] << 1) + - ((u64) in[5]) * (in[5] << 1); - tmp[11] = ((u64) in[3]) * (in[8] << 1) + ((u64) in[4]) * - (in[7] << 1) + ((u64) in[5]) * (in[6] << 1); - tmp[12] = ((u64) in[4]) * (in[8] << 1) + - ((u64) in[5]) * (in[7] << 2) + ((u64) in[6]) * in[6]; - tmp[13] = ((u64) in[5]) * (in[8] << 1) + - ((u64) in[6]) * (in[7] << 1); - tmp[14] = ((u64) in[6]) * (in[8] << 1) + - ((u64) in[7]) * (in[7] << 1); - tmp[15] = ((u64) in[7]) * (in[8] << 1); - tmp[16] = ((u64) in[8]) * in[8]; - - felem_reduce_degree(out, tmp); -} - -/* felem_mul sets out=in*in2. - * - * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and - * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29. - * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ -static void felem_mul(felem out, const felem in, const felem in2) { - u64 tmp[17]; - - tmp[0] = ((u64) in[0]) * in2[0]; - tmp[1] = ((u64) in[0]) * (in2[1] << 0) + - ((u64) in[1]) * (in2[0] << 0); - tmp[2] = ((u64) in[0]) * (in2[2] << 0) + ((u64) in[1]) * - (in2[1] << 1) + ((u64) in[2]) * (in2[0] << 0); - tmp[3] = ((u64) in[0]) * (in2[3] << 0) + ((u64) in[1]) * - (in2[2] << 0) + ((u64) in[2]) * (in2[1] << 0) + - ((u64) in[3]) * (in2[0] << 0); - tmp[4] = ((u64) in[0]) * (in2[4] << 0) + ((u64) in[1]) * - (in2[3] << 1) + ((u64) in[2]) * (in2[2] << 0) + - ((u64) in[3]) * (in2[1] << 1) + - ((u64) in[4]) * (in2[0] << 0); - tmp[5] = ((u64) in[0]) * (in2[5] << 0) + ((u64) in[1]) * - (in2[4] << 0) + ((u64) in[2]) * (in2[3] << 0) + - ((u64) in[3]) * (in2[2] << 0) + ((u64) in[4]) * - (in2[1] << 0) + ((u64) in[5]) * (in2[0] << 0); - tmp[6] = ((u64) in[0]) * (in2[6] << 0) + ((u64) in[1]) * - (in2[5] << 1) + ((u64) in[2]) * (in2[4] << 0) + - ((u64) in[3]) * (in2[3] << 1) + ((u64) in[4]) * - (in2[2] << 0) + ((u64) in[5]) * (in2[1] << 1) + - ((u64) in[6]) * (in2[0] << 0); - tmp[7] = ((u64) in[0]) * (in2[7] << 0) + ((u64) in[1]) * - (in2[6] << 0) + ((u64) in[2]) * (in2[5] << 0) + - ((u64) in[3]) * (in2[4] << 0) + ((u64) in[4]) * - (in2[3] << 0) + ((u64) in[5]) * (in2[2] << 0) + - ((u64) in[6]) * (in2[1] << 0) + - ((u64) in[7]) * (in2[0] << 0); - /* tmp[8] has the greatest value but doesn't overflow. See logic in - * felem_square. */ - tmp[8] = ((u64) in[0]) * (in2[8] << 0) + ((u64) in[1]) * - (in2[7] << 1) + ((u64) in[2]) * (in2[6] << 0) + - ((u64) in[3]) * (in2[5] << 1) + ((u64) in[4]) * - (in2[4] << 0) + ((u64) in[5]) * (in2[3] << 1) + - ((u64) in[6]) * (in2[2] << 0) + ((u64) in[7]) * - (in2[1] << 1) + ((u64) in[8]) * (in2[0] << 0); - tmp[9] = ((u64) in[1]) * (in2[8] << 0) + ((u64) in[2]) * - (in2[7] << 0) + ((u64) in[3]) * (in2[6] << 0) + - ((u64) in[4]) * (in2[5] << 0) + ((u64) in[5]) * - (in2[4] << 0) + ((u64) in[6]) * (in2[3] << 0) + - ((u64) in[7]) * (in2[2] << 0) + - ((u64) in[8]) * (in2[1] << 0); - tmp[10] = ((u64) in[2]) * (in2[8] << 0) + ((u64) in[3]) * - (in2[7] << 1) + ((u64) in[4]) * (in2[6] << 0) + - ((u64) in[5]) * (in2[5] << 1) + ((u64) in[6]) * - (in2[4] << 0) + ((u64) in[7]) * (in2[3] << 1) + - ((u64) in[8]) * (in2[2] << 0); - tmp[11] = ((u64) in[3]) * (in2[8] << 0) + ((u64) in[4]) * - (in2[7] << 0) + ((u64) in[5]) * (in2[6] << 0) + - ((u64) in[6]) * (in2[5] << 0) + ((u64) in[7]) * - (in2[4] << 0) + ((u64) in[8]) * (in2[3] << 0); - tmp[12] = ((u64) in[4]) * (in2[8] << 0) + ((u64) in[5]) * - (in2[7] << 1) + ((u64) in[6]) * (in2[6] << 0) + - ((u64) in[7]) * (in2[5] << 1) + - ((u64) in[8]) * (in2[4] << 0); - tmp[13] = ((u64) in[5]) * (in2[8] << 0) + ((u64) in[6]) * - (in2[7] << 0) + ((u64) in[7]) * (in2[6] << 0) + - ((u64) in[8]) * (in2[5] << 0); - tmp[14] = ((u64) in[6]) * (in2[8] << 0) + ((u64) in[7]) * - (in2[7] << 1) + ((u64) in[8]) * (in2[6] << 0); - tmp[15] = ((u64) in[7]) * (in2[8] << 0) + - ((u64) in[8]) * (in2[7] << 0); - tmp[16] = ((u64) in[8]) * (in2[8] << 0); - - felem_reduce_degree(out, tmp); -} - -static void felem_assign(felem out, const felem in) { - memcpy(out, in, sizeof(felem)); -} - -/* felem_inv calculates |out| = |in|^{-1} - * - * Based on Fermat's Little Theorem: - * a^p = a (mod p) - * a^{p-1} = 1 (mod p) - * a^{p-2} = a^{-1} (mod p) - */ -static void felem_inv(felem out, const felem in) { - felem ftmp, ftmp2; - /* each e_I will hold |in|^{2^I - 1} */ - felem e2, e4, e8, e16, e32, e64; - unsigned i; - - felem_square(ftmp, in); /* 2^1 */ - felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */ - felem_assign(e2, ftmp); - felem_square(ftmp, ftmp); /* 2^3 - 2^1 */ - felem_square(ftmp, ftmp); /* 2^4 - 2^2 */ - felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */ - felem_assign(e4, ftmp); - felem_square(ftmp, ftmp); /* 2^5 - 2^1 */ - felem_square(ftmp, ftmp); /* 2^6 - 2^2 */ - felem_square(ftmp, ftmp); /* 2^7 - 2^3 */ - felem_square(ftmp, ftmp); /* 2^8 - 2^4 */ - felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */ - felem_assign(e8, ftmp); - for (i = 0; i < 8; i++) { - felem_square(ftmp, ftmp); - } /* 2^16 - 2^8 */ - felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */ - felem_assign(e16, ftmp); - for (i = 0; i < 16; i++) { - felem_square(ftmp, ftmp); - } /* 2^32 - 2^16 */ - felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */ - felem_assign(e32, ftmp); - for (i = 0; i < 32; i++) { - felem_square(ftmp, ftmp); - } /* 2^64 - 2^32 */ - felem_assign(e64, ftmp); - felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */ - for (i = 0; i < 192; i++) { - felem_square(ftmp, ftmp); - } /* 2^256 - 2^224 + 2^192 */ - - felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */ - for (i = 0; i < 16; i++) { - felem_square(ftmp2, ftmp2); - } /* 2^80 - 2^16 */ - felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */ - for (i = 0; i < 8; i++) { - felem_square(ftmp2, ftmp2); - } /* 2^88 - 2^8 */ - felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */ - for (i = 0; i < 4; i++) { - felem_square(ftmp2, ftmp2); - } /* 2^92 - 2^4 */ - felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */ - felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */ - felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */ - felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */ - felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */ - felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */ - felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */ - - felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */ -} - -/* felem_scalar_3 sets out=3*out. - * - * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. - * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ -static void felem_scalar_3(felem out) { - limb carry = 0; - unsigned i; - - for (i = 0;; i++) { - out[i] *= 3; - out[i] += carry; - carry = out[i] >> 29; - out[i] &= kBottom29Bits; - - i++; - if (i == NLIMBS) - break; - - out[i] *= 3; - out[i] += carry; - carry = out[i] >> 28; - out[i] &= kBottom28Bits; - } - - felem_reduce_carry(out, carry); -} - -/* felem_scalar_4 sets out=4*out. - * - * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. - * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ -static void felem_scalar_4(felem out) { - limb carry = 0, next_carry; - unsigned i; - - for (i = 0;; i++) { - next_carry = out[i] >> 27; - out[i] <<= 2; - out[i] &= kBottom29Bits; - out[i] += carry; - carry = next_carry + (out[i] >> 29); - out[i] &= kBottom29Bits; - - i++; - if (i == NLIMBS) - break; - - next_carry = out[i] >> 26; - out[i] <<= 2; - out[i] &= kBottom28Bits; - out[i] += carry; - carry = next_carry + (out[i] >> 28); - out[i] &= kBottom28Bits; - } - - felem_reduce_carry(out, carry); -} - -/* felem_scalar_8 sets out=8*out. - * - * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. - * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ -static void felem_scalar_8(felem out) { - limb carry = 0, next_carry; - unsigned i; - - for (i = 0;; i++) { - next_carry = out[i] >> 26; - out[i] <<= 3; - out[i] &= kBottom29Bits; - out[i] += carry; - carry = next_carry + (out[i] >> 29); - out[i] &= kBottom29Bits; - - i++; - if (i == NLIMBS) - break; - - next_carry = out[i] >> 25; - out[i] <<= 3; - out[i] &= kBottom28Bits; - out[i] += carry; - carry = next_carry + (out[i] >> 28); - out[i] &= kBottom28Bits; - } - - felem_reduce_carry(out, carry); -} - -/* felem_is_zero_vartime returns 1 iff |in| == 0. It takes a variable amount of - * time depending on the value of |in|. */ -static char felem_is_zero_vartime(const felem in) { - limb carry; - int i; - limb tmp[NLIMBS]; - - felem_assign(tmp, in); - - /* First, reduce tmp to a minimal form. */ - do { - carry = 0; - for (i = 0;; i++) { - tmp[i] += carry; - carry = tmp[i] >> 29; - tmp[i] &= kBottom29Bits; - - i++; - if (i == NLIMBS) - break; - - tmp[i] += carry; - carry = tmp[i] >> 28; - tmp[i] &= kBottom28Bits; - } - - felem_reduce_carry(tmp, carry); - } while (carry); - - /* tmp < 2**257, so the only possible zero values are 0, p and 2p. */ - return memcmp(tmp, kZero, sizeof(tmp)) == 0 || - memcmp(tmp, kP, sizeof(tmp)) == 0 || - memcmp(tmp, k2P, sizeof(tmp)) == 0; -} - - -/* Group operations: - * - * Elements of the elliptic curve group are represented in Jacobian - * coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in - * Jacobian form. */ - -/* point_double sets {x_out,y_out,z_out} = 2*{x,y,z}. - * - * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */ -static void point_double(felem x_out, felem y_out, felem z_out, const felem x, - const felem y, const felem z) { - felem delta, gamma, alpha, beta, tmp, tmp2; - - felem_square(delta, z); - felem_square(gamma, y); - felem_mul(beta, x, gamma); - - felem_sum(tmp, x, delta); - felem_diff(tmp2, x, delta); - felem_mul(alpha, tmp, tmp2); - felem_scalar_3(alpha); - - felem_sum(tmp, y, z); - felem_square(tmp, tmp); - felem_diff(tmp, tmp, gamma); - felem_diff(z_out, tmp, delta); - - felem_scalar_4(beta); - felem_square(x_out, alpha); - felem_diff(x_out, x_out, beta); - felem_diff(x_out, x_out, beta); - - felem_diff(tmp, beta, x_out); - felem_mul(tmp, alpha, tmp); - felem_square(tmp2, gamma); - felem_scalar_8(tmp2); - felem_diff(y_out, tmp, tmp2); -} - -/* point_add_mixed sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,1}. - * (i.e. the second point is affine.) - * - * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl - * - * Note that this function does not handle P+P, infinity+P nor P+infinity - * correctly. */ -static void point_add_mixed(felem x_out, felem y_out, felem z_out, - const felem x1, const felem y1, const felem z1, - const felem x2, const felem y2) { - felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp; - - felem_square(z1z1, z1); - felem_sum(tmp, z1, z1); - - felem_mul(u2, x2, z1z1); - felem_mul(z1z1z1, z1, z1z1); - felem_mul(s2, y2, z1z1z1); - felem_diff(h, u2, x1); - felem_sum(i, h, h); - felem_square(i, i); - felem_mul(j, h, i); - felem_diff(r, s2, y1); - felem_sum(r, r, r); - felem_mul(v, x1, i); - - felem_mul(z_out, tmp, h); - felem_square(rr, r); - felem_diff(x_out, rr, j); - felem_diff(x_out, x_out, v); - felem_diff(x_out, x_out, v); - - felem_diff(tmp, v, x_out); - felem_mul(y_out, tmp, r); - felem_mul(tmp, y1, j); - felem_diff(y_out, y_out, tmp); - felem_diff(y_out, y_out, tmp); -} - -/* point_add sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,z2}. - * - * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl - * - * Note that this function does not handle P+P, infinity+P nor P+infinity - * correctly. */ -static void point_add(felem x_out, felem y_out, felem z_out, const felem x1, - const felem y1, const felem z1, const felem x2, - const felem y2, const felem z2) { - felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp; - - felem_square(z1z1, z1); - felem_square(z2z2, z2); - felem_mul(u1, x1, z2z2); - - felem_sum(tmp, z1, z2); - felem_square(tmp, tmp); - felem_diff(tmp, tmp, z1z1); - felem_diff(tmp, tmp, z2z2); - - felem_mul(z2z2z2, z2, z2z2); - felem_mul(s1, y1, z2z2z2); - - felem_mul(u2, x2, z1z1); - felem_mul(z1z1z1, z1, z1z1); - felem_mul(s2, y2, z1z1z1); - felem_diff(h, u2, u1); - felem_sum(i, h, h); - felem_square(i, i); - felem_mul(j, h, i); - felem_diff(r, s2, s1); - felem_sum(r, r, r); - felem_mul(v, u1, i); - - felem_mul(z_out, tmp, h); - felem_square(rr, r); - felem_diff(x_out, rr, j); - felem_diff(x_out, x_out, v); - felem_diff(x_out, x_out, v); - - felem_diff(tmp, v, x_out); - felem_mul(y_out, tmp, r); - felem_mul(tmp, s1, j); - felem_diff(y_out, y_out, tmp); - felem_diff(y_out, y_out, tmp); -} - -/* point_add_or_double_vartime sets {x_out,y_out,z_out} = {x1,y1,z1} + - * {x2,y2,z2}. - * - * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl - * - * This function handles the case where {x1,y1,z1}={x2,y2,z2}. */ -static void point_add_or_double_vartime( - felem x_out, felem y_out, felem z_out, const felem x1, const felem y1, - const felem z1, const felem x2, const felem y2, const felem z2) { - felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp; - char x_equal, y_equal; - - felem_square(z1z1, z1); - felem_square(z2z2, z2); - felem_mul(u1, x1, z2z2); - - felem_sum(tmp, z1, z2); - felem_square(tmp, tmp); - felem_diff(tmp, tmp, z1z1); - felem_diff(tmp, tmp, z2z2); - - felem_mul(z2z2z2, z2, z2z2); - felem_mul(s1, y1, z2z2z2); - - felem_mul(u2, x2, z1z1); - felem_mul(z1z1z1, z1, z1z1); - felem_mul(s2, y2, z1z1z1); - felem_diff(h, u2, u1); - x_equal = felem_is_zero_vartime(h); - felem_sum(i, h, h); - felem_square(i, i); - felem_mul(j, h, i); - felem_diff(r, s2, s1); - y_equal = felem_is_zero_vartime(r); - if (x_equal && y_equal) { - point_double(x_out, y_out, z_out, x1, y1, z1); - return; - } - felem_sum(r, r, r); - felem_mul(v, u1, i); - - felem_mul(z_out, tmp, h); - felem_square(rr, r); - felem_diff(x_out, rr, j); - felem_diff(x_out, x_out, v); - felem_diff(x_out, x_out, v); - - felem_diff(tmp, v, x_out); - felem_mul(y_out, tmp, r); - felem_mul(tmp, s1, j); - felem_diff(y_out, y_out, tmp); - felem_diff(y_out, y_out, tmp); -} - -/* copy_conditional sets out=in if mask = 0xffffffff in constant time. - * - * On entry: mask is either 0 or 0xffffffff. */ -static void copy_conditional(felem out, const felem in, limb mask) { - int i; - - for (i = 0; i < NLIMBS; i++) { - const limb tmp = mask & (in[i] ^ out[i]); - out[i] ^= tmp; - } -} - -/* select_affine_point sets {out_x,out_y} to the index'th entry of table. - * On entry: index < 16, table[0] must be zero. */ -static void select_affine_point(felem out_x, felem out_y, const limb* table, - limb index) { - limb i, j; - - memset(out_x, 0, sizeof(felem)); - memset(out_y, 0, sizeof(felem)); - - for (i = 1; i < 16; i++) { - limb mask = i ^ index; - mask |= mask >> 2; - mask |= mask >> 1; - mask &= 1; - mask--; - for (j = 0; j < NLIMBS; j++, table++) { - out_x[j] |= *table & mask; - } - for (j = 0; j < NLIMBS; j++, table++) { - out_y[j] |= *table & mask; - } - } -} - -/* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of - * table. On entry: index < 16, table[0] must be zero. */ -static void select_jacobian_point(felem out_x, felem out_y, felem out_z, - const limb* table, limb index) { - limb i, j; - - memset(out_x, 0, sizeof(felem)); - memset(out_y, 0, sizeof(felem)); - memset(out_z, 0, sizeof(felem)); - - /* The implicit value at index 0 is all zero. We don't need to perform that - * iteration of the loop because we already set out_* to zero. */ - table += 3 * NLIMBS; - - // Hit all entries to obscure cache profiling. - for (i = 1; i < 16; i++) { - limb mask = i ^ index; - mask |= mask >> 2; - mask |= mask >> 1; - mask &= 1; - mask--; - for (j = 0; j < NLIMBS; j++, table++) { - out_x[j] |= *table & mask; - } - for (j = 0; j < NLIMBS; j++, table++) { - out_y[j] |= *table & mask; - } - for (j = 0; j < NLIMBS; j++, table++) { - out_z[j] |= *table & mask; - } - } -} - -/* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian - * number. Note that the value of scalar must be less than the order of the - * group. */ -static void scalar_base_mult(felem nx, felem ny, felem nz, - const p256_int* scalar) { - int i, j; - limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask; - u32 table_offset; - - felem px, py; - felem tx, ty, tz; - - memset(nx, 0, sizeof(felem)); - memset(ny, 0, sizeof(felem)); - memset(nz, 0, sizeof(felem)); - - /* The loop adds bits at positions 0, 64, 128 and 192, followed by - * positions 32,96,160 and 224 and does this 32 times. */ - for (i = 0; i < 32; i++) { - if (i) { - point_double(nx, ny, nz, nx, ny, nz); - } - table_offset = 0; - for (j = 0; j <= 32; j += 32) { - char bit0 = p256_get_bit(scalar, 31 - i + j); - char bit1 = p256_get_bit(scalar, 95 - i + j); - char bit2 = p256_get_bit(scalar, 159 - i + j); - char bit3 = p256_get_bit(scalar, 223 - i + j); - limb index = bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3); - - select_affine_point(px, py, kPrecomputed + table_offset, index); - table_offset += 30 * NLIMBS; - - /* Since scalar is less than the order of the group, we know that - * {nx,ny,nz} != {px,py,1}, unless both are zero, which we handle - * below. */ - point_add_mixed(tx, ty, tz, nx, ny, nz, px, py); - /* The result of point_add_mixed is incorrect if {nx,ny,nz} is zero - * (a.k.a. the point at infinity). We handle that situation by - * copying the point from the table. */ - copy_conditional(nx, px, n_is_infinity_mask); - copy_conditional(ny, py, n_is_infinity_mask); - copy_conditional(nz, kOne, n_is_infinity_mask); - - /* Equally, the result is also wrong if the point from the table is - * zero, which happens when the index is zero. We handle that by - * only copying from {tx,ty,tz} to {nx,ny,nz} if index != 0. */ - p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index); - mask = p_is_noninfinite_mask & ~n_is_infinity_mask; - copy_conditional(nx, tx, mask); - copy_conditional(ny, ty, mask); - copy_conditional(nz, tz, mask); - /* If p was not zero, then n is now non-zero. */ - n_is_infinity_mask &= ~p_is_noninfinite_mask; - } - } -} - -/* point_to_affine converts a Jacobian point to an affine point. If the input - * is the point at infinity then it returns (0, 0) in constant time. */ -static void point_to_affine(felem x_out, felem y_out, const felem nx, - const felem ny, const felem nz) { - felem z_inv, z_inv_sq; - felem_inv(z_inv, nz); - felem_square(z_inv_sq, z_inv); - felem_mul(x_out, nx, z_inv_sq); - felem_mul(z_inv, z_inv, z_inv_sq); - felem_mul(y_out, ny, z_inv); -} - -/* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */ -static void scalar_mult(felem nx, felem ny, felem nz, const felem x, - const felem y, const p256_int* scalar) { - int i; - felem px, py, pz, tx, ty, tz; - felem precomp[16][3]; - limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask; - - /* We precompute 0,1,2,... times {x,y}. */ - memset(precomp, 0, sizeof(felem) * 3); - memcpy(&precomp[1][0], x, sizeof(felem)); - memcpy(&precomp[1][1], y, sizeof(felem)); - memcpy(&precomp[1][2], kOne, sizeof(felem)); - - for (i = 2; i < 16; i += 2) { - point_double(precomp[i][0], precomp[i][1], precomp[i][2], - precomp[i / 2][0], precomp[i / 2][1], precomp[i / 2][2]); - - point_add_mixed(precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2], - precomp[i][0], precomp[i][1], precomp[i][2], x, y); - } - - memset(nx, 0, sizeof(felem)); - memset(ny, 0, sizeof(felem)); - memset(nz, 0, sizeof(felem)); - n_is_infinity_mask = -1; - - /* We add in a window of four bits each iteration and do this 64 times. */ - for (i = 0; i < 256; i += 4) { - if (i) { - point_double(nx, ny, nz, nx, ny, nz); - point_double(nx, ny, nz, nx, ny, nz); - point_double(nx, ny, nz, nx, ny, nz); - point_double(nx, ny, nz, nx, ny, nz); - } - - index = (p256_get_bit(scalar, 255 - i - 0) << 3) | - (p256_get_bit(scalar, 255 - i - 1) << 2) | - (p256_get_bit(scalar, 255 - i - 2) << 1) | - p256_get_bit(scalar, 255 - i - 3); - - /* See the comments in scalar_base_mult about handling infinities. */ - select_jacobian_point(px, py, pz, precomp[0][0], index); - point_add(tx, ty, tz, nx, ny, nz, px, py, pz); - copy_conditional(nx, px, n_is_infinity_mask); - copy_conditional(ny, py, n_is_infinity_mask); - copy_conditional(nz, pz, n_is_infinity_mask); - - p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index); - mask = p_is_noninfinite_mask & ~n_is_infinity_mask; - - copy_conditional(nx, tx, mask); - copy_conditional(ny, ty, mask); - copy_conditional(nz, tz, mask); - n_is_infinity_mask &= ~p_is_noninfinite_mask; - } -} - -#define kRDigits {2, 0, 0, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, 1} // 2^257 mod p256.p - -#define kRInvDigits {0x80000000, 1, 0xffffffff, 0, 0x80000001, 0xfffffffe, 1, 0x7fffffff} // 1 / 2^257 mod p256.p - -static const p256_int kR = { kRDigits }; -static const p256_int kRInv = { kRInvDigits }; - -/* to_montgomery sets out = R*in. */ -static void to_montgomery(felem out, const p256_int* in) { - p256_int in_shifted; - int i; - - p256_init(&in_shifted); - p256_modmul(&SECP256r1_p, in, 0, &kR, &in_shifted); - - for (i = 0; i < NLIMBS; i++) { - if ((i & 1) == 0) { - out[i] = P256_DIGIT(&in_shifted, 0) & kBottom29Bits; - p256_shr(&in_shifted, 29, &in_shifted); - } else { - out[i] = P256_DIGIT(&in_shifted, 0) & kBottom28Bits; - p256_shr(&in_shifted, 28, &in_shifted); - } - } - - p256_clear(&in_shifted); -} - -/* from_montgomery sets out=in/R. */ -static void from_montgomery(p256_int* out, const felem in) { - p256_int result, tmp; - int i, top; - - p256_init(&result); - p256_init(&tmp); - - p256_add_d(&tmp, in[NLIMBS - 1], &result); - for (i = NLIMBS - 2; i >= 0; i--) { - if ((i & 1) == 0) { - top = p256_shl(&result, 29, &tmp); - } else { - top = p256_shl(&result, 28, &tmp); - } - top |= p256_add_d(&tmp, in[i], &result); - } - - p256_modmul(&SECP256r1_p, &kRInv, top, &result, out); - - p256_clear(&result); - p256_clear(&tmp); -} - -/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the - * order of the group. */ -void p256_base_point_mul(const p256_int* n, p256_int* out_x, p256_int* out_y) { - felem x, y, z; - - scalar_base_mult(x, y, z, n); - - { - felem x_affine, y_affine; - - point_to_affine(x_affine, y_affine, x, y, z); - from_montgomery(out_x, x_affine); - from_montgomery(out_y, y_affine); - } -} - -/* p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where - * n1 and n2 are < the order of the group. - * - * As indicated by the name, this function operates in variable time. This - * is safe because it's used for signature validation which doesn't deal - * with secrets. */ -void p256_points_mul_vartime( - const p256_int* n1, const p256_int* n2, const p256_int* in_x, - const p256_int* in_y, p256_int* out_x, p256_int* out_y) { - felem x1, y1, z1, x2, y2, z2, px, py; - - /* If both scalars are zero, then the result is the point at infinity. */ - if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) { - p256_clear(out_x); - p256_clear(out_y); - return; - } - - to_montgomery(px, in_x); - to_montgomery(py, in_y); - scalar_base_mult(x1, y1, z1, n1); - scalar_mult(x2, y2, z2, px, py, n2); - - if (p256_is_zero(n2) != 0) { - /* If n2 == 0, then {x2,y2,z2} is zero and the result is just - * {x1,y1,z1}. */ - } else if (p256_is_zero(n1) != 0) { - /* If n1 == 0, then {x1,y1,z1} is zero and the result is just - * {x2,y2,z2}. */ - memcpy(x1, x2, sizeof(x2)); - memcpy(y1, y2, sizeof(y2)); - memcpy(z1, z2, sizeof(z2)); - } else { - /* This function handles the case where {x1,y1,z1} == {x2,y2,z2}. */ - point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2); - } - - point_to_affine(px, py, x1, y1, z1); - from_montgomery(out_x, px); - from_montgomery(out_y, py); -} diff --git a/src/libmincrypt/c/p256_ecdsa.c b/src/libmincrypt/c/p256_ecdsa.c deleted file mode 100644 index f2264b0..0000000 --- a/src/libmincrypt/c/p256_ecdsa.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include "mincrypt/p256_ecdsa.h" -#include "mincrypt/p256.h" - -int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y, - const p256_int* message, - const p256_int* r, const p256_int* s) { - p256_int u, v; - - // Check public key. - if (!p256_is_valid_point(key_x, key_y)) return 0; - - // Check r and s are != 0 % n. - p256_mod(&SECP256r1_n, r, &u); - p256_mod(&SECP256r1_n, s, &v); - if (p256_is_zero(&u) || p256_is_zero(&v)) return 0; - - p256_modinv_vartime(&SECP256r1_n, s, &v); - p256_modmul(&SECP256r1_n, message, 0, &v, &u); // message / s % n - p256_modmul(&SECP256r1_n, r, 0, &v, &v); // r / s % n - - p256_points_mul_vartime(&u, &v, - key_x, key_y, - &u, &v); - - p256_mod(&SECP256r1_n, &u, &u); // (x coord % p) % n - return p256_cmp(r, &u) == 0; -} - diff --git a/src/libmincrypt/c/rsa.c b/src/libmincrypt/c/rsa.c deleted file mode 100644 index 9061b3a..0000000 --- a/src/libmincrypt/c/rsa.c +++ /dev/null @@ -1,308 +0,0 @@ -/* rsa.c -** -** Copyright 2012, The Android Open Source Project -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** * Neither the name of Google Inc. nor the names of its contributors may -** be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "mincrypt/rsa.h" -#include "mincrypt/sha.h" -#include "mincrypt/sha256.h" - -// a[] -= mod -static void subM(const RSAPublicKey* key, - uint32_t* a) { - int64_t A = 0; - int i; - for (i = 0; i < key->len; ++i) { - A += (uint64_t)a[i] - key->n[i]; - a[i] = (uint32_t)A; - A >>= 32; - } -} - -// return a[] >= mod -static int geM(const RSAPublicKey* key, - const uint32_t* a) { - int i; - for (i = key->len; i;) { - --i; - if (a[i] < key->n[i]) return 0; - if (a[i] > key->n[i]) return 1; - } - return 1; // equal -} - -// montgomery c[] += a * b[] / R % mod -static void montMulAdd(const RSAPublicKey* key, - uint32_t* c, - const uint32_t a, - const uint32_t* b) { - uint64_t A = (uint64_t)a * b[0] + c[0]; - uint32_t d0 = (uint32_t)A * key->n0inv; - uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A; - int i; - - for (i = 1; i < key->len; ++i) { - A = (A >> 32) + (uint64_t)a * b[i] + c[i]; - B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A; - c[i - 1] = (uint32_t)B; - } - - A = (A >> 32) + (B >> 32); - - c[i - 1] = (uint32_t)A; - - if (A >> 32) { - subM(key, c); - } -} - -// montgomery c[] = a[] * b[] / R % mod -static void montMul(const RSAPublicKey* key, - uint32_t* c, - const uint32_t* a, - const uint32_t* b) { - int i; - for (i = 0; i < key->len; ++i) { - c[i] = 0; - } - for (i = 0; i < key->len; ++i) { - montMulAdd(key, c, a[i], b); - } -} - -// In-place public exponentiation. -// Input and output big-endian byte array in inout. -static void modpow(const RSAPublicKey* key, - uint8_t* inout) { - uint32_t a[RSANUMWORDS]; - uint32_t aR[RSANUMWORDS]; - uint32_t aaR[RSANUMWORDS]; - uint32_t* aaa = 0; - int i; - - // Convert from big endian byte array to little endian word array. - for (i = 0; i < key->len; ++i) { - uint32_t tmp = - (inout[((key->len - 1 - i) * 4) + 0] << 24) | - (inout[((key->len - 1 - i) * 4) + 1] << 16) | - (inout[((key->len - 1 - i) * 4) + 2] << 8) | - (inout[((key->len - 1 - i) * 4) + 3] << 0); - a[i] = tmp; - } - - if (key->exponent == 65537) { - aaa = aaR; // Re-use location. - montMul(key, aR, a, key->rr); // aR = a * RR / R mod M - for (i = 0; i < 16; i += 2) { - montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M - montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M - } - montMul(key, aaa, aR, a); // aaa = aR * a / R mod M - } else if (key->exponent == 3) { - aaa = aR; // Re-use location. - montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */ - montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */ - montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */ - } - - // Make sure aaa < mod; aaa is at most 1x mod too large. - if (geM(key, aaa)) { - subM(key, aaa); - } - - // Convert to bigendian byte array - for (i = key->len - 1; i >= 0; --i) { - uint32_t tmp = aaa[i]; - *inout++ = tmp >> 24; - *inout++ = tmp >> 16; - *inout++ = tmp >> 8; - *inout++ = tmp >> 0; - } -} - -// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature. -// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the -// other flavor which omits the optional parameter entirely). This code does not -// accept signatures without the optional parameter. - -/* -static const uint8_t sha_padding[RSANUMBYTES] = { - 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30, - 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, - 0x05, 0x00, 0x04, 0x14, - - // 20 bytes of hash go here. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; -*/ - -// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above. -// At the location of the bytes of the hash all 00 are hashed. -static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = { - 0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e, - 0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68, - 0x7c, 0xfb, 0xf1, 0x67 -}; - -/* -static const uint8_t sha256_padding[RSANUMBYTES] = { - 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30, - 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, - 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, - - // 32 bytes of hash go here. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -}; -*/ - -// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above. -// At the location of the bytes of the hash all 00 are hashed. -static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = { - 0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92, - 0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e, - 0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd, - 0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59, -}; - -// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash. -// Both e=3 and e=65537 are supported. hash_len may be -// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or -// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash. No other -// values are supported. -// -// Returns 1 on successful verification, 0 on failure. -int RSA_verify(const RSAPublicKey *key, - const uint8_t *signature, - const int len, - const uint8_t *hash, - const int hash_len) { - uint8_t buf[RSANUMBYTES]; - int i; - const uint8_t* padding_hash; - - if (key->len != RSANUMWORDS) { - return 0; // Wrong key passed in. - } - - if (len != sizeof(buf)) { - return 0; // Wrong input length. - } - - if (hash_len != SHA_DIGEST_SIZE && - hash_len != SHA256_DIGEST_SIZE) { - return 0; // Unsupported hash. - } - - if (key->exponent != 3 && key->exponent != 65537) { - return 0; // Unsupported exponent. - } - - for (i = 0; i < len; ++i) { // Copy input to local workspace. - buf[i] = signature[i]; - } - - modpow(key, buf); // In-place exponentiation. - - // Xor sha portion, so it all becomes 00 iff equal. - for (i = len - hash_len; i < len; ++i) { - buf[i] ^= *hash++; - } - - // Hash resulting buf, in-place. - switch (hash_len) { - case SHA_DIGEST_SIZE: - padding_hash = kExpectedPadShaRsa2048; - SHA_hash(buf, len, buf); - break; - case SHA256_DIGEST_SIZE: - padding_hash = kExpectedPadSha256Rsa2048; - SHA256_hash(buf, len, buf); - break; - default: - return 0; - } - - // Compare against expected hash value. - for (i = 0; i < hash_len; ++i) { - if (buf[i] != padding_hash[i]) { - return 0; - } - } - - return 1; // All checked out OK. -} diff --git a/src/libmincrypt/c/sha.c b/src/libmincrypt/c/sha.c deleted file mode 100644 index 5bef32e..0000000 --- a/src/libmincrypt/c/sha.c +++ /dev/null @@ -1,155 +0,0 @@ -/* sha.c -** -** Copyright 2013, The Android Open Source Project -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** * Neither the name of Google Inc. nor the names of its contributors may -** be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// Optimized for minimal code size. - -#include "mincrypt/sha.h" - -#include -#include -#include - -#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -static void SHA1_Transform(SHA_CTX* ctx) { - uint32_t W[80]; - uint32_t A, B, C, D, E; - uint8_t* p = ctx->buf; - int t; - - for(t = 0; t < 16; ++t) { - uint32_t tmp = *p++ << 24; - tmp |= *p++ << 16; - tmp |= *p++ << 8; - tmp |= *p++; - W[t] = tmp; - } - - for(; t < 80; t++) { - W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); - } - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - E = ctx->state[4]; - - for(t = 0; t < 80; t++) { - uint32_t tmp = rol(5,A) + E + W[t]; - - if (t < 20) - tmp += (D^(B&(C^D))) + 0x5A827999; - else if ( t < 40) - tmp += (B^C^D) + 0x6ED9EBA1; - else if ( t < 60) - tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC; - else - tmp += (B^C^D) + 0xCA62C1D6; - - E = D; - D = C; - C = rol(30,B); - B = A; - A = tmp; - } - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; - ctx->state[4] += E; -} - -static const HASH_VTAB SHA_VTAB = { - SHA_init, - SHA_update, - SHA_final, - SHA_hash, - SHA_DIGEST_SIZE -}; - -void SHA_init(SHA_CTX* ctx) { - ctx->f = &SHA_VTAB; - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; - ctx->state[4] = 0xC3D2E1F0; - ctx->count = 0; -} - - -void SHA_update(SHA_CTX* ctx, const void* data, int len) { - int i = (int) (ctx->count & 63); - const uint8_t* p = (const uint8_t*)data; - - ctx->count += len; - - while (len--) { - ctx->buf[i++] = *p++; - if (i == 64) { - SHA1_Transform(ctx); - i = 0; - } - } -} - - -const uint8_t* SHA_final(SHA_CTX* ctx) { - uint8_t *p = ctx->buf; - uint64_t cnt = ctx->count * 8; - int i; - - SHA_update(ctx, (uint8_t*)"\x80", 1); - while ((ctx->count & 63) != 56) { - SHA_update(ctx, (uint8_t*)"\0", 1); - } - for (i = 0; i < 8; ++i) { - uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8)); - SHA_update(ctx, &tmp, 1); - } - - for (i = 0; i < 5; i++) { - uint32_t tmp = ctx->state[i]; - *p++ = tmp >> 24; - *p++ = tmp >> 16; - *p++ = tmp >> 8; - *p++ = tmp >> 0; - } - - return ctx->buf; -} - -/* Convenience function */ -const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) { - SHA_CTX ctx; - SHA_init(&ctx); - SHA_update(&ctx, data, len); - memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE); - return digest; -} diff --git a/src/libmincrypt/c/sha256.c b/src/libmincrypt/c/sha256.c deleted file mode 100644 index eb6e308..0000000 --- a/src/libmincrypt/c/sha256.c +++ /dev/null @@ -1,184 +0,0 @@ -/* sha256.c -** -** Copyright 2013, The Android Open Source Project -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** * Neither the name of Google Inc. nor the names of its contributors may -** be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -// Optimized for minimal code size. - -#include "mincrypt/sha256.h" - -#include -#include -#include - -#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits)))) -#define shr(value, bits) ((value) >> (bits)) - -static const uint32_t K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; - -static void SHA256_Transform(SHA256_CTX* ctx) { - uint32_t W[64]; - uint32_t A, B, C, D, E, F, G, H; - uint8_t* p = ctx->buf; - int t; - - for(t = 0; t < 16; ++t) { - uint32_t tmp = *p++ << 24; - tmp |= *p++ << 16; - tmp |= *p++ << 8; - tmp |= *p++; - W[t] = tmp; - } - - for(; t < 64; t++) { - uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3); - uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10); - W[t] = W[t-16] + s0 + W[t-7] + s1; - } - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - E = ctx->state[4]; - F = ctx->state[5]; - G = ctx->state[6]; - H = ctx->state[7]; - - for(t = 0; t < 64; t++) { - uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22); - uint32_t maj = (A & B) ^ (A & C) ^ (B & C); - uint32_t t2 = s0 + maj; - uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25); - uint32_t ch = (E & F) ^ ((~E) & G); - uint32_t t1 = H + s1 + ch + K[t] + W[t]; - - H = G; - G = F; - F = E; - E = D + t1; - D = C; - C = B; - B = A; - A = t1 + t2; - } - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; - ctx->state[4] += E; - ctx->state[5] += F; - ctx->state[6] += G; - ctx->state[7] += H; -} - -static const HASH_VTAB SHA256_VTAB = { - SHA256_init, - SHA256_update, - SHA256_final, - SHA256_hash, - SHA256_DIGEST_SIZE -}; - -void SHA256_init(SHA256_CTX* ctx) { - ctx->f = &SHA256_VTAB; - ctx->state[0] = 0x6a09e667; - ctx->state[1] = 0xbb67ae85; - ctx->state[2] = 0x3c6ef372; - ctx->state[3] = 0xa54ff53a; - ctx->state[4] = 0x510e527f; - ctx->state[5] = 0x9b05688c; - ctx->state[6] = 0x1f83d9ab; - ctx->state[7] = 0x5be0cd19; - ctx->count = 0; -} - - -void SHA256_update(SHA256_CTX* ctx, const void* data, int len) { - int i = (int) (ctx->count & 63); - const uint8_t* p = (const uint8_t*)data; - - ctx->count += len; - - while (len--) { - ctx->buf[i++] = *p++; - if (i == 64) { - SHA256_Transform(ctx); - i = 0; - } - } -} - - -const uint8_t* SHA256_final(SHA256_CTX* ctx) { - uint8_t *p = ctx->buf; - uint64_t cnt = ctx->count * 8; - int i; - - SHA256_update(ctx, (uint8_t*)"\x80", 1); - while ((ctx->count & 63) != 56) { - SHA256_update(ctx, (uint8_t*)"\0", 1); - } - for (i = 0; i < 8; ++i) { - uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8)); - SHA256_update(ctx, &tmp, 1); - } - - for (i = 0; i < 8; i++) { - uint32_t tmp = ctx->state[i]; - *p++ = tmp >> 24; - *p++ = tmp >> 16; - *p++ = tmp >> 8; - *p++ = tmp >> 0; - } - - return ctx->buf; -} - -/* Convenience function */ -const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) { - SHA256_CTX ctx; - SHA256_init(&ctx); - SHA256_update(&ctx, data, len); - memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE); - return digest; -} diff --git a/src/libmincrypt/headers/mincrypt/dsa_sig.h b/src/libmincrypt/headers/mincrypt/dsa_sig.h deleted file mode 100644 index b0d91cd..0000000 --- a/src/libmincrypt/headers/mincrypt/dsa_sig.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ -#define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ - -#include "mincrypt/p256.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Returns 0 if input sig is not a valid ASN.1 sequence -int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int); - -#ifdef __cplusplus -} -#endif - -#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */ diff --git a/src/libmincrypt/headers/mincrypt/hash-internal.h b/src/libmincrypt/headers/mincrypt/hash-internal.h deleted file mode 100644 index c813b44..0000000 --- a/src/libmincrypt/headers/mincrypt/hash-internal.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2007 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ -#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -struct HASH_CTX; // forward decl - -typedef struct HASH_VTAB { - void (* const init)(struct HASH_CTX*); - void (* const update)(struct HASH_CTX*, const void*, int); - const uint8_t* (* const final)(struct HASH_CTX*); - const uint8_t* (* const hash)(const void*, int, uint8_t*); - int size; -} HASH_VTAB; - -typedef struct HASH_CTX { - const HASH_VTAB * f; - uint64_t count; - uint8_t buf[64]; - uint32_t state[8]; // upto SHA2 -} HASH_CTX; - -#define HASH_init(ctx) (ctx)->f->init(ctx) -#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len) -#define HASH_final(ctx) (ctx)->f->final(ctx) -#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest) -#define HASH_size(ctx) (ctx)->f->size - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ diff --git a/src/libmincrypt/headers/mincrypt/p256.h b/src/libmincrypt/headers/mincrypt/p256.h deleted file mode 100644 index 465a1b9..0000000 --- a/src/libmincrypt/headers/mincrypt/p256.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_ -#define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_ - -// Collection of routines manipulating 256 bit unsigned integers. -// Just enough to implement ecdsa-p256 and related algorithms. - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define P256_BITSPERDIGIT 32 -#define P256_NDIGITS 8 -#define P256_NBYTES 32 - -typedef int p256_err; -typedef uint32_t p256_digit; -typedef int32_t p256_sdigit; -typedef uint64_t p256_ddigit; -typedef int64_t p256_sddigit; - -// Defining p256_int as struct to leverage struct assigment. -typedef struct { - p256_digit a[P256_NDIGITS]; -} p256_int; - -extern const p256_int SECP256r1_n; // Curve order -extern const p256_int SECP256r1_p; // Curve prime -extern const p256_int SECP256r1_b; // Curve param - -// Initialize a p256_int to zero. -void p256_init(p256_int* a); - -// Clear a p256_int to zero. -void p256_clear(p256_int* a); - -// Return bit. Index 0 is least significant. -int p256_get_bit(const p256_int* a, int index); - -// b := a % MOD -void p256_mod( - const p256_int* MOD, - const p256_int* a, - p256_int* b); - -// c := a * (top_b | b) % MOD -void p256_modmul( - const p256_int* MOD, - const p256_int* a, - const p256_digit top_b, - const p256_int* b, - p256_int* c); - -// b := 1 / a % MOD -// MOD best be SECP256r1_n -void p256_modinv( - const p256_int* MOD, - const p256_int* a, - p256_int* b); - -// b := 1 / a % MOD -// MOD best be SECP256r1_n -// Faster than p256_modinv() -void p256_modinv_vartime( - const p256_int* MOD, - const p256_int* a, - p256_int* b); - -// b := a << (n % P256_BITSPERDIGIT) -// Returns the bits shifted out of most significant digit. -p256_digit p256_shl(const p256_int* a, int n, p256_int* b); - -// b := a >> (n % P256_BITSPERDIGIT) -void p256_shr(const p256_int* a, int n, p256_int* b); - -int p256_is_zero(const p256_int* a); -int p256_is_odd(const p256_int* a); -int p256_is_even(const p256_int* a); - -// Returns -1, 0 or 1. -int p256_cmp(const p256_int* a, const p256_int *b); - -// c: = a - b -// Returns -1 on borrow. -int p256_sub(const p256_int* a, const p256_int* b, p256_int* c); - -// c := a + b -// Returns 1 on carry. -int p256_add(const p256_int* a, const p256_int* b, p256_int* c); - -// c := a + (single digit)b -// Returns carry 1 on carry. -int p256_add_d(const p256_int* a, p256_digit b, p256_int* c); - -// ec routines. - -// {out_x,out_y} := nG -void p256_base_point_mul(const p256_int *n, - p256_int *out_x, - p256_int *out_y); - -// {out_x,out_y} := n{in_x,in_y} -void p256_point_mul(const p256_int *n, - const p256_int *in_x, - const p256_int *in_y, - p256_int *out_x, - p256_int *out_y); - -// {out_x,out_y} := n1G + n2{in_x,in_y} -void p256_points_mul_vartime( - const p256_int *n1, const p256_int *n2, - const p256_int *in_x, const p256_int *in_y, - p256_int *out_x, p256_int *out_y); - -// Return whether point {x,y} is on curve. -int p256_is_valid_point(const p256_int* x, const p256_int* y); - -// Outputs big-endian binary form. No leading zero skips. -void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]); - -// Reads from big-endian binary form, -// thus pre-pad with leading zeros if short. -void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst); - -#define P256_DIGITS(x) ((x)->a) -#define P256_DIGIT(x,y) ((x)->a[y]) - -#define P256_ZERO {{0}} -#define P256_ONE {{1}} - -#ifdef __cplusplus -} -#endif - -#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_ diff --git a/src/libmincrypt/headers/mincrypt/p256_ecdsa.h b/src/libmincrypt/headers/mincrypt/p256_ecdsa.h deleted file mode 100644 index da339fa..0000000 --- a/src/libmincrypt/headers/mincrypt/p256_ecdsa.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_ -#define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_ - -// Using current directory as relative include path here since -// this code typically gets lifted into a variety of build systems -// and directory structures. -#include "p256.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Returns 0 if {r,s} is not a signature on message for -// public key {key_x,key_y}. -// -// Note: message is a p256_int. -// Convert from a binary string using p256_from_bin(). -int p256_ecdsa_verify(const p256_int* key_x, - const p256_int* key_y, - const p256_int* message, - const p256_int* r, const p256_int* s); - -#ifdef __cplusplus -} -#endif - -#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_ diff --git a/src/libmincrypt/headers/mincrypt/rsa.h b/src/libmincrypt/headers/mincrypt/rsa.h deleted file mode 100644 index 3d0556b..0000000 --- a/src/libmincrypt/headers/mincrypt/rsa.h +++ /dev/null @@ -1,58 +0,0 @@ -/* rsa.h -** -** Copyright 2008, The Android Open Source Project -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** * Neither the name of Google Inc. nor the names of its contributors may -** be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ -#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define RSANUMBYTES 256 /* 2048 bit key length */ -#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t)) - -typedef struct RSAPublicKey { - int len; /* Length of n[] in number of uint32_t */ - uint32_t n0inv; /* -1 / n[0] mod 2^32 */ - uint32_t n[RSANUMWORDS]; /* modulus as little endian array */ - uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */ - int exponent; /* 3 or 65537 */ -} RSAPublicKey; - -int RSA_verify(const RSAPublicKey *key, - const uint8_t* signature, - const int len, - const uint8_t* hash, - const int hash_len); - -#ifdef __cplusplus -} -#endif - -#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ diff --git a/src/libmincrypt/headers/mincrypt/sha.h b/src/libmincrypt/headers/mincrypt/sha.h deleted file mode 100644 index ef60aab..0000000 --- a/src/libmincrypt/headers/mincrypt/sha.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2005 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ -#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ - -#include -#include "hash-internal.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -typedef HASH_CTX SHA_CTX; - -void SHA_init(SHA_CTX* ctx); -void SHA_update(SHA_CTX* ctx, const void* data, int len); -const uint8_t* SHA_final(SHA_CTX* ctx); - -// Convenience method. Returns digest address. -// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes. -const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest); - -#define SHA_DIGEST_SIZE 20 - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ diff --git a/src/libmincrypt/headers/mincrypt/sha256.h b/src/libmincrypt/headers/mincrypt/sha256.h deleted file mode 100644 index 3a87c31..0000000 --- a/src/libmincrypt/headers/mincrypt/sha256.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2011 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ -#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ - -#include -#include "hash-internal.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -typedef HASH_CTX SHA256_CTX; - -void SHA256_init(SHA256_CTX* ctx); -void SHA256_update(SHA256_CTX* ctx, const void* data, int len); -const uint8_t* SHA256_final(SHA256_CTX* ctx); - -// Convenience method. Returns digest address. -const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest); - -#define SHA256_DIGEST_SIZE 32 - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ diff --git a/src/libmincrypt/tools/DumpPublicKey.java b/src/libmincrypt/tools/DumpPublicKey.java deleted file mode 100644 index 3eb1398..0000000 --- a/src/libmincrypt/tools/DumpPublicKey.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.dumpkey; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -import java.io.FileInputStream; -import java.math.BigInteger; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.KeyStore; -import java.security.Key; -import java.security.PublicKey; -import java.security.Security; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.ECPoint; - -/** - * Command line tool to extract RSA public keys from X.509 certificates - * and output source code with data initializers for the keys. - * @hide - */ -class DumpPublicKey { - /** - * @param key to perform sanity checks on - * @return version number of key. Supported versions are: - * 1: 2048-bit RSA key with e=3 and SHA-1 hash - * 2: 2048-bit RSA key with e=65537 and SHA-1 hash - * 3: 2048-bit RSA key with e=3 and SHA-256 hash - * 4: 2048-bit RSA key with e=65537 and SHA-256 hash - * @throws Exception if the key has the wrong size or public exponent - */ - static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception { - BigInteger pubexp = key.getPublicExponent(); - BigInteger modulus = key.getModulus(); - int version; - - if (pubexp.equals(BigInteger.valueOf(3))) { - version = useSHA256 ? 3 : 1; - } else if (pubexp.equals(BigInteger.valueOf(65537))) { - version = useSHA256 ? 4 : 2; - } else { - throw new Exception("Public exponent should be 3 or 65537 but is " + - pubexp.toString(10) + "."); - } - - if (modulus.bitLength() != 2048) { - throw new Exception("Modulus should be 2048 bits long but is " + - modulus.bitLength() + " bits."); - } - - return version; - } - - /** - * @param key to perform sanity checks on - * @return version number of key. Supported versions are: - * 5: 256-bit EC key with curve NIST P-256 - * @throws Exception if the key has the wrong size or public exponent - */ - static int checkEC(ECPublicKey key) throws Exception { - if (key.getParams().getCurve().getField().getFieldSize() != 256) { - throw new Exception("Curve must be NIST P-256"); - } - - return 5; - } - - /** - * Perform sanity check on public key. - */ - static int check(PublicKey key, boolean useSHA256) throws Exception { - if (key instanceof RSAPublicKey) { - return checkRSA((RSAPublicKey) key, useSHA256); - } else if (key instanceof ECPublicKey) { - if (!useSHA256) { - throw new Exception("Must use SHA-256 with EC keys!"); - } - return checkEC((ECPublicKey) key); - } else { - throw new Exception("Unsupported key class: " + key.getClass().getName()); - } - } - - /** - * @param key to output - * @return a String representing this public key. If the key is a - * version 1 key, the string will be a C initializer; this is - * not true for newer key versions. - */ - static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception { - int version = check(key, useSHA256); - - BigInteger N = key.getModulus(); - - StringBuilder result = new StringBuilder(); - - int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus - - if (version > 1) { - result.append("v"); - result.append(Integer.toString(version)); - result.append(" "); - } - - result.append("{"); - result.append(nwords); - - BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32 - BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32 - - result.append(",0x"); - result.append(N0inv.toString(16)); - - BigInteger R = BigInteger.valueOf(2).pow(N.bitLength()); - BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N - - // Write out modulus as little endian array of integers. - result.append(",{"); - for (int i = 0; i < nwords; ++i) { - long n = N.mod(B).longValue(); - result.append(n); - - if (i != nwords - 1) { - result.append(","); - } - - N = N.divide(B); - } - result.append("}"); - - // Write R^2 as little endian array of integers. - result.append(",{"); - for (int i = 0; i < nwords; ++i) { - long rr = RR.mod(B).longValue(); - result.append(rr); - - if (i != nwords - 1) { - result.append(","); - } - - RR = RR.divide(B); - } - result.append("}"); - - result.append("}"); - return result.toString(); - } - - /** - * @param key to output - * @return a String representing this public key. If the key is a - * version 1 key, the string will be a C initializer; this is - * not true for newer key versions. - */ - static String printEC(ECPublicKey key) throws Exception { - int version = checkEC(key); - - StringBuilder result = new StringBuilder(); - - result.append("v"); - result.append(Integer.toString(version)); - result.append(" "); - - BigInteger X = key.getW().getAffineX(); - BigInteger Y = key.getW().getAffineY(); - int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8; // # of 32 bit integers in X coordinate - - result.append("{"); - result.append(nbytes); - - BigInteger B = BigInteger.valueOf(0x100L); // 2^8 - - // Write out Y coordinate as array of characters. - result.append(",{"); - for (int i = 0; i < nbytes; ++i) { - long n = X.mod(B).longValue(); - result.append(n); - - if (i != nbytes - 1) { - result.append(","); - } - - X = X.divide(B); - } - result.append("}"); - - // Write out Y coordinate as array of characters. - result.append(",{"); - for (int i = 0; i < nbytes; ++i) { - long n = Y.mod(B).longValue(); - result.append(n); - - if (i != nbytes - 1) { - result.append(","); - } - - Y = Y.divide(B); - } - result.append("}"); - - result.append("}"); - return result.toString(); - } - - static String print(PublicKey key, boolean useSHA256) throws Exception { - if (key instanceof RSAPublicKey) { - return printRSA((RSAPublicKey) key, useSHA256); - } else if (key instanceof ECPublicKey) { - return printEC((ECPublicKey) key); - } else { - throw new Exception("Unsupported key class: " + key.getClass().getName()); - } - } - - public static void main(String[] args) { - if (args.length < 1) { - System.err.println("Usage: DumpPublicKey certfile ... > source.c"); - System.exit(1); - } - Security.addProvider(new BouncyCastleProvider()); - try { - for (int i = 0; i < args.length; i++) { - FileInputStream input = new FileInputStream(args[i]); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) cf.generateCertificate(input); - - boolean useSHA256 = false; - String sigAlg = cert.getSigAlgName(); - if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) { - // SignApk has historically accepted "MD5withRSA" - // certificates, but treated them as "SHA1withRSA" - // anyway. Continue to do so for backwards - // compatibility. - useSHA256 = false; - } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) { - useSHA256 = true; - } else { - System.err.println(args[i] + ": unsupported signature algorithm \"" + - sigAlg + "\""); - System.exit(1); - } - - PublicKey key = cert.getPublicKey(); - check(key, useSHA256); - System.out.print(print(key, useSHA256)); - System.out.println(i < args.length - 1 ? "," : ""); - } - } catch (Exception e) { - e.printStackTrace(); - System.exit(1); - } - System.exit(0); - } -} diff --git a/src/libmincrypt/tools/DumpPublicKey.mf b/src/libmincrypt/tools/DumpPublicKey.mf deleted file mode 100644 index 7bb3bc8..0000000 --- a/src/libmincrypt/tools/DumpPublicKey.mf +++ /dev/null @@ -1 +0,0 @@ -Main-Class: com.android.dumpkey.DumpPublicKey diff --git a/src/mkbootfs/c/fs_config.c b/src/mkbootfs/c/fs_config.c index 16eca31..e46eb2a 100644 --- a/src/mkbootfs/c/fs_config.c +++ b/src/mkbootfs/c/fs_config.c @@ -34,20 +34,13 @@ #include #include +#include #ifndef O_BINARY #define O_BINARY 0 #endif #define ALOGE printf -/* Used to retry syscalls that can return EINTR. */ -#define TEMP_FAILURE_RETRY(exp) ({ \ - __typeof__(exp) _rc; \ - do { \ - _rc = (exp); \ - } while (_rc == -1 && errno == EINTR); \ - _rc; }) - /* The following structure is stored little endian */ struct fs_path_config_from_file { @@ -84,6 +77,7 @@ static inline uint64_t get8LE(const uint8_t* src) static const struct fs_path_config android_dirs[] = { { 00770, AID_SYSTEM, AID_CACHE, 0, "cache" }, + { 00500, AID_ROOT, AID_ROOT, 0, "config" }, { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app" }, { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private" }, { 00771, AID_ROOT, AID_ROOT, 0, "data/dalvik-cache" }, @@ -95,8 +89,13 @@ static const struct fs_path_config android_dirs[] = { { 00771, AID_SHARED_RELRO, AID_SHARED_RELRO, 0, "data/misc/shared_relro" }, { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" }, { 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" }, + { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest" }, + { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64" }, { 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" }, + { 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" }, + { 00755, AID_ROOT, AID_ROOT, 0, "root" }, { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, + { 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" }, @@ -122,24 +121,26 @@ static const struct fs_path_config android_files[] = { { 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" }, { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" }, { 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" }, + { 00440, AID_ROOT, AID_ROOT, 0, "system/etc/recovery.img" }, { 00444, AID_ROOT, AID_ROOT, 0, conf_dir + 1 }, { 00444, AID_ROOT, AID_ROOT, 0, conf_file + 1 }, { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" }, { 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" }, { 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" }, { 00644, AID_APP, AID_APP, 0, "data/data/*" }, + { 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest/tests.txt" }, + { 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest64/tests.txt" }, + { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest/*" }, + { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64/*" }, - /* the following five files are INTENTIONALLY set-uid, but they + /* the following two files are INTENTIONALLY set-uid, but they * are NOT included on user builds. */ { 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" }, - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" }, { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, - { 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" }, /* the following files have enhanced capabilities and ARE included in user builds. */ - { 00750, AID_ROOT, AID_SHELL, (1ULL << CAP_SETUID) | (1ULL << CAP_SETGID), "system/bin/run-as" }, - { 00700, AID_SYSTEM, AID_SHELL, (1ULL << CAP_BLOCK_SUSPEND), "system/bin/inputflinger" }, + { 00750, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SETUID) | CAP_MASK_LONG(CAP_SETGID), "system/bin/run-as" }, + { 00700, AID_SYSTEM, AID_SHELL, CAP_MASK_LONG(CAP_BLOCK_SUSPEND), "system/bin/inputflinger" }, { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" }, { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" }, @@ -171,8 +172,7 @@ static int fs_config_open(int dir, const char *target_out_path) if (target_out_path[target_out_path_len] == '/') { skip_len++; } - asprintf(&name, "%s%s", target_out_path, (dir ? conf_dir : conf_file) + skip_len); - if (name) { + if (asprintf(&name, "%s%s", target_out_path, (dir ? conf_dir : conf_file) + skip_len) != -1) { fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY)); free(name); } diff --git a/src/mkbootfs/headers/private/android_filesystem_config.h b/src/mkbootfs/headers/private/android_filesystem_config.h index 2ed27dc..e540de2 100644 --- a/src/mkbootfs/headers/private/android_filesystem_config.h +++ b/src/mkbootfs/headers/private/android_filesystem_config.h @@ -26,12 +26,14 @@ #include #include -#ifdef HAVE_ANDROID_OS +#if defined(__ANDROID__) #include #else #include "android_filesystem_capability.h" #endif +#define CAP_MASK_LONG(cap_name) (1ULL << (cap_name)) + /* This is the master Users and Groups config for the platform. * DO NOT EVER RENUMBER */ @@ -77,6 +79,20 @@ #define AID_SDCARD_ALL 1035 /* access all users external storage */ #define AID_LOGD 1036 /* log daemon */ #define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */ +#define AID_DBUS 1038 /* dbus-daemon IPC broker process */ +#define AID_TLSDATE 1039 /* tlsdate unprivileged user */ +#define AID_MEDIA_EX 1040 /* mediaextractor process */ +#define AID_AUDIOSERVER 1041 /* audioserver process */ +#define AID_METRICS_COLL 1042 /* metrics_collector process */ +#define AID_METRICSD 1043 /* metricsd process */ +#define AID_WEBSERV 1044 /* webservd process */ +#define AID_DEBUGGERD 1045 /* debuggerd unprivileged user */ +#define AID_MEDIA_CODEC 1046 /* mediacodec process */ +#define AID_CAMERASERVER 1047 /* cameraserver process */ +#define AID_FIREWALL 1048 /* firewalld process */ +#define AID_TRUNKS 1049 /* trunksd process (TPM daemon) */ +#define AID_NVRAM 1050 /* Access-controlled NVRAM */ +/* Changes to this file must be made in AOSP, *not* in internal branches. */ #define AID_SHELL 2000 /* adb and debug shell user */ #define AID_CACHE 2001 /* cache access */ @@ -97,6 +113,12 @@ #define AID_NET_BW_STATS 3006 /* read bandwidth statistics */ #define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */ #define AID_NET_BT_STACK 3008 /* bluetooth: access config files */ +#define AID_READPROC 3009 /* Allow /proc read access */ +#define AID_WAKELOCK 3010 /* Allow system wakelock read/write access */ + +/* The range 5000-5999 is also reserved for OEM, and must never be used here. */ +#define AID_OEM_RESERVED_2_START 5000 +#define AID_OEM_RESERVED_2_END 5999 #define AID_EVERYBODY 9997 /* shared between all apps in the same profile */ #define AID_MISC 9998 /* access to misc storage */ @@ -168,6 +190,19 @@ static const struct android_id_info android_ids[] = { { "sdcard_all", AID_SDCARD_ALL, }, { "logd", AID_LOGD, }, { "shared_relro", AID_SHARED_RELRO, }, + { "dbus", AID_DBUS, }, + { "tlsdate", AID_TLSDATE, }, + { "mediaex", AID_MEDIA_EX, }, + { "audioserver", AID_AUDIOSERVER, }, + { "metrics_coll", AID_METRICS_COLL }, + { "metricsd", AID_METRICSD }, + { "webserv", AID_WEBSERV }, + { "debuggerd", AID_DEBUGGERD, }, + { "mediacodec", AID_MEDIA_CODEC, }, + { "cameraserver", AID_CAMERASERVER, }, + { "firewall", AID_FIREWALL, }, + { "trunks", AID_TRUNKS, }, + { "nvram", AID_NVRAM, }, { "shell", AID_SHELL, }, { "cache", AID_CACHE, }, @@ -181,6 +216,8 @@ static const struct android_id_info android_ids[] = { { "net_bw_stats", AID_NET_BW_STATS, }, { "net_bw_acct", AID_NET_BW_ACCT, }, { "net_bt_stack", AID_NET_BT_STACK, }, + { "readproc", AID_READPROC, }, + { "wakelock", AID_WAKELOCK, }, { "everybody", AID_EVERYBODY, }, { "misc", AID_MISC, }, diff --git a/src/mkbootfs/headers/utils/Compat.h b/src/mkbootfs/headers/utils/Compat.h new file mode 100644 index 0000000..b2ba55e --- /dev/null +++ b/src/mkbootfs/headers/utils/Compat.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LIB_UTILS_COMPAT_H +#define __LIB_UTILS_COMPAT_H + +#include + +#if defined(__APPLE__) + +/* Mac OS has always had a 64-bit off_t, so it doesn't have off64_t. */ + +typedef off_t off64_t; + +static inline off64_t lseek64(int fd, off64_t offset, int whence) { + return lseek(fd, offset, whence); +} + +static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) { + return pread(fd, buf, nbytes, offset); +} + +static inline ssize_t pwrite64(int fd, const void* buf, size_t nbytes, off64_t offset) { + return pwrite(fd, buf, nbytes, offset); +} + +#endif /* __APPLE__ */ + +#if defined(_WIN32) +#define O_CLOEXEC O_NOINHERIT +#define O_NOFOLLOW 0 +#define DEFFILEMODE 0666 +#endif /* _WIN32 */ + +#if defined(_WIN32) +#define ZD "%ld" +#define ZD_TYPE long +#else +#define ZD "%zd" +#define ZD_TYPE ssize_t +#endif + +/* + * Needed for cases where something should be constexpr if possible, but not + * being constexpr is fine if in pre-C++11 code (such as a const static float + * member variable). + */ +#if __cplusplus >= 201103L +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + +/* + * TEMP_FAILURE_RETRY is defined by some, but not all, versions of + * . (Alas, it is not as standard as we'd hoped!) So, if it's + * not already defined, then define it here. + */ +#ifndef TEMP_FAILURE_RETRY +/* Used to retry syscalls that can return EINTR. */ +#define TEMP_FAILURE_RETRY(exp) ({ \ + typeof (exp) _rc; \ + do { \ + _rc = (exp); \ + } while (_rc == -1 && errno == EINTR); \ + _rc; }) +#endif + +#if defined(_WIN32) +#define OS_PATH_SEPARATOR '\\' +#else +#define OS_PATH_SEPARATOR '/' +#endif + +#endif /* __LIB_UTILS_COMPAT_H */ diff --git a/src/mkbootimg/c/mkbootimg.c b/src/mkbootimg/c/mkbootimg.c deleted file mode 100644 index b6a2801..0000000 --- a/src/mkbootimg/c/mkbootimg.c +++ /dev/null @@ -1,292 +0,0 @@ -/* tools/mkbootimg/mkbootimg.c -** -** Copyright 2007, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "mincrypt/sha.h" -#include "bootimg.h" - -static void *load_file(const char *fn, unsigned *_sz) -{ - char *data; - int sz; - int fd; - - data = 0; - fd = open(fn, O_RDONLY); - if(fd < 0) return 0; - - sz = lseek(fd, 0, SEEK_END); - if(sz < 0) goto oops; - - if(lseek(fd, 0, SEEK_SET) != 0) goto oops; - - data = (char*) malloc(sz); - if(data == 0) goto oops; - - if(read(fd, data, sz) != sz) goto oops; - close(fd); - - if(_sz) *_sz = sz; - return data; - -oops: - close(fd); - if(data != 0) free(data); - return 0; -} - -int usage(void) -{ - fprintf(stderr,"usage: mkbootimg\n" - " --kernel \n" - " [ --ramdisk ]\n" - " [ --second <2ndbootloader-filename> ]\n" - " [ --cmdline ]\n" - " [ --board ]\n" - " [ --base
    ]\n" - " [ --pagesize ]\n" - " [ --id ]\n" - " -o|--output \n" - ); - return 1; -} - - - -static unsigned char padding[16384] = { 0, }; - -static void print_id(const uint8_t *id, size_t id_len) { - printf("0x"); - for (unsigned i = 0; i < id_len; i++) { - printf("%02x", id[i]); - } - printf("\n"); -} - -int write_padding(int fd, unsigned pagesize, unsigned itemsize) -{ - unsigned pagemask = pagesize - 1; - ssize_t count; - - if((itemsize & pagemask) == 0) { - return 0; - } - - count = pagesize - (itemsize & pagemask); - - if(write(fd, padding, count) != count) { - return -1; - } else { - return 0; - } -} - -int main(int argc, char **argv) -{ - boot_img_hdr hdr; - - char *kernel_fn = NULL; - void *kernel_data = NULL; - char *ramdisk_fn = NULL; - void *ramdisk_data = NULL; - char *second_fn = NULL; - void *second_data = NULL; - char *cmdline = ""; - char *bootimg = NULL; - char *board = ""; - uint32_t pagesize = 2048; - int fd; - SHA_CTX ctx; - const uint8_t* sha; - uint32_t base = 0x10000000U; - uint32_t kernel_offset = 0x00008000U; - uint32_t ramdisk_offset = 0x01000000U; - uint32_t second_offset = 0x00f00000U; - uint32_t tags_offset = 0x00000100U; - size_t cmdlen; - - argc--; - argv++; - - memset(&hdr, 0, sizeof(hdr)); - - bool get_id = false; - while(argc > 0){ - char *arg = argv[0]; - if (!strcmp(arg, "--id")) { - get_id = true; - argc -= 1; - argv += 1; - } else if(argc >= 2) { - char *val = argv[1]; - argc -= 2; - argv += 2; - if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) { - bootimg = val; - } else if(!strcmp(arg, "--kernel")) { - kernel_fn = val; - } else if(!strcmp(arg, "--ramdisk")) { - ramdisk_fn = val; - } else if(!strcmp(arg, "--second")) { - second_fn = val; - } else if(!strcmp(arg, "--cmdline")) { - cmdline = val; - } else if(!strcmp(arg, "--base")) { - base = strtoul(val, 0, 16); - } else if(!strcmp(arg, "--kernel_offset")) { - kernel_offset = strtoul(val, 0, 16); - } else if(!strcmp(arg, "--ramdisk_offset")) { - ramdisk_offset = strtoul(val, 0, 16); - } else if(!strcmp(arg, "--second_offset")) { - second_offset = strtoul(val, 0, 16); - } else if(!strcmp(arg, "--tags_offset")) { - tags_offset = strtoul(val, 0, 16); - } else if(!strcmp(arg, "--board")) { - board = val; - } else if(!strcmp(arg,"--pagesize")) { - pagesize = strtoul(val, 0, 10); - if ((pagesize != 2048) && (pagesize != 4096) - && (pagesize != 8192) && (pagesize != 16384)) { - fprintf(stderr,"error: unsupported page size %d\n", pagesize); - return -1; - } - } else { - return usage(); - } - } else { - return usage(); - } - } - hdr.page_size = pagesize; - - hdr.kernel_addr = base + kernel_offset; - hdr.ramdisk_addr = base + ramdisk_offset; - hdr.second_addr = base + second_offset; - hdr.tags_addr = base + tags_offset; - - if(bootimg == 0) { - fprintf(stderr,"error: no output filename specified\n"); - return usage(); - } - - if(kernel_fn == 0) { - fprintf(stderr,"error: no kernel image specified\n"); - return usage(); - } - - if(strlen(board) >= BOOT_NAME_SIZE) { - fprintf(stderr,"error: board name too large\n"); - return usage(); - } - - strcpy((char *) hdr.name, board); - - memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); - - cmdlen = strlen(cmdline); - if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) { - fprintf(stderr,"error: kernel commandline too large\n"); - return 1; - } - /* Even if we need to use the supplemental field, ensure we - * are still NULL-terminated */ - strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1); - hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0'; - if (cmdlen >= (BOOT_ARGS_SIZE - 1)) { - cmdline += (BOOT_ARGS_SIZE - 1); - strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE); - } - - kernel_data = load_file(kernel_fn, &hdr.kernel_size); - if(kernel_data == 0) { - fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn); - return 1; - } - - if(ramdisk_fn == 0) { - ramdisk_data = 0; - hdr.ramdisk_size = 0; - } else { - ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size); - if(ramdisk_data == 0) { - fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn); - return 1; - } - } - - if(second_fn) { - second_data = load_file(second_fn, &hdr.second_size); - if(second_data == 0) { - fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn); - return 1; - } - } - - /* put a hash of the contents in the header so boot images can be - * differentiated based on their first 2k. - */ - SHA_init(&ctx); - SHA_update(&ctx, kernel_data, hdr.kernel_size); - SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size)); - SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size); - SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size)); - SHA_update(&ctx, second_data, hdr.second_size); - SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size)); - sha = SHA_final(&ctx); - memcpy(hdr.id, sha, - SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); - - fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644); - if(fd < 0) { - fprintf(stderr,"error: could not create '%s'\n", bootimg); - return 1; - } - - if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; - if(write_padding(fd, pagesize, sizeof(hdr))) goto fail; - - if(write(fd, kernel_data, hdr.kernel_size) != (ssize_t) hdr.kernel_size) goto fail; - if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail; - - if(write(fd, ramdisk_data, hdr.ramdisk_size) != (ssize_t) hdr.ramdisk_size) goto fail; - if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; - - if(second_data) { - if(write(fd, second_data, hdr.second_size) != (ssize_t) hdr.second_size) goto fail; - if(write_padding(fd, pagesize, hdr.second_size)) goto fail; - } - - if (get_id) { - print_id((uint8_t *) hdr.id, sizeof(hdr.id)); - } - - return 0; - -fail: - unlink(bootimg); - close(fd); - fprintf(stderr,"error: failed writing '%s': %s\n", bootimg, - strerror(errno)); - return 1; -} diff --git a/src/mkbootimg/headers/bootimg.h b/src/mkbootimg/headers/bootimg.h deleted file mode 100644 index 5ab6195..0000000 --- a/src/mkbootimg/headers/bootimg.h +++ /dev/null @@ -1,104 +0,0 @@ -/* tools/mkbootimg/bootimg.h -** -** Copyright 2007, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include - -#ifndef _BOOT_IMAGE_H_ -#define _BOOT_IMAGE_H_ - -typedef struct boot_img_hdr boot_img_hdr; - -#define BOOT_MAGIC "ANDROID!" -#define BOOT_MAGIC_SIZE 8 -#define BOOT_NAME_SIZE 16 -#define BOOT_ARGS_SIZE 512 -#define BOOT_EXTRA_ARGS_SIZE 1024 - -struct boot_img_hdr -{ - uint8_t magic[BOOT_MAGIC_SIZE]; - - uint32_t kernel_size; /* size in bytes */ - uint32_t kernel_addr; /* physical load addr */ - - uint32_t ramdisk_size; /* size in bytes */ - uint32_t ramdisk_addr; /* physical load addr */ - - uint32_t second_size; /* size in bytes */ - uint32_t second_addr; /* physical load addr */ - - uint32_t tags_addr; /* physical addr for kernel tags */ - uint32_t page_size; /* flash page size we assume */ - uint32_t unused[2]; /* future expansion: should be 0 */ - - uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */ - - uint8_t cmdline[BOOT_ARGS_SIZE]; - - uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ - - /* Supplemental command line data; kept here to maintain - * binary compatibility with older versions of mkbootimg */ - uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE]; -} __attribute__((packed)); - -/* -** +-----------------+ -** | boot header | 1 page -** +-----------------+ -** | kernel | n pages -** +-----------------+ -** | ramdisk | m pages -** +-----------------+ -** | second stage | o pages -** +-----------------+ -** -** n = (kernel_size + page_size - 1) / page_size -** m = (ramdisk_size + page_size - 1) / page_size -** o = (second_size + page_size - 1) / page_size -** -** 0. all entities are page_size aligned in flash -** 1. kernel and ramdisk are required (size != 0) -** 2. second is optional (second_size == 0 -> no second) -** 3. load each element (kernel, ramdisk, second) at -** the specified physical address (kernel_addr, etc) -** 4. prepare tags at tag_addr. kernel_args[] is -** appended to the kernel commandline in the tags. -** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr -** 6. if second_size != 0: jump to second_addr -** else: jump to kernel_addr -*/ - -#if 0 -typedef struct ptentry ptentry; - -struct ptentry { - char name[16]; /* asciiz partition name */ - unsigned start; /* starting block number */ - unsigned length; /* length in blocks */ - unsigned flags; /* set to zero */ -}; - -/* MSM Partition Table ATAG -** -** length: 2 + 7 * n -** atag: 0x4d534d70 -** x n -*/ -#endif - -#endif diff --git a/src/mkbootimg/mkbootimg b/src/mkbootimg/mkbootimg new file mode 100755 index 0000000..5a13da2 --- /dev/null +++ b/src/mkbootimg/mkbootimg @@ -0,0 +1,175 @@ +#!/usr/bin/env python +# Copyright 2015, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function +from sys import argv, exit, stderr +from argparse import ArgumentParser, FileType, Action +from os import fstat +from struct import pack +from hashlib import sha1 +import sys +import re + +def filesize(f): + if f is None: + return 0 + try: + return fstat(f.fileno()).st_size + except OSError: + return 0 + + +def update_sha(sha, f): + if f: + sha.update(f.read()) + f.seek(0) + sha.update(pack('I', filesize(f))) + else: + sha.update(pack('I', 0)) + + +def pad_file(f, padding): + pad = (padding - (f.tell() & (padding - 1))) & (padding - 1) + f.write(pack(str(pad) + 'x')) + + +def write_header(args): + BOOT_MAGIC = 'ANDROID!'.encode() + args.output.write(pack('8s', BOOT_MAGIC)) + args.output.write(pack('10I', + filesize(args.kernel), # size in bytes + args.base + args.kernel_offset, # physical load addr + filesize(args.ramdisk), # size in bytes + args.base + args.ramdisk_offset, # physical load addr + filesize(args.second), # size in bytes + args.base + args.second_offset, # physical load addr + args.base + args.tags_offset, # physical addr for kernel tags + args.pagesize, # flash page size we assume + 0, # future expansion: MUST be 0 + (args.os_version << 11) | args.os_patch_level)) # os version and patch level + args.output.write(pack('16s', args.board.encode())) # asciiz product name + args.output.write(pack('512s', args.cmdline[:512].encode())) + + sha = sha1() + update_sha(sha, args.kernel) + update_sha(sha, args.ramdisk) + update_sha(sha, args.second) + img_id = pack('32s', sha.digest()) + + args.output.write(img_id) + args.output.write(pack('1024s', args.cmdline[512:].encode())) + pad_file(args.output, args.pagesize) + return img_id + + +class ValidateStrLenAction(Action): + def __init__(self, option_strings, dest, nargs=None, **kwargs): + if 'maxlen' not in kwargs: + raise ValueError('maxlen must be set') + self.maxlen = int(kwargs['maxlen']) + del kwargs['maxlen'] + super(ValidateStrLenAction, self).__init__(option_strings, dest, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + if len(values) > self.maxlen: + raise ValueError('String argument too long: max {0:d}, got {1:d}'. + format(self.maxlen, len(values))) + setattr(namespace, self.dest, values) + + +def write_padded_file(f_out, f_in, padding): + if f_in is None: + return + f_out.write(f_in.read()) + pad_file(f_out, padding) + + +def parse_int(x): + return int(x, 0) + +def parse_os_version(x): + match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x) + if match: + a = int(match.group(1)) + b = c = 0 + if match.lastindex >= 2: + b = int(match.group(2)) + if match.lastindex == 3: + c = int(match.group(3)) + # 7 bits allocated for each field + assert a < 128 + assert b < 128 + assert c < 128 + return (a << 14) | (b << 7) | c + return 0 + +def parse_os_patch_level(x): + match = re.search(r'^(\d{4})-(\d{2})-(\d{2})', x) + if match: + y = int(match.group(1)) - 2000 + m = int(match.group(2)) + # 7 bits allocated for the year, 4 bits for the month + assert y >= 0 and y < 128 + assert m > 0 and m <= 12 + return (y << 4) | m + return 0 + +def parse_cmdline(): + parser = ArgumentParser() + parser.add_argument('--kernel', help='path to the kernel', type=FileType('rb'), + required=True) + parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb')) + parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb')) + parser.add_argument('--cmdline', help='extra arguments to be passed on the ' + 'kernel command line', default='', action=ValidateStrLenAction, maxlen=1536) + parser.add_argument('--base', help='base address', type=parse_int, default=0x10000000) + parser.add_argument('--kernel_offset', help='kernel offset', type=parse_int, default=0x00008000) + parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int, default=0x01000000) + parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int, + default=0x00f00000) + parser.add_argument('--os_version', help='operating system version', type=parse_os_version, + default=0) + parser.add_argument('--os_patch_level', help='operating system patch level', + type=parse_os_patch_level, default=0) + parser.add_argument('--tags_offset', help='tags offset', type=parse_int, default=0x00000100) + parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction, + maxlen=16) + parser.add_argument('--pagesize', help='page size', type=parse_int, + choices=[2**i for i in range(11,15)], default=2048) + parser.add_argument('--id', help='print the image ID on standard output', + action='store_true') + parser.add_argument('-o', '--output', help='output file name', type=FileType('wb'), + required=True) + return parser.parse_args() + + +def write_data(args): + write_padded_file(args.output, args.kernel, args.pagesize) + write_padded_file(args.output, args.ramdisk, args.pagesize) + write_padded_file(args.output, args.second, args.pagesize) + + +def main(): + args = parse_cmdline() + img_id = write_header(args) + write_data(args) + if args.id: + if isinstance(img_id, str): + # Python 2's struct.pack returns a string, but py3 returns bytes. + img_id = [ord(x) for x in img_id] + print('0x' + ''.join('{:02x}'.format(c) for c in img_id)) + +if __name__ == '__main__': + main()