summaryrefslogtreecommitdiffstats
path: root/bcprov/src/main
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2012-09-17 16:04:47 -0700
committerBrian Carlstrom <bdc@google.com>2012-09-19 14:26:13 -0700
commite6bf3e8dfa2804891a82075cb469b736321b4827 (patch)
tree8d78ebadb9c33191a0490537dbd50da4e6c85b49 /bcprov/src/main
parent517da5b1cf8927b100e5e1d9df870854b09aa2ce (diff)
downloadandroid_external_bouncycastle-e6bf3e8dfa2804891a82075cb469b736321b4827.tar.gz
android_external_bouncycastle-e6bf3e8dfa2804891a82075cb469b736321b4827.tar.bz2
android_external_bouncycastle-e6bf3e8dfa2804891a82075cb469b736321b4827.zip
Make existing bouncycastle bcprov build on host and add host-only bcpkix build
- Move existing provider source to bcprov - Added bcpkix host build to support built/tooks/signapk sha1sum of sources: - 10bfea344842fe8e065c80e399c93f8651dc87d8 bcprov-jdk15on-147.tar.gz - 913828c7ae36e030508e97e07b3c213fb1db1e9c bcpkix-jdk15on-147.tar.gz Bug: 7056297 Change-Id: Id4f957f300a39aa34b4c3c679b2312631d3f1639
Diffstat (limited to 'bcprov/src/main')
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java14
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Exception.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Generator.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java466
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java66
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Object.java97
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java37
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java146
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java194
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java69
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java323
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java464
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java247
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java6
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java236
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java41
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java144
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERFactory.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERGenerator.java100
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BEROctetString.java168
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java102
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java41
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java73
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java73
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERSetParser.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java147
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java66
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java111
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java276
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java141
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java312
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java183
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java146
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java294
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java52
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERFactory.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java98
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java338
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java171
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java136
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERNull.java37
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java174
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java383
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DEROctetString.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java39
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DEROutputStream.java41
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java203
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java98
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java108
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERSetParser.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java123
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java118
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERTags.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERUTCTime.java266
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERUTF8String.java120
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java136
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DERVisibleString.java123
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DLOutputStream.java31
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java98
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java101
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java112
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java106
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java111
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java43
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java109
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java32
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/StreamUtil.java112
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java51
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java100
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java248
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java49
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java13
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java99
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java107
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java302
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java98
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java183
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java128
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java55
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java180
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java47
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java54
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java96
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java56
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java31
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java74
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java82
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java66
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java91
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java148
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java102
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java104
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java115
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java89
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java55
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java85
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java106
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java73
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java77
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java72
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java108
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java69
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java267
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java87
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java160
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java153
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java187
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java189
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java95
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java174
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java96
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java166
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java143
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java128
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java1029
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java50
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java42
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java429
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java72
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java125
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java119
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java326
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java81
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java34
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java33
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java544
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java301
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java443
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java99
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java173
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java91
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java84
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/Attribute.java93
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java94
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java166
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java233
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java164
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java100
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java54
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java152
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/Certificate.java131
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java127
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java92
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java86
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java158
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java138
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java123
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java266
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java214
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java94
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java439
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java102
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java218
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java245
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java106
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java282
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java119
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java77
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java118
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java191
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java87
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java98
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java85
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java134
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java155
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java309
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java192
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java194
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/Time.java133
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java144
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/V2Form.java130
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java212
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java129
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java65
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java248
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java489
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java117
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java1286
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java113
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java110
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java67
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java139
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java52
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java80
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java621
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java86
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java161
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java176
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java64
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java109
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java47
-rw-r--r--bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java132
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricBlockCipher.java45
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java44
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/BasicAgreement.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/BlockCipher.java56
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java313
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/CipherKeyGenerator.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/CipherParameters.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/CryptoException.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/DSA.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/DataLengthException.java29
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/DerivationParameters.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/Digest.java51
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/ExtendedDigest.java13
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/KeyGenerationParameters.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/Mac.java71
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java159
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/RuntimeCryptoException.java26
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/Signer.java43
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java34
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java108
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java53
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/Wrapper.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java66
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java47
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactory.java78
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java37
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java27
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java37
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java135
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java354
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java302
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java159
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java290
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java295
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java87
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java89
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java352
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java253
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java547
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java876
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/BlowfishEngine.java576
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java494
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java126
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java352
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/RC2Engine.java316
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java143
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java177
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java126
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java203
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/engines/TwofishEngine.java679
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DESKeyGenerator.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java56
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java42
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java51
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java52
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java93
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java61
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java342
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java53
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java135
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java221
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java119
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java162
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java147
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java244
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java188
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java52
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java42
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java52
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java42
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java229
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java207
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java108
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java253
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java338
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java254
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java265
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java421
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java183
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java124
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java155
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java99
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/paddings/BlockCipherPadding.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java79
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java77
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java76
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java298
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/paddings/TBCPadding.java89
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/paddings/X923Padding.java80
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/paddings/ZeroBytePadding.java73
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DESParameters.java107
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java57
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java30
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DHKeyParameters.java54
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java189
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java41
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java41
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java50
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DSAKeyParameters.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DSAParameters.java74
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java23
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java50
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java81
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ECKeyParameters.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/KeyParameter.java30
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithIV.java39
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java31
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java67
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java138
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java163
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java238
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java100
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java180
-rw-r--r--bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java217
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java88
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java55
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java96
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java96
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java38
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java68
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java99
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java217
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/X509.java33
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java77
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java142
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java214
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java204
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java50
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java211
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java128
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java106
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java72
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java133
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java168
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java171
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java288
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java72
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java117
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java82
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java500
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java443
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/EC5Util.java123
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java237
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java337
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java240
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java329
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java352
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java273
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java243
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java142
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java131
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java589
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java389
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java162
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java78
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java66
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java220
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java82
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java112
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java13
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java72
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java125
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java397
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java95
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java93
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java376
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java41
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java146
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java47
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java36
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java72
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java76
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java73
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java73
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java74
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java295
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java58
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java77
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java316
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java423
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java151
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java19
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java385
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java921
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java83
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java463
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java196
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java366
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java406
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java118
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java306
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java68
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java8
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java42
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java156
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java125
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java687
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/PrincipalUtil.java81
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java164
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/exception/ExtCertPathBuilderException.java29
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/exception/ExtCertPathValidatorException.java30
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/exception/ExtException.java21
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/interfaces/BCKeyStore.java14
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECKey.java15
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPointEncoder.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPrivateKey.java16
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPublicKey.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java22
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java296
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java32
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java628
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java146
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java216
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java1435
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/CertStatus.java46
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java104
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/DHUtil.java50
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/ExtCRLException.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java1103
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java188
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java178
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java484
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java532
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCEMac.java455
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java243
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java149
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java133
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java612
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java532
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java320
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java181
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java177
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java1048
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java1658
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java48
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/PEMUtil.java94
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java155
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java261
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java462
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java1924
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java168
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java2569
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/ReasonsMask.java101
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java296
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java576
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java826
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java148
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/spec/ECKeySpec.java26
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java28
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java62
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java121
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java121
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/spec/ECPrivateKeySpec.java35
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java35
-rw-r--r--bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java34
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java92
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/ECConstants.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java668
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java1196
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java19
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java588
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java39
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java518
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java253
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java844
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java240
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java44
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java119
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java39
-rw-r--r--bcprov/src/main/java/org/bouncycastle/math/ec/ZTauElement.java37
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/Arrays.java532
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java78
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/CollectionStore.java57
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/IPAddress.java188
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/Selector.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/Store.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/StoreException.java18
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/Strings.java303
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/encoders/Base64.java121
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java298
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/encoders/Encoder.java17
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/encoders/Hex.java131
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java172
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/StreamOverflowException.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/Streams.java87
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/TeeInputStream.java62
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java52
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java25
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java66
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObject.java61
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java7
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java9
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java84
-rw-r--r--bcprov/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java137
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java420
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java208
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages.properties616
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/ExtCertificateEncodingException.java20
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java210
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java651
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/NoSuchStoreException.java10
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/PKIXAttrCertChecker.java56
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509Attribute.java79
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java101
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java330
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509CertStoreSelector.java87
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509CollectionStoreParameters.java70
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509Store.java79
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509StoreParameters.java5
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509StoreSpi.java12
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509Util.java450
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java377
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java350
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java527
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java152
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java53
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java102
562 files changed, 93113 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
new file mode 100644
index 0000000..d7216a6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ApplicationSpecificParser.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public interface ASN1ApplicationSpecificParser
+ extends ASN1Encodable, InMemoryRepresentable
+{
+ ASN1Encodable readObject()
+ throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java
new file mode 100644
index 0000000..1360e8b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java
@@ -0,0 +1,15 @@
+package org.bouncycastle.asn1;
+
+public class ASN1Boolean
+ extends DERBoolean
+{
+ public ASN1Boolean(boolean value)
+ {
+ super(value);
+ }
+
+ ASN1Boolean(byte[] value)
+ {
+ super(value);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java
new file mode 100644
index 0000000..603131d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Choice.java
@@ -0,0 +1,14 @@
+package org.bouncycastle.asn1;
+
+/**
+ * Marker interface for CHOICE objects - if you implement this in a role your
+ * own object any attempt to tag the object implicitly will convert the tag to
+ * an explicit one as the encoding rules require.
+ * <p>
+ * If you use this interface your class should also implement the getInstance
+ * pattern which takes a tag object and the tagging mode used.
+ */
+public interface ASN1Choice
+{
+ // marker interface
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java
new file mode 100644
index 0000000..f5738bf
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encodable.java
@@ -0,0 +1,6 @@
+package org.bouncycastle.asn1;
+
+public interface ASN1Encodable
+{
+ ASN1Primitive toASN1Primitive();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
new file mode 100644
index 0000000..2aa68b3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java
@@ -0,0 +1,27 @@
+package org.bouncycastle.asn1;
+
+import java.util.Vector;
+
+public class ASN1EncodableVector
+{
+ Vector v = new Vector();
+
+ public ASN1EncodableVector()
+ {
+ }
+
+ public void add(ASN1Encodable obj)
+ {
+ v.addElement(obj);
+ }
+
+ public ASN1Encodable get(int i)
+ {
+ return (ASN1Encodable)v.elementAt(i);
+ }
+
+ public int size()
+ {
+ return v.size();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java
new file mode 100644
index 0000000..821d3b9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Encoding.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.asn1;
+
+public interface ASN1Encoding
+{
+ static final String DER = "DER";
+ static final String DL = "DL";
+ static final String BER = "BER";
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
new file mode 100644
index 0000000..d93fd91
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1;
+
+import java.math.BigInteger;
+
+public class ASN1Enumerated
+ extends DEREnumerated
+{
+ ASN1Enumerated(byte[] bytes)
+ {
+ super(bytes);
+ }
+
+ public ASN1Enumerated(BigInteger value)
+ {
+ super(value);
+ }
+
+ public ASN1Enumerated(int value)
+ {
+ super(value);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Exception.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Exception.java
new file mode 100644
index 0000000..dc0ee20
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Exception.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class ASN1Exception
+ extends IOException
+{
+ private Throwable cause;
+
+ ASN1Exception(String message)
+ {
+ super(message);
+ }
+
+ ASN1Exception(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java
new file mode 100644
index 0000000..0088a53
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1;
+
+import java.util.Date;
+
+public class ASN1GeneralizedTime
+ extends DERGeneralizedTime
+{
+ ASN1GeneralizedTime(byte[] bytes)
+ {
+ super(bytes);
+ }
+
+ public ASN1GeneralizedTime(Date time)
+ {
+ super(time);
+ }
+
+ public ASN1GeneralizedTime(String time)
+ {
+ super(time);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Generator.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Generator.java
new file mode 100644
index 0000000..50cb705
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Generator.java
@@ -0,0 +1,15 @@
+package org.bouncycastle.asn1;
+
+import java.io.OutputStream;
+
+public abstract class ASN1Generator
+{
+ protected OutputStream _out;
+
+ public ASN1Generator(OutputStream out)
+ {
+ _out = out;
+ }
+
+ public abstract OutputStream getRawOutputStream();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
new file mode 100644
index 0000000..4471433
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
@@ -0,0 +1,466 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.util.io.Streams;
+
+/**
+ * a general purpose ASN.1 decoder - note: this class differs from the
+ * others in that it returns null after it has read the last object in
+ * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
+ * returned.
+ */
+public class ASN1InputStream
+ extends FilterInputStream
+ implements BERTags
+{
+ private final int limit;
+ private final boolean lazyEvaluate;
+
+ private final byte[][] tmpBuffers;
+
+ public ASN1InputStream(
+ InputStream is)
+ {
+ this(is, StreamUtil.findLimit(is));
+ }
+
+ /**
+ * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+ * the stream is automatically limited to the length of the input array.
+ *
+ * @param input array containing ASN.1 encoded data.
+ */
+ public ASN1InputStream(
+ byte[] input)
+ {
+ this(new ByteArrayInputStream(input), input.length);
+ }
+
+ /**
+ * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+ * the stream is automatically limited to the length of the input array.
+ *
+ * @param input array containing ASN.1 encoded data.
+ * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+ */
+ public ASN1InputStream(
+ byte[] input,
+ boolean lazyEvaluate)
+ {
+ this(new ByteArrayInputStream(input), input.length, lazyEvaluate);
+ }
+
+ /**
+ * Create an ASN1InputStream where no DER object will be longer than limit.
+ *
+ * @param input stream containing ASN.1 encoded data.
+ * @param limit maximum size of a DER encoded object.
+ */
+ public ASN1InputStream(
+ InputStream input,
+ int limit)
+ {
+ this(input, limit, false);
+ }
+
+ /**
+ * Create an ASN1InputStream where no DER object will be longer than limit, and constructed
+ * objects such as sequences will be parsed lazily.
+ *
+ * @param input stream containing ASN.1 encoded data.
+ * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+ */
+ public ASN1InputStream(
+ InputStream input,
+ boolean lazyEvaluate)
+ {
+ this(input, StreamUtil.findLimit(input), lazyEvaluate);
+ }
+
+ /**
+ * Create an ASN1InputStream where no DER object will be longer than limit, and constructed
+ * objects such as sequences will be parsed lazily.
+ *
+ * @param input stream containing ASN.1 encoded data.
+ * @param limit maximum size of a DER encoded object.
+ * @param lazyEvaluate true if parsing inside constructed objects can be delayed.
+ */
+ public ASN1InputStream(
+ InputStream input,
+ int limit,
+ boolean lazyEvaluate)
+ {
+ super(input);
+ this.limit = limit;
+ this.lazyEvaluate = lazyEvaluate;
+ this.tmpBuffers = new byte[11][];
+ }
+
+ int getLimit()
+ {
+ return limit;
+ }
+
+ protected int readLength()
+ throws IOException
+ {
+ return readLength(this, limit);
+ }
+
+ protected void readFully(
+ byte[] bytes)
+ throws IOException
+ {
+ if (Streams.readFully(this, bytes) != bytes.length)
+ {
+ throw new EOFException("EOF encountered in middle of object");
+ }
+ }
+
+ /**
+ * build an object given its tag and the number of bytes to construct it from.
+ */
+ protected ASN1Primitive buildObject(
+ int tag,
+ int tagNo,
+ int length)
+ throws IOException
+ {
+ boolean isConstructed = (tag & CONSTRUCTED) != 0;
+
+ DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(this, length);
+
+ if ((tag & APPLICATION) != 0)
+ {
+ return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
+ }
+
+ if ((tag & TAGGED) != 0)
+ {
+ return new ASN1StreamParser(defIn).readTaggedObject(isConstructed, tagNo);
+ }
+
+ if (isConstructed)
+ {
+ // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+ switch (tagNo)
+ {
+ case OCTET_STRING:
+ //
+ // yes, people actually do this...
+ //
+ ASN1EncodableVector v = buildDEREncodableVector(defIn);
+ ASN1OctetString[] strings = new ASN1OctetString[v.size()];
+
+ for (int i = 0; i != strings.length; i++)
+ {
+ strings[i] = (ASN1OctetString)v.get(i);
+ }
+
+ return new BEROctetString(strings);
+ case SEQUENCE:
+ if (lazyEvaluate)
+ {
+ return new LazyEncodedSequence(defIn.toByteArray());
+ }
+ else
+ {
+ return DERFactory.createSequence(buildDEREncodableVector(defIn));
+ }
+ case SET:
+ return DERFactory.createSet(buildDEREncodableVector(defIn));
+ case EXTERNAL:
+ return new DERExternal(buildDEREncodableVector(defIn));
+ default:
+ throw new IOException("unknown tag " + tagNo + " encountered");
+ }
+ }
+
+ return createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
+ }
+
+ ASN1EncodableVector buildEncodableVector()
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ ASN1Primitive o;
+
+ while ((o = readObject()) != null)
+ {
+ v.add(o);
+ }
+
+ return v;
+ }
+
+ ASN1EncodableVector buildDEREncodableVector(
+ DefiniteLengthInputStream dIn) throws IOException
+ {
+ return new ASN1InputStream(dIn).buildEncodableVector();
+ }
+
+ public ASN1Primitive readObject()
+ throws IOException
+ {
+ int tag = read();
+ if (tag <= 0)
+ {
+ if (tag == 0)
+ {
+ throw new IOException("unexpected end-of-contents marker");
+ }
+
+ return null;
+ }
+
+ //
+ // calculate tag number
+ //
+ int tagNo = readTagNumber(this, tag);
+
+ boolean isConstructed = (tag & CONSTRUCTED) != 0;
+
+ //
+ // calculate length
+ //
+ int length = readLength();
+
+ if (length < 0) // indefinite length method
+ {
+ if (!isConstructed)
+ {
+ throw new IOException("indefinite length primitive encoding encountered");
+ }
+
+ IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(this, limit);
+ ASN1StreamParser sp = new ASN1StreamParser(indIn, limit);
+
+ if ((tag & APPLICATION) != 0)
+ {
+ return new BERApplicationSpecificParser(tagNo, sp).getLoadedObject();
+ }
+
+ if ((tag & TAGGED) != 0)
+ {
+ return new BERTaggedObjectParser(true, tagNo, sp).getLoadedObject();
+ }
+
+ // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+ switch (tagNo)
+ {
+ case OCTET_STRING:
+ return new BEROctetStringParser(sp).getLoadedObject();
+ case SEQUENCE:
+ return new BERSequenceParser(sp).getLoadedObject();
+ case SET:
+ return new BERSetParser(sp).getLoadedObject();
+ case EXTERNAL:
+ return new DERExternalParser(sp).getLoadedObject();
+ default:
+ throw new IOException("unknown BER object encountered");
+ }
+ }
+ else
+ {
+ try
+ {
+ return buildObject(tag, tagNo, length);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ASN1Exception("corrupted stream detected", e);
+ }
+ }
+ }
+
+ static int readTagNumber(InputStream s, int tag)
+ throws IOException
+ {
+ int tagNo = tag & 0x1f;
+
+ //
+ // with tagged object tag number is bottom 5 bits, or stored at the start of the content
+ //
+ if (tagNo == 0x1f)
+ {
+ tagNo = 0;
+
+ int b = s.read();
+
+ // 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 IOException("corrupted stream - invalid high tag number found");
+ }
+
+ while ((b >= 0) && ((b & 0x80) != 0))
+ {
+ tagNo |= (b & 0x7f);
+ tagNo <<= 7;
+ b = s.read();
+ }
+
+ if (b < 0)
+ {
+ throw new EOFException("EOF found inside tag value.");
+ }
+
+ tagNo |= (b & 0x7f);
+ }
+
+ return tagNo;
+ }
+
+ static int readLength(InputStream s, int limit)
+ throws IOException
+ {
+ int length = s.read();
+ if (length < 0)
+ {
+ throw new EOFException("EOF found when length expected");
+ }
+
+ if (length == 0x80)
+ {
+ return -1; // 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 IOException("DER length more than 4 bytes: " + size);
+ }
+
+ length = 0;
+ for (int i = 0; i < size; i++)
+ {
+ int next = s.read();
+
+ if (next < 0)
+ {
+ throw new EOFException("EOF found reading length");
+ }
+
+ length = (length << 8) + next;
+ }
+
+ if (length < 0)
+ {
+ throw new IOException("corrupted stream - negative length found");
+ }
+
+ if (length >= limit) // after all we must have read at least 1 byte
+ {
+ throw new IOException("corrupted stream - out of bounds length found");
+ }
+ }
+
+ return length;
+ }
+
+ private static byte[] getBuffer(DefiniteLengthInputStream defIn, byte[][] tmpBuffers)
+ throws IOException
+ {
+ int len = defIn.getRemaining();
+ if (defIn.getRemaining() < tmpBuffers.length)
+ {
+ byte[] buf = tmpBuffers[len];
+
+ if (buf == null)
+ {
+ buf = tmpBuffers[len] = new byte[len];
+ }
+
+ Streams.readFully(defIn, buf);
+
+ return buf;
+ }
+ else
+ {
+ return defIn.toByteArray();
+ }
+ }
+
+ private static char[] getBMPCharBuffer(DefiniteLengthInputStream defIn)
+ throws IOException
+ {
+ int len = defIn.getRemaining() / 2;
+ char[] buf = new char[len];
+ int totalRead = 0;
+ while (totalRead < len)
+ {
+ int ch1 = defIn.read();
+ if (ch1 < 0)
+ {
+ break;
+ }
+ int ch2 = defIn.read();
+ if (ch2 < 0)
+ {
+ break;
+ }
+ buf[totalRead++] = (char)((ch1 << 8) | (ch2 & 0xff));
+ }
+
+ return buf;
+ }
+
+ static ASN1Primitive createPrimitiveDERObject(
+ int tagNo,
+ DefiniteLengthInputStream defIn,
+ byte[][] tmpBuffers)
+ throws IOException
+ {
+ switch (tagNo)
+ {
+ case BIT_STRING:
+ return DERBitString.fromInputStream(defIn.getRemaining(), defIn);
+ case BMP_STRING:
+ return new DERBMPString(getBMPCharBuffer(defIn));
+ case BOOLEAN:
+ return ASN1Boolean.fromOctetString(getBuffer(defIn, tmpBuffers));
+ case ENUMERATED:
+ return ASN1Enumerated.fromOctetString(getBuffer(defIn, tmpBuffers));
+ case GENERALIZED_TIME:
+ return new ASN1GeneralizedTime(defIn.toByteArray());
+ case GENERAL_STRING:
+ return new DERGeneralString(defIn.toByteArray());
+ case IA5_STRING:
+ return new DERIA5String(defIn.toByteArray());
+ case INTEGER:
+ return new ASN1Integer(defIn.toByteArray());
+ case NULL:
+ return DERNull.INSTANCE; // actual content is ignored (enforce 0 length?)
+ case NUMERIC_STRING:
+ return new DERNumericString(defIn.toByteArray());
+ case OBJECT_IDENTIFIER:
+ return ASN1ObjectIdentifier.fromOctetString(getBuffer(defIn, tmpBuffers));
+ case OCTET_STRING:
+ return new DEROctetString(defIn.toByteArray());
+ case PRINTABLE_STRING:
+ return new DERPrintableString(defIn.toByteArray());
+ case T61_STRING:
+ return new DERT61String(defIn.toByteArray());
+ case UNIVERSAL_STRING:
+ return new DERUniversalString(defIn.toByteArray());
+ case UTC_TIME:
+ return new ASN1UTCTime(defIn.toByteArray());
+ case UTF8_STRING:
+ return new DERUTF8String(defIn.toByteArray());
+ case VISIBLE_STRING:
+ return new DERVisibleString(defIn.toByteArray());
+ default:
+ throw new IOException("unknown tag " + tagNo + " encountered");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
new file mode 100644
index 0000000..71009a0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Integer.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1;
+
+import java.math.BigInteger;
+
+public class ASN1Integer
+ extends DERInteger
+{
+ ASN1Integer(byte[] bytes)
+ {
+ super(bytes);
+ }
+
+ public ASN1Integer(BigInteger value)
+ {
+ super(value);
+ }
+
+ public ASN1Integer(int value)
+ {
+ super(value);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java
new file mode 100644
index 0000000..5b52da8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Null.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A NULL object.
+ */
+public abstract class ASN1Null
+ extends ASN1Primitive
+{
+ // BEGIN android-changed
+ /*package*/ ASN1Null()
+ {
+ }
+ // END android-changed
+
+ public static ASN1Null getInstance(Object o)
+ {
+ if (o instanceof ASN1Null)
+ {
+ return (ASN1Null)o;
+ }
+
+ if (o != null)
+ {
+ try
+ {
+ return ASN1Null.getInstance(ASN1Primitive.fromByteArray((byte[])o));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("failed to construct NULL from byte[]: " + e.getMessage());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException("unknown object in getInstance(): " + o.getClass().getName());
+ }
+ }
+
+ return null;
+ }
+
+ public int hashCode()
+ {
+ return -1;
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof ASN1Null))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ abstract void encode(ASN1OutputStream out)
+ throws IOException;
+
+ public String toString()
+ {
+ return "NULL";
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Object.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Object.java
new file mode 100644
index 0000000..956fb7d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Object.java
@@ -0,0 +1,97 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public abstract class ASN1Object
+ implements ASN1Encodable
+{
+ /**
+ * Return the default BER or DER encoding for this object.
+ *
+ * @return BER/DER byte encoded object.
+ * @throws java.io.IOException on encoding error.
+ */
+ public byte[] getEncoded()
+ throws IOException
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(this);
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Return either the default for "BER" or a DER encoding if "DER" is specified.
+ *
+ * @param encoding name of encoding to use.
+ * @return byte encoded object.
+ * @throws IOException on encoding error.
+ */
+ public byte[] getEncoded(
+ String encoding)
+ throws IOException
+ {
+ if (encoding.equals(ASN1Encoding.DER))
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(this);
+
+ return bOut.toByteArray();
+ }
+ else if (encoding.equals(ASN1Encoding.DL))
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DLOutputStream dOut = new DLOutputStream(bOut);
+
+ dOut.writeObject(this);
+
+ return bOut.toByteArray();
+ }
+
+ return this.getEncoded();
+ }
+
+ public int hashCode()
+ {
+ return this.toASN1Primitive().hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+
+ if (!(o instanceof ASN1Encodable))
+ {
+ return false;
+ }
+
+ ASN1Encodable other = (ASN1Encodable)o;
+
+ return this.toASN1Primitive().equals(other.toASN1Primitive());
+ }
+
+ /**
+ * @deprecated use toASN1Primitive()
+ * @return the underlying primitive type.
+ */
+ public ASN1Primitive toASN1Object()
+ {
+ return this.toASN1Primitive();
+ }
+
+ protected static boolean hasEncodedTagValue(Object obj, int tagValue)
+ {
+ return (obj instanceof byte[]) && ((byte[])obj)[0] == tagValue;
+ }
+
+ public abstract ASN1Primitive toASN1Primitive();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
new file mode 100644
index 0000000..eb29838
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.asn1;
+
+public class ASN1ObjectIdentifier
+ extends DERObjectIdentifier
+{
+ public ASN1ObjectIdentifier(String identifier)
+ {
+ super(identifier);
+ }
+
+ ASN1ObjectIdentifier(byte[] bytes)
+ {
+ super(bytes);
+ }
+
+ /**
+ * Return 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.
+ */
+ public ASN1ObjectIdentifier branch(String branchID)
+ {
+ return new ASN1ObjectIdentifier(getId() + "." + branchID);
+ }
+
+ /**
+ * 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.
+ */
+ public boolean on(ASN1ObjectIdentifier stem)
+ {
+ String id = getId(), stemId = stem.getId();
+ return id.length() > stemId.length() && id.charAt(stemId.length()) == '.' && id.startsWith(stemId);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
new file mode 100644
index 0000000..703b858
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java
@@ -0,0 +1,146 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+
+public abstract class ASN1OctetString
+ extends ASN1Primitive
+ implements ASN1OctetStringParser
+{
+ byte[] string;
+
+ /**
+ * return an Octet 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.
+ */
+ public static ASN1OctetString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof ASN1OctetString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return BEROctetString.fromSequence(ASN1Sequence.getInstance(o));
+ }
+ }
+
+ /**
+ * return an Octet String from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1OctetString getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1OctetString)
+ {
+ return (ASN1OctetString)obj;
+ }
+ else if (obj instanceof byte[])
+ {
+ try
+ {
+ return ASN1OctetString.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("failed to construct OCTET STRING from byte[]: " + e.getMessage());
+ }
+ }
+ else if (obj instanceof ASN1Encodable)
+ {
+ ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+ if (primitive instanceof ASN1OctetString)
+ {
+ return (ASN1OctetString)primitive;
+ }
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * @param string the octets making up the octet string.
+ */
+ public ASN1OctetString(
+ byte[] string)
+ {
+ if (string == null)
+ {
+ throw new NullPointerException("string cannot be null");
+ }
+ this.string = string;
+ }
+
+ public InputStream getOctetStream()
+ {
+ return new ByteArrayInputStream(string);
+ }
+
+ public ASN1OctetStringParser parser()
+ {
+ return this;
+ }
+
+ public byte[] getOctets()
+ {
+ return string;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(this.getOctets());
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof ASN1OctetString))
+ {
+ return false;
+ }
+
+ ASN1OctetString other = (ASN1OctetString)o;
+
+ return Arrays.areEqual(string, other.string);
+ }
+
+ public ASN1Primitive getLoadedObject()
+ {
+ return this.toASN1Primitive();
+ }
+
+ ASN1Primitive toDERObject()
+ {
+ return new DEROctetString(string);
+ }
+
+ ASN1Primitive toDLObject()
+ {
+ return new DEROctetString(string);
+ }
+
+ abstract void encode(ASN1OutputStream out)
+ throws IOException;
+
+ public String toString()
+ {
+ return "#"+new String(Hex.encode(string));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java
new file mode 100644
index 0000000..0042317
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OctetStringParser.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.asn1;
+
+import java.io.InputStream;
+
+public interface ASN1OctetStringParser
+ extends ASN1Encodable, InMemoryRepresentable
+{
+ public InputStream getOctetStream();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java
new file mode 100644
index 0000000..9a46a78
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1OutputStream.java
@@ -0,0 +1,194 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Stream that produces output based on the default encoding for the passed in objects.
+ */
+public class ASN1OutputStream
+{
+ private OutputStream os;
+
+ public ASN1OutputStream(
+ OutputStream os)
+ {
+ this.os = os;
+ }
+
+ void writeLength(
+ int length)
+ throws IOException
+ {
+ if (length > 127)
+ {
+ int size = 1;
+ int val = length;
+
+ while ((val >>>= 8) != 0)
+ {
+ size++;
+ }
+
+ write((byte)(size | 0x80));
+
+ for (int i = (size - 1) * 8; i >= 0; i -= 8)
+ {
+ write((byte)(length >> i));
+ }
+ }
+ else
+ {
+ write((byte)length);
+ }
+ }
+
+ void write(int b)
+ throws IOException
+ {
+ os.write(b);
+ }
+
+ void write(byte[] bytes)
+ throws IOException
+ {
+ os.write(bytes);
+ }
+
+ void write(byte[] bytes, int off, int len)
+ throws IOException
+ {
+ os.write(bytes, off, len);
+ }
+
+ void writeEncoded(
+ int tag,
+ byte[] bytes)
+ throws IOException
+ {
+ write(tag);
+ writeLength(bytes.length);
+ write(bytes);
+ }
+
+ void writeTag(int flags, int tagNo)
+ throws IOException
+ {
+ if (tagNo < 31)
+ {
+ write(flags | tagNo);
+ }
+ else
+ {
+ write(flags | 0x1f);
+ if (tagNo < 128)
+ {
+ write(tagNo);
+ }
+ else
+ {
+ byte[] stack = new byte[5];
+ int pos = stack.length;
+
+ stack[--pos] = (byte)(tagNo & 0x7F);
+
+ do
+ {
+ tagNo >>= 7;
+ stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
+ }
+ while (tagNo > 127);
+
+ write(stack, pos, stack.length - pos);
+ }
+ }
+ }
+
+ void writeEncoded(int flags, int tagNo, byte[] bytes)
+ throws IOException
+ {
+ writeTag(flags, tagNo);
+ writeLength(bytes.length);
+ write(bytes);
+ }
+
+ protected void writeNull()
+ throws IOException
+ {
+ os.write(BERTags.NULL);
+ os.write(0x00);
+ }
+
+ public void writeObject(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ obj.toASN1Primitive().encode(this);
+ }
+ else
+ {
+ throw new IOException("null object detected");
+ }
+ }
+
+ void writeImplicitObject(ASN1Primitive obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ obj.encode(new ImplicitOutputStream(os));
+ }
+ else
+ {
+ throw new IOException("null object detected");
+ }
+ }
+
+ public void close()
+ throws IOException
+ {
+ os.close();
+ }
+
+ public void flush()
+ throws IOException
+ {
+ os.flush();
+ }
+
+ ASN1OutputStream getDERSubStream()
+ {
+ return new DEROutputStream(os);
+ }
+
+ ASN1OutputStream getDLSubStream()
+ {
+ return new DLOutputStream(os);
+ }
+
+ private class ImplicitOutputStream
+ extends ASN1OutputStream
+ {
+ private boolean first = true;
+
+ public ImplicitOutputStream(OutputStream os)
+ {
+ super(os);
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ super.write(b);
+ }
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java
new file mode 100644
index 0000000..995b5e9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1ParsingException.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.asn1;
+
+public class ASN1ParsingException
+ extends IllegalStateException
+{
+ private Throwable cause;
+
+ public ASN1ParsingException(String message)
+ {
+ super(message);
+ }
+
+ public ASN1ParsingException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java
new file mode 100644
index 0000000..e6fe137
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Primitive.java
@@ -0,0 +1,69 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public abstract class ASN1Primitive
+ extends ASN1Object
+{
+ ASN1Primitive()
+ {
+
+ }
+
+ /**
+ * Create a base ASN.1 object from a byte stream.
+ *
+ * @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.
+ */
+ public static ASN1Primitive fromByteArray(byte[] data)
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(data);
+
+ try
+ {
+ return aIn.readObject();
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("cannot recognise object in stream");
+ }
+ }
+
+ public final boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+
+ return (o instanceof ASN1Encodable) && asn1Equals(((ASN1Encodable)o).toASN1Primitive());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return this;
+ }
+
+ ASN1Primitive toDERObject()
+ {
+ return this;
+ }
+
+ ASN1Primitive toDLObject()
+ {
+ return this;
+ }
+
+ public abstract int hashCode();
+
+ abstract boolean isConstructed();
+
+ abstract int encodedLength() throws IOException;
+
+ abstract void encode(ASN1OutputStream out) throws IOException;
+
+ abstract boolean asn1Equals(ASN1Primitive o);
+} \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
new file mode 100644
index 0000000..0507a2b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java
@@ -0,0 +1,323 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public abstract class ASN1Sequence
+ extends ASN1Primitive
+{
+ protected Vector seq = new Vector();
+
+ /**
+ * return an ASN1Sequence from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1Sequence getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1Sequence)
+ {
+ return (ASN1Sequence)obj;
+ }
+ else if (obj instanceof ASN1SequenceParser)
+ {
+ return ASN1Sequence.getInstance(((ASN1SequenceParser)obj).toASN1Primitive());
+ }
+ else if (obj instanceof byte[])
+ {
+ try
+ {
+ return ASN1Sequence.getInstance(fromByteArray((byte[])obj));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage());
+ }
+ }
+ else if (obj instanceof ASN1Encodable)
+ {
+ ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+ if (primitive instanceof ASN1Sequence)
+ {
+ return (ASN1Sequence)primitive;
+ }
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * Return an ASN1 sequence from a tagged object. There is a special
+ * case here, if an object appears to have been explicitly tagged on
+ * reading but we were expecting it to be implicitly tagged in the
+ * normal course of events it indicates that we lost the surrounding
+ * sequence - so we need to add it back (this will happen if the tagged
+ * object is a sequence that contains other sequences). If you are
+ * dealing with implicitly tagged sequences you really <b>should</b>
+ * be using this method.
+ *
+ * @param obj the tagged object.
+ * @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 ASN1Sequence getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ if (explicit)
+ {
+ if (!obj.isExplicit())
+ {
+ throw new IllegalArgumentException("object implicit - explicit expected.");
+ }
+
+ return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive());
+ }
+ else
+ {
+ //
+ // constructed object which appears to be explicitly tagged
+ // when it should be implicit means we have to add the
+ // surrounding sequence.
+ //
+ if (obj.isExplicit())
+ {
+ if (obj instanceof BERTaggedObject)
+ {
+ return new BERSequence(obj.getObject());
+ }
+ else
+ {
+ return new DLSequence(obj.getObject());
+ }
+ }
+ else
+ {
+ if (obj.getObject() instanceof ASN1Sequence)
+ {
+ return (ASN1Sequence)obj.getObject();
+ }
+ }
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * create an empty sequence
+ */
+ protected ASN1Sequence()
+ {
+ }
+
+ /**
+ * create a sequence containing one object
+ */
+ protected ASN1Sequence(
+ ASN1Encodable obj)
+ {
+ seq.addElement(obj);
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ protected ASN1Sequence(
+ ASN1EncodableVector v)
+ {
+ for (int i = 0; i != v.size(); i++)
+ {
+ seq.addElement(v.get(i));
+ }
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ protected ASN1Sequence(
+ ASN1Encodable[] array)
+ {
+ for (int i = 0; i != array.length; i++)
+ {
+ seq.addElement(array[i]);
+ }
+ }
+
+ public ASN1Encodable[] toArray()
+ {
+ ASN1Encodable[] values = new ASN1Encodable[this.size()];
+
+ for (int i = 0; i != this.size(); i++)
+ {
+ values[i] = this.getObjectAt(i);
+ }
+
+ return values;
+ }
+
+ public Enumeration getObjects()
+ {
+ return seq.elements();
+ }
+
+ public ASN1SequenceParser parser()
+ {
+ final ASN1Sequence outer = this;
+
+ return new ASN1SequenceParser()
+ {
+ private final int max = size();
+
+ private int index;
+
+ public ASN1Encodable readObject() throws IOException
+ {
+ if (index == max)
+ {
+ return null;
+ }
+
+ ASN1Encodable obj = getObjectAt(index++);
+ if (obj instanceof ASN1Sequence)
+ {
+ return ((ASN1Sequence)obj).parser();
+ }
+ if (obj instanceof ASN1Set)
+ {
+ return ((ASN1Set)obj).parser();
+ }
+
+ return obj;
+ }
+
+ public ASN1Primitive getLoadedObject()
+ {
+ return outer;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return outer;
+ }
+ };
+ }
+
+ /**
+ * 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.
+ */
+ public ASN1Encodable getObjectAt(
+ int index)
+ {
+ return (ASN1Encodable)seq.elementAt(index);
+ }
+
+ /**
+ * return the number of objects in this sequence.
+ *
+ * @return the number of objects in this sequence.
+ */
+ public int size()
+ {
+ return seq.size();
+ }
+
+ public int hashCode()
+ {
+ Enumeration e = this.getObjects();
+ int hashCode = size();
+
+ while (e.hasMoreElements())
+ {
+ Object o = getNext(e);
+ hashCode *= 17;
+
+ hashCode ^= o.hashCode();
+ }
+
+ return hashCode;
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof ASN1Sequence))
+ {
+ return false;
+ }
+
+ ASN1Sequence other = (ASN1Sequence)o;
+
+ if (this.size() != other.size())
+ {
+ return false;
+ }
+
+ Enumeration s1 = this.getObjects();
+ Enumeration s2 = other.getObjects();
+
+ while (s1.hasMoreElements())
+ {
+ ASN1Encodable obj1 = getNext(s1);
+ ASN1Encodable obj2 = getNext(s2);
+
+ ASN1Primitive o1 = obj1.toASN1Primitive();
+ ASN1Primitive o2 = obj2.toASN1Primitive();
+
+ if (o1 == o2 || o1.equals(o2))
+ {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ private ASN1Encodable getNext(Enumeration e)
+ {
+ ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
+
+ return encObj;
+ }
+
+ ASN1Primitive toDERObject()
+ {
+ ASN1Sequence derSeq = new DERSequence();
+
+ derSeq.seq = this.seq;
+
+ return derSeq;
+ }
+
+ ASN1Primitive toDLObject()
+ {
+ ASN1Sequence dlSeq = new DLSequence();
+
+ dlSeq.seq = this.seq;
+
+ return dlSeq;
+ }
+
+ boolean isConstructed()
+ {
+ return true;
+ }
+
+ abstract void encode(ASN1OutputStream out)
+ throws IOException;
+
+ public String toString()
+ {
+ return seq.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java
new file mode 100644
index 0000000..441f150
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SequenceParser.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public interface ASN1SequenceParser
+ extends ASN1Encodable, InMemoryRepresentable
+{
+ ASN1Encodable readObject()
+ throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java
new file mode 100644
index 0000000..8f785b8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1Set.java
@@ -0,0 +1,464 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+abstract public class ASN1Set
+ extends ASN1Primitive
+{
+ private Vector set = new Vector();
+ private boolean isSorted = false;
+
+ /**
+ * return an ASN1Set from the given object.
+ *
+ * @param obj the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1Set getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1Set)
+ {
+ return (ASN1Set)obj;
+ }
+ else if (obj instanceof ASN1SetParser)
+ {
+ return ASN1Set.getInstance(((ASN1SetParser)obj).toASN1Primitive());
+ }
+ else if (obj instanceof byte[])
+ {
+ try
+ {
+ return ASN1Set.getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("failed to construct set from byte[]: " + e.getMessage());
+ }
+ }
+ else if (obj instanceof ASN1Encodable)
+ {
+ ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive();
+
+ if (primitive instanceof ASN1Set)
+ {
+ return (ASN1Set)primitive;
+ }
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * Return an ASN1 set from a tagged object. There is a special
+ * case here, if an object appears to have been explicitly tagged on
+ * reading but we were expecting it to be implicitly tagged in the
+ * normal course of events it indicates that we lost the surrounding
+ * set - so we need to add it back (this will happen if the tagged
+ * object is a sequence that contains other sequences). If you are
+ * dealing with implicitly tagged sets you really <b>should</b>
+ * be using this method.
+ *
+ * @param obj the tagged object.
+ * @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 ASN1Set getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ if (explicit)
+ {
+ if (!obj.isExplicit())
+ {
+ throw new IllegalArgumentException("object implicit - explicit expected.");
+ }
+
+ return (ASN1Set)obj.getObject();
+ }
+ else
+ {
+ //
+ // constructed object which appears to be explicitly tagged
+ // and it's really implicit means we have to add the
+ // surrounding set.
+ //
+ if (obj.isExplicit())
+ {
+ if (obj instanceof BERTaggedObject)
+ {
+ return new BERSet(obj.getObject());
+ }
+ else
+ {
+ return new DLSet(obj.getObject());
+ }
+ }
+ else
+ {
+ if (obj.getObject() instanceof ASN1Set)
+ {
+ return (ASN1Set)obj.getObject();
+ }
+
+ //
+ // in this case the parser returns a sequence, convert it
+ // into a set.
+ //
+
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (obj.getObject() instanceof ASN1Sequence)
+ {
+ ASN1Sequence s = (ASN1Sequence)obj.getObject();
+
+ if (obj instanceof BERTaggedObject)
+ {
+ return new BERSet(s.toArray());
+ }
+ else
+ {
+ return new DLSet(s.toArray());
+ }
+ }
+ }
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+ }
+
+ protected ASN1Set()
+ {
+ }
+
+ /**
+ * create a sequence containing one object
+ */
+ protected ASN1Set(
+ ASN1Encodable obj)
+ {
+ set.addElement(obj);
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ protected ASN1Set(
+ ASN1EncodableVector v,
+ boolean doSort)
+ {
+ for (int i = 0; i != v.size(); i++)
+ {
+ set.addElement(v.get(i));
+ }
+
+ if (doSort)
+ {
+ this.sort();
+ }
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ protected ASN1Set(
+ ASN1Encodable[] array,
+ boolean doSort)
+ {
+ for (int i = 0; i != array.length; i++)
+ {
+ set.addElement(array[i]);
+ }
+
+ if (doSort)
+ {
+ this.sort();
+ }
+ }
+
+ public Enumeration getObjects()
+ {
+ return set.elements();
+ }
+
+ /**
+ * return the object at the set position indicated by index.
+ *
+ * @param index the set number (starting at zero) of the object
+ * @return the object at the set position indicated by index.
+ */
+ public ASN1Encodable getObjectAt(
+ int index)
+ {
+ return (ASN1Encodable)set.elementAt(index);
+ }
+
+ /**
+ * return the number of objects in this set.
+ *
+ * @return the number of objects in this set.
+ */
+ public int size()
+ {
+ return set.size();
+ }
+
+ public ASN1Encodable[] toArray()
+ {
+ ASN1Encodable[] values = new ASN1Encodable[this.size()];
+
+ for (int i = 0; i != this.size(); i++)
+ {
+ values[i] = this.getObjectAt(i);
+ }
+
+ return values;
+ }
+
+ public ASN1SetParser parser()
+ {
+ final ASN1Set outer = this;
+
+ return new ASN1SetParser()
+ {
+ private final int max = size();
+
+ private int index;
+
+ public ASN1Encodable readObject() throws IOException
+ {
+ if (index == max)
+ {
+ return null;
+ }
+
+ ASN1Encodable obj = getObjectAt(index++);
+ if (obj instanceof ASN1Sequence)
+ {
+ return ((ASN1Sequence)obj).parser();
+ }
+ if (obj instanceof ASN1Set)
+ {
+ return ((ASN1Set)obj).parser();
+ }
+
+ return obj;
+ }
+
+ public ASN1Primitive getLoadedObject()
+ {
+ return outer;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return outer;
+ }
+ };
+ }
+
+ public int hashCode()
+ {
+ Enumeration e = this.getObjects();
+ int hashCode = size();
+
+ while (e.hasMoreElements())
+ {
+ Object o = getNext(e);
+ hashCode *= 17;
+
+ hashCode ^= o.hashCode();
+ }
+
+ return hashCode;
+ }
+
+ ASN1Primitive toDERObject()
+ {
+ if (isSorted)
+ {
+ ASN1Set derSet = new DERSet();
+
+ derSet.set = this.set;
+
+ return derSet;
+ }
+ else
+ {
+ Vector v = new Vector();
+
+ for (int i = 0; i != set.size(); i++)
+ {
+ v.addElement(set.elementAt(i));
+ }
+
+ ASN1Set derSet = new DERSet();
+
+ derSet.set = v;
+
+ derSet.sort();
+
+ return derSet;
+ }
+ }
+
+ ASN1Primitive toDLObject()
+ {
+ ASN1Set derSet = new DLSet();
+
+ derSet.set = this.set;
+
+ return derSet;
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof ASN1Set))
+ {
+ return false;
+ }
+
+ ASN1Set other = (ASN1Set)o;
+
+ if (this.size() != other.size())
+ {
+ return false;
+ }
+
+ Enumeration s1 = this.getObjects();
+ Enumeration s2 = other.getObjects();
+
+ while (s1.hasMoreElements())
+ {
+ ASN1Encodable obj1 = getNext(s1);
+ ASN1Encodable obj2 = getNext(s2);
+
+ ASN1Primitive o1 = obj1.toASN1Primitive();
+ ASN1Primitive o2 = obj2.toASN1Primitive();
+
+ if (o1 == o2 || o1.equals(o2))
+ {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ private ASN1Encodable getNext(Enumeration e)
+ {
+ ASN1Encodable encObj = (ASN1Encodable)e.nextElement();
+
+ // unfortunately null was allowed as a substitute for DER null
+ if (encObj == null)
+ {
+ return DERNull.INSTANCE;
+ }
+
+ return encObj;
+ }
+
+ /**
+ * return true if a <= b (arrays are assumed padded with zeros).
+ */
+ private boolean lessThanOrEqual(
+ byte[] a,
+ byte[] b)
+ {
+ int len = Math.min(a.length, b.length);
+ for (int i = 0; i != len; ++i)
+ {
+ if (a[i] != b[i])
+ {
+ return (a[i] & 0xff) < (b[i] & 0xff);
+ }
+ }
+ return len == a.length;
+ }
+
+ private byte[] getEncoded(
+ ASN1Encodable obj)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ try
+ {
+ aOut.writeObject(obj);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("cannot encode object added to SET");
+ }
+
+ return bOut.toByteArray();
+ }
+
+ protected void sort()
+ {
+ if (!isSorted)
+ {
+ isSorted = true;
+ if (set.size() > 1)
+ {
+ boolean swapped = true;
+ int lastSwap = set.size() - 1;
+
+ while (swapped)
+ {
+ int index = 0;
+ int swapIndex = 0;
+ byte[] a = getEncoded((ASN1Encodable)set.elementAt(0));
+
+ swapped = false;
+
+ while (index != lastSwap)
+ {
+ byte[] b = getEncoded((ASN1Encodable)set.elementAt(index + 1));
+
+ if (lessThanOrEqual(a, b))
+ {
+ a = b;
+ }
+ else
+ {
+ Object o = set.elementAt(index);
+
+ set.setElementAt(set.elementAt(index + 1), index);
+ set.setElementAt(o, index + 1);
+
+ swapped = true;
+ swapIndex = index;
+ }
+
+ index++;
+ }
+
+ lastSwap = swapIndex;
+ }
+ }
+ }
+ }
+
+ boolean isConstructed()
+ {
+ return true;
+ }
+
+ abstract void encode(ASN1OutputStream out)
+ throws IOException;
+
+ public String toString()
+ {
+ return set.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java
new file mode 100644
index 0000000..e025535
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1SetParser.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public interface ASN1SetParser
+ extends ASN1Encodable, InMemoryRepresentable
+{
+ public ASN1Encodable readObject()
+ throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java
new file mode 100644
index 0000000..420fa34
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1StreamParser.java
@@ -0,0 +1,247 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ASN1StreamParser
+{
+ private final InputStream _in;
+ private final int _limit;
+ private final byte[][] tmpBuffers;
+
+ public ASN1StreamParser(
+ InputStream in)
+ {
+ this(in, StreamUtil.findLimit(in));
+ }
+
+ public ASN1StreamParser(
+ InputStream in,
+ int limit)
+ {
+ this._in = in;
+ this._limit = limit;
+
+ this.tmpBuffers = new byte[11][];
+ }
+
+ public ASN1StreamParser(
+ byte[] encoding)
+ {
+ this(new ByteArrayInputStream(encoding), encoding.length);
+ }
+
+ ASN1Encodable readIndef(int tagValue) throws IOException
+ {
+ // Note: INDEF => CONSTRUCTED
+
+ // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+ switch (tagValue)
+ {
+ case BERTags.EXTERNAL:
+ return new DERExternalParser(this);
+ case BERTags.OCTET_STRING:
+ return new BEROctetStringParser(this);
+ case BERTags.SEQUENCE:
+ return new BERSequenceParser(this);
+ case BERTags.SET:
+ return new BERSetParser(this);
+ default:
+ throw new ASN1Exception("unknown BER object encountered: 0x" + Integer.toHexString(tagValue));
+ }
+ }
+
+ ASN1Encodable readImplicit(boolean constructed, int tag) throws IOException
+ {
+ if (_in instanceof IndefiniteLengthInputStream)
+ {
+ if (!constructed)
+ {
+ throw new IOException("indefinite length primitive encoding encountered");
+ }
+
+ return readIndef(tag);
+ }
+
+ if (constructed)
+ {
+ switch (tag)
+ {
+ case BERTags.SET:
+ return new DERSetParser(this);
+ case BERTags.SEQUENCE:
+ return new DERSequenceParser(this);
+ case BERTags.OCTET_STRING:
+ return new BEROctetStringParser(this);
+ }
+ }
+ else
+ {
+ switch (tag)
+ {
+ case BERTags.SET:
+ throw new ASN1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
+ case BERTags.SEQUENCE:
+ throw new ASN1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
+ case BERTags.OCTET_STRING:
+ return new DEROctetStringParser((DefiniteLengthInputStream)_in);
+ }
+ }
+
+ // TODO ASN1Exception
+ throw new RuntimeException("implicit tagging not implemented");
+ }
+
+ ASN1Primitive readTaggedObject(boolean constructed, int tag) throws IOException
+ {
+ if (!constructed)
+ {
+ // Note: !CONSTRUCTED => IMPLICIT
+ DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
+ return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray()));
+ }
+
+ ASN1EncodableVector v = readVector();
+
+ if (_in instanceof IndefiniteLengthInputStream)
+ {
+ return v.size() == 1
+ ? new BERTaggedObject(true, tag, v.get(0))
+ : new BERTaggedObject(false, tag, BERFactory.createSequence(v));
+ }
+
+ return v.size() == 1
+ ? new DERTaggedObject(true, tag, v.get(0))
+ : new DERTaggedObject(false, tag, DERFactory.createSequence(v));
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ int tag = _in.read();
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ //
+ // turn of looking for "00" while we resolve the tag
+ //
+ set00Check(false);
+
+ //
+ // calculate tag number
+ //
+ int tagNo = ASN1InputStream.readTagNumber(_in, tag);
+
+ boolean isConstructed = (tag & BERTags.CONSTRUCTED) != 0;
+
+ //
+ // calculate length
+ //
+ int length = ASN1InputStream.readLength(_in, _limit);
+
+ if (length < 0) // indefinite length method
+ {
+ if (!isConstructed)
+ {
+ throw new IOException("indefinite length primitive encoding encountered");
+ }
+
+ IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
+ ASN1StreamParser sp = new ASN1StreamParser(indIn, _limit);
+
+ if ((tag & BERTags.APPLICATION) != 0)
+ {
+ return new BERApplicationSpecificParser(tagNo, sp);
+ }
+
+ if ((tag & BERTags.TAGGED) != 0)
+ {
+ return new BERTaggedObjectParser(true, tagNo, sp);
+ }
+
+ return sp.readIndef(tagNo);
+ }
+ else
+ {
+ DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
+
+ if ((tag & BERTags.APPLICATION) != 0)
+ {
+ return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray());
+ }
+
+ if ((tag & BERTags.TAGGED) != 0)
+ {
+ return new BERTaggedObjectParser(isConstructed, tagNo, new ASN1StreamParser(defIn));
+ }
+
+ if (isConstructed)
+ {
+ // TODO There are other tags that may be constructed (e.g. BIT_STRING)
+ switch (tagNo)
+ {
+ case BERTags.OCTET_STRING:
+ //
+ // yes, people actually do this...
+ //
+ return new BEROctetStringParser(new ASN1StreamParser(defIn));
+ case BERTags.SEQUENCE:
+ return new DERSequenceParser(new ASN1StreamParser(defIn));
+ case BERTags.SET:
+ return new DERSetParser(new ASN1StreamParser(defIn));
+ case BERTags.EXTERNAL:
+ return new DERExternalParser(new ASN1StreamParser(defIn));
+ default:
+ throw new IOException("unknown tag " + tagNo + " encountered");
+ }
+ }
+
+ // Some primitive encodings can be handled by parsers too...
+ switch (tagNo)
+ {
+ case BERTags.OCTET_STRING:
+ return new DEROctetStringParser(defIn);
+ }
+
+ try
+ {
+ return ASN1InputStream.createPrimitiveDERObject(tagNo, defIn, tmpBuffers);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ASN1Exception("corrupted stream detected", e);
+ }
+ }
+ }
+
+ private void set00Check(boolean enabled)
+ {
+ if (_in instanceof IndefiniteLengthInputStream)
+ {
+ ((IndefiniteLengthInputStream)_in).setEofOn00(enabled);
+ }
+ }
+
+ ASN1EncodableVector readVector() throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ ASN1Encodable obj;
+ while ((obj = readObject()) != null)
+ {
+ if (obj instanceof InMemoryRepresentable)
+ {
+ v.add(((InMemoryRepresentable)obj).getLoadedObject());
+ }
+ else
+ {
+ v.add(obj.toASN1Primitive());
+ }
+ }
+
+ return v;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java
new file mode 100644
index 0000000..fde4e23
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1String.java
@@ -0,0 +1,6 @@
+package org.bouncycastle.asn1;
+
+public interface ASN1String
+{
+ public String getString();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
new file mode 100644
index 0000000..fb1e244
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java
@@ -0,0 +1,236 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ */
+public abstract class ASN1TaggedObject
+ extends ASN1Primitive
+ implements ASN1TaggedObjectParser
+{
+ int tagNo;
+ boolean empty = false;
+ boolean explicit = true;
+ ASN1Encodable obj = null;
+
+ static public ASN1TaggedObject getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ if (explicit)
+ {
+ return (ASN1TaggedObject)obj.getObject();
+ }
+
+ throw new IllegalArgumentException("implicitly tagged tagged object");
+ }
+
+ static public ASN1TaggedObject getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof ASN1TaggedObject)
+ {
+ return (ASN1TaggedObject)obj;
+ }
+ else if (obj instanceof byte[])
+ {
+ try
+ {
+ return ASN1TaggedObject.getInstance(fromByteArray((byte[])obj));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("failed to construct tagged object from byte[]: " + e.getMessage());
+ }
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * Create a tagged object with the style given by the value of explicit.
+ * <p>
+ * If the object implements ASN1Choice the tag style will always be changed
+ * to explicit in accordance with the ASN.1 encoding rules.
+ * </p>
+ * @param explicit true if the object is explicitly tagged.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public ASN1TaggedObject(
+ boolean explicit,
+ int tagNo,
+ ASN1Encodable obj)
+ {
+ if (obj instanceof ASN1Choice)
+ {
+ this.explicit = true;
+ }
+ else
+ {
+ this.explicit = explicit;
+ }
+
+ this.tagNo = tagNo;
+
+ if (this.explicit)
+ {
+ this.obj = obj;
+ }
+ else
+ {
+ ASN1Primitive prim = obj.toASN1Primitive();
+
+ if (prim instanceof ASN1Set)
+ {
+ ASN1Set s = null;
+ }
+
+ this.obj = obj;
+ }
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof ASN1TaggedObject))
+ {
+ return false;
+ }
+
+ ASN1TaggedObject other = (ASN1TaggedObject)o;
+
+ if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit)
+ {
+ return false;
+ }
+
+ if(obj == null)
+ {
+ if (other.obj != null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive())))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ int code = tagNo;
+
+ // TODO: actually this is wrong - the problem is that a re-encoded
+ // object may end up with a different hashCode due to implicit
+ // tagging. As implicit tagging is ambiguous if a sequence is involved
+ // it seems the only correct method for both equals and hashCode is to
+ // compare the encodings...
+ if (obj != null)
+ {
+ code ^= obj.hashCode();
+ }
+
+ return code;
+ }
+
+ public int getTagNo()
+ {
+ return tagNo;
+ }
+
+ /**
+ * return whether or not the object may be explicitly tagged.
+ * <p>
+ * Note: if the object has been read from an input stream, the only
+ * time you can be sure if isExplicit is returning the true state of
+ * affairs is if it returns false. An implicitly tagged object may appear
+ * to be explicitly tagged, so you need to understand the context under
+ * which the reading was done as well, see getObject below.
+ */
+ public boolean isExplicit()
+ {
+ return explicit;
+ }
+
+ public boolean isEmpty()
+ {
+ return empty;
+ }
+
+ /**
+ * return whatever was following the tag.
+ * <p>
+ * Note: tagged objects are generally context dependent if you're
+ * trying to extract a tagged object you should be going via the
+ * appropriate getInstance method.
+ */
+ public ASN1Primitive getObject()
+ {
+ if (obj != null)
+ {
+ return obj.toASN1Primitive();
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the object held in this tagged object as a parser assuming it has
+ * the type of the passed in tag. If the object doesn't have a parser
+ * associated with it, the base object is returned.
+ */
+ public ASN1Encodable getObjectParser(
+ int tag,
+ boolean isExplicit)
+ {
+ switch (tag)
+ {
+ case BERTags.SET:
+ return ASN1Set.getInstance(this, isExplicit).parser();
+ case BERTags.SEQUENCE:
+ return ASN1Sequence.getInstance(this, isExplicit).parser();
+ case BERTags.OCTET_STRING:
+ return ASN1OctetString.getInstance(this, isExplicit).parser();
+ }
+
+ if (isExplicit)
+ {
+ return getObject();
+ }
+
+ throw new RuntimeException("implicit tagging not implemented for tag: " + tag);
+ }
+
+ public ASN1Primitive getLoadedObject()
+ {
+ return this.toASN1Primitive();
+ }
+
+ ASN1Primitive toDERObject()
+ {
+ return new DERTaggedObject(explicit, tagNo, obj);
+ }
+
+ ASN1Primitive toDLObject()
+ {
+ return new DLTaggedObject(explicit, tagNo, obj);
+ }
+
+ abstract void encode(ASN1OutputStream out)
+ throws IOException;
+
+ public String toString()
+ {
+ return "[" + tagNo + "]" + obj;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
new file mode 100644
index 0000000..a681dc9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1TaggedObjectParser.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public interface ASN1TaggedObjectParser
+ extends ASN1Encodable, InMemoryRepresentable
+{
+ public int getTagNo();
+
+ public ASN1Encodable getObjectParser(int tag, boolean isExplicit)
+ throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java
new file mode 100644
index 0000000..d3816f2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.asn1;
+
+import java.util.Date;
+
+public class ASN1UTCTime
+ extends DERUTCTime
+{
+ ASN1UTCTime(byte[] bytes)
+ {
+ super(bytes);
+ }
+
+ public ASN1UTCTime(Date time)
+ {
+ super(time);
+ }
+
+ public ASN1UTCTime(String time)
+ {
+ super(time);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java
new file mode 100644
index 0000000..8bc8a4e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecific.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.asn1;
+
+public class BERApplicationSpecific
+ extends DERApplicationSpecific
+{
+ public BERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
+ {
+ super(tagNo, vec);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java
new file mode 100644
index 0000000..63bd9f3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERApplicationSpecificParser.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class BERApplicationSpecificParser
+ implements ASN1ApplicationSpecificParser
+{
+ private final int tag;
+ private final ASN1StreamParser parser;
+
+ BERApplicationSpecificParser(int tag, ASN1StreamParser parser)
+ {
+ this.tag = tag;
+ this.parser = parser;
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ return parser.readObject();
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new BERApplicationSpecific(tag, parser.readVector());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException(e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
new file mode 100644
index 0000000..cad6e42
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERConstructedOctetString.java
@@ -0,0 +1,144 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * @deprecated use BEROctetString
+ */
+public class BERConstructedOctetString
+ extends BEROctetString
+{
+ private static final int MAX_LENGTH = 1000;
+
+ /**
+ * convert a vector of octet strings into a single byte string
+ */
+ static private byte[] toBytes(
+ Vector octs)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ for (int i = 0; i != octs.size(); i++)
+ {
+ try
+ {
+ DEROctetString o = (DEROctetString)octs.elementAt(i);
+
+ bOut.write(o.getOctets());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + " found in input should only contain DEROctetString");
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("exception converting octets " + e.toString());
+ }
+ }
+
+ return bOut.toByteArray();
+ }
+
+ private Vector octs;
+
+ /**
+ * @param string the octets making up the octet string.
+ */
+ public BERConstructedOctetString(
+ byte[] string)
+ {
+ super(string);
+ }
+
+ public BERConstructedOctetString(
+ Vector octs)
+ {
+ super(toBytes(octs));
+
+ this.octs = octs;
+ }
+
+ public BERConstructedOctetString(
+ ASN1Primitive obj)
+ {
+ super(toByteArray(obj));
+ }
+
+ private static byte[] toByteArray(ASN1Primitive obj)
+ {
+ try
+ {
+ return obj.getEncoded();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("Unable to encode object");
+ }
+ }
+
+ public BERConstructedOctetString(
+ ASN1Encodable obj)
+ {
+ this(obj.toASN1Primitive());
+ }
+
+ public byte[] getOctets()
+ {
+ return string;
+ }
+
+ /**
+ * return the DER octets that make up this string.
+ */
+ public Enumeration getObjects()
+ {
+ if (octs == null)
+ {
+ return generateOcts().elements();
+ }
+
+ return octs.elements();
+ }
+
+ private Vector generateOcts()
+ {
+ Vector vec = new Vector();
+ for (int i = 0; i < string.length; i += MAX_LENGTH)
+ {
+ int end;
+
+ if (i + MAX_LENGTH > string.length)
+ {
+ end = string.length;
+ }
+ else
+ {
+ end = i + MAX_LENGTH;
+ }
+
+ byte[] nStr = new byte[end - i];
+
+ System.arraycopy(string, i, nStr, 0, nStr.length);
+
+ vec.addElement(new DEROctetString(nStr));
+ }
+
+ return vec;
+ }
+
+ public static BEROctetString fromSequence(ASN1Sequence seq)
+ {
+ Vector v = new Vector();
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ v.addElement(e.nextElement());
+ }
+
+ return new BERConstructedOctetString(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERFactory.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERFactory.java
new file mode 100644
index 0000000..023be0b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERFactory.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.asn1;
+
+class BERFactory
+{
+ static final BERSequence EMPTY_SEQUENCE = new BERSequence();
+ static final BERSet EMPTY_SET = new BERSet();
+
+ static BERSequence createSequence(ASN1EncodableVector v)
+ {
+ return v.size() < 1 ? EMPTY_SEQUENCE : new BERSequence(v);
+ }
+
+ static BERSet createSet(ASN1EncodableVector v)
+ {
+ return v.size() < 1 ? EMPTY_SET : new BERSet(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERGenerator.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERGenerator.java
new file mode 100644
index 0000000..ef7f9a3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERGenerator.java
@@ -0,0 +1,100 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class BERGenerator
+ extends ASN1Generator
+{
+ private boolean _tagged = false;
+ private boolean _isExplicit;
+ private int _tagNo;
+
+ protected BERGenerator(
+ OutputStream out)
+ {
+ super(out);
+ }
+
+ public BERGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit)
+ {
+ super(out);
+
+ _tagged = true;
+ _isExplicit = isExplicit;
+ _tagNo = tagNo;
+ }
+
+ public OutputStream getRawOutputStream()
+ {
+ return _out;
+ }
+
+ private void writeHdr(
+ int tag)
+ throws IOException
+ {
+ _out.write(tag);
+ _out.write(0x80);
+ }
+
+ protected void writeBERHeader(
+ int tag)
+ throws IOException
+ {
+ if (_tagged)
+ {
+ int tagNum = _tagNo | BERTags.TAGGED;
+
+ if (_isExplicit)
+ {
+ writeHdr(tagNum | BERTags.CONSTRUCTED);
+ writeHdr(tag);
+ }
+ else
+ {
+ if ((tag & BERTags.CONSTRUCTED) != 0)
+ {
+ writeHdr(tagNum | BERTags.CONSTRUCTED);
+ }
+ else
+ {
+ writeHdr(tagNum);
+ }
+ }
+ }
+ else
+ {
+ writeHdr(tag);
+ }
+ }
+
+ protected void writeBERBody(
+ InputStream contentStream)
+ throws IOException
+ {
+ int ch;
+
+ while ((ch = contentStream.read()) >= 0)
+ {
+ _out.write(ch);
+ }
+ }
+
+ protected void writeBEREnd()
+ throws IOException
+ {
+ _out.write(0x00);
+ _out.write(0x00);
+
+ if (_tagged && _isExplicit) // write extra end for tag header
+ {
+ _out.write(0x00);
+ _out.write(0x00);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetString.java b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetString.java
new file mode 100644
index 0000000..bc1ed44
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetString.java
@@ -0,0 +1,168 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class BEROctetString
+ extends ASN1OctetString
+{
+ private static final int MAX_LENGTH = 1000;
+
+ private ASN1OctetString[] octs;
+
+ /**
+ * convert a vector of octet strings into a single byte string
+ */
+ static private byte[] toBytes(
+ ASN1OctetString[] octs)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ for (int i = 0; i != octs.length; i++)
+ {
+ try
+ {
+ DEROctetString o = (DEROctetString)octs[i];
+
+ bOut.write(o.getOctets());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException(octs[i].getClass().getName() + " found in input should only contain DEROctetString");
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("exception converting octets " + e.toString());
+ }
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * @param string the octets making up the octet string.
+ */
+ public BEROctetString(
+ byte[] string)
+ {
+ super(string);
+ }
+
+ public BEROctetString(
+ ASN1OctetString[] octs)
+ {
+ super(toBytes(octs));
+
+ this.octs = octs;
+ }
+
+ public byte[] getOctets()
+ {
+ return string;
+ }
+
+ /**
+ * return the DER octets that make up this string.
+ */
+ public Enumeration getObjects()
+ {
+ if (octs == null)
+ {
+ return generateOcts().elements();
+ }
+
+ return new Enumeration()
+ {
+ int counter = 0;
+
+ public boolean hasMoreElements()
+ {
+ return counter < octs.length;
+ }
+
+ public Object nextElement()
+ {
+ return octs[counter++];
+ }
+ };
+ }
+
+ private Vector generateOcts()
+ {
+ Vector vec = new Vector();
+ for (int i = 0; i < string.length; i += MAX_LENGTH)
+ {
+ int end;
+
+ if (i + MAX_LENGTH > string.length)
+ {
+ end = string.length;
+ }
+ else
+ {
+ end = i + MAX_LENGTH;
+ }
+
+ byte[] nStr = new byte[end - i];
+
+ System.arraycopy(string, i, nStr, 0, nStr.length);
+
+ vec.addElement(new DEROctetString(nStr));
+ }
+
+ return vec;
+ }
+
+ boolean isConstructed()
+ {
+ return true;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = 0;
+ for (Enumeration e = getObjects(); e.hasMoreElements();)
+ {
+ length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+ }
+
+ return 2 + length + 2;
+ }
+
+ public void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.write(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+
+ out.write(0x80);
+
+ //
+ // write out the octet array
+ //
+ for (Enumeration e = getObjects(); e.hasMoreElements();)
+ {
+ out.writeObject((ASN1Encodable)e.nextElement());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+
+ static BEROctetString fromSequence(ASN1Sequence seq)
+ {
+ ASN1OctetString[] v = new ASN1OctetString[seq.size()];
+ Enumeration e = seq.getObjects();
+ int index = 0;
+
+ while (e.hasMoreElements())
+ {
+ v[index++] = (ASN1OctetString)e.nextElement();
+ }
+
+ return new BEROctetString(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java
new file mode 100644
index 0000000..b8df94a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java
@@ -0,0 +1,102 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class BEROctetStringGenerator
+ extends BERGenerator
+{
+ public BEROctetStringGenerator(OutputStream out)
+ throws IOException
+ {
+ super(out);
+
+ writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+ }
+
+ public BEROctetStringGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit)
+ throws IOException
+ {
+ super(out, tagNo, isExplicit);
+
+ writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING);
+ }
+
+ public OutputStream getOctetOutputStream()
+ {
+ return getOctetOutputStream(new byte[1000]); // limit for CER encoding.
+ }
+
+ public OutputStream getOctetOutputStream(
+ byte[] buf)
+ {
+ return new BufferedBEROctetStream(buf);
+ }
+
+ private class BufferedBEROctetStream
+ extends OutputStream
+ {
+ private byte[] _buf;
+ private int _off;
+ private DEROutputStream _derOut;
+
+ BufferedBEROctetStream(
+ byte[] buf)
+ {
+ _buf = buf;
+ _off = 0;
+ _derOut = new DEROutputStream(_out);
+ }
+
+ public void write(
+ int b)
+ throws IOException
+ {
+ _buf[_off++] = (byte)b;
+
+ if (_off == _buf.length)
+ {
+ DEROctetString.encode(_derOut, _buf);
+ _off = 0;
+ }
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ while (len > 0)
+ {
+ int numToCopy = Math.min(len, _buf.length - _off);
+ System.arraycopy(b, off, _buf, _off, numToCopy);
+
+ _off += numToCopy;
+ if (_off < _buf.length)
+ {
+ break;
+ }
+
+ DEROctetString.encode(_derOut, _buf);
+ _off = 0;
+
+ off += numToCopy;
+ len -= numToCopy;
+ }
+ }
+
+ public void close()
+ throws IOException
+ {
+ if (_off != 0)
+ {
+ byte[] bytes = new byte[_off];
+ System.arraycopy(_buf, 0, bytes, 0, _off);
+
+ DEROctetString.encode(_derOut, bytes);
+ }
+
+ writeBEREnd();
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
new file mode 100644
index 0000000..1c7132e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.util.io.Streams;
+
+public class BEROctetStringParser
+ implements ASN1OctetStringParser
+{
+ private ASN1StreamParser _parser;
+
+ BEROctetStringParser(
+ ASN1StreamParser parser)
+ {
+ _parser = parser;
+ }
+
+ public InputStream getOctetStream()
+ {
+ return new ConstructedOctetStream(_parser);
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new BEROctetString(Streams.readAll(getOctetStream()));
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
new file mode 100644
index 0000000..7117d4f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BEROutputStream.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class BEROutputStream
+ extends DEROutputStream
+{
+ public BEROutputStream(
+ OutputStream os)
+ {
+ super(os);
+ }
+
+ public void writeObject(
+ Object obj)
+ throws IOException
+ {
+ if (obj == null)
+ {
+ writeNull();
+ }
+ else if (obj instanceof ASN1Primitive)
+ {
+ ((ASN1Primitive)obj).encode(this);
+ }
+ else if (obj instanceof ASN1Encodable)
+ {
+ ((ASN1Encodable)obj).toASN1Primitive().encode(this);
+ }
+ else
+ {
+ throw new IOException("object not BEREncodable");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java
new file mode 100644
index 0000000..aa44950
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERSequence.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class BERSequence
+ extends ASN1Sequence
+{
+ /**
+ * create an empty sequence
+ */
+ public BERSequence()
+ {
+ }
+
+ /**
+ * create a sequence containing one object
+ */
+ public BERSequence(
+ ASN1Encodable obj)
+ {
+ super(obj);
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ public BERSequence(
+ ASN1EncodableVector v)
+ {
+ super(v);
+ }
+
+ /**
+ * create a sequence containing an array of objects.
+ */
+ public BERSequence(
+ ASN1Encodable[] array)
+ {
+ super(array);
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = 0;
+ for (Enumeration e = getObjects(); e.hasMoreElements();)
+ {
+ length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+ }
+
+ return 2 + length + 2;
+ }
+
+ /*
+ */
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+ out.write(0x80);
+
+ Enumeration e = getObjects();
+ while (e.hasMoreElements())
+ {
+ out.writeObject((ASN1Encodable)e.nextElement());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java
new file mode 100644
index 0000000..d5d4395
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java
@@ -0,0 +1,38 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class BERSequenceParser
+ implements ASN1SequenceParser
+{
+ private ASN1StreamParser _parser;
+
+ BERSequenceParser(ASN1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ return _parser.readObject();
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new BERSequence(_parser.readVector());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException(e.getMessage());
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java
new file mode 100644
index 0000000..064d778
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERSet.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class BERSet
+ extends ASN1Set
+{
+ /**
+ * create an empty sequence
+ */
+ public BERSet()
+ {
+ }
+
+ /**
+ * @param obj - a single object that makes up the set.
+ */
+ public BERSet(
+ ASN1Encodable obj)
+ {
+ super(obj);
+ }
+
+ /**
+ * @param v - a vector of objects making up the set.
+ */
+ public BERSet(
+ ASN1EncodableVector v)
+ {
+ super(v, false);
+ }
+
+ /**
+ * create a set from an array of objects.
+ */
+ public BERSet(
+ ASN1Encodable[] a)
+ {
+ super(a, false);
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = 0;
+ for (Enumeration e = getObjects(); e.hasMoreElements();)
+ {
+ length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength();
+ }
+
+ return 2 + length + 2;
+ }
+
+ /*
+ */
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.write(BERTags.SET | BERTags.CONSTRUCTED);
+ out.write(0x80);
+
+ Enumeration e = getObjects();
+ while (e.hasMoreElements())
+ {
+ out.writeObject((ASN1Encodable)e.nextElement());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERSetParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERSetParser.java
new file mode 100644
index 0000000..5a30f3c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERSetParser.java
@@ -0,0 +1,38 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class BERSetParser
+ implements ASN1SetParser
+{
+ private ASN1StreamParser _parser;
+
+ BERSetParser(ASN1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ return _parser.readObject();
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new BERSet(_parser.readVector());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
new file mode 100644
index 0000000..1af0a43
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObject.java
@@ -0,0 +1,147 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * BER TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ */
+public class BERTaggedObject
+ extends ASN1TaggedObject
+{
+ /**
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BERTaggedObject(
+ int tagNo,
+ ASN1Encodable obj)
+ {
+ super(true, tagNo, obj);
+ }
+
+ /**
+ * @param explicit true if an explicitly tagged object.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BERTaggedObject(
+ boolean explicit,
+ int tagNo,
+ ASN1Encodable obj)
+ {
+ super(explicit, tagNo, obj);
+ }
+
+ /**
+ * create an implicitly tagged object that contains a zero
+ * length sequence.
+ */
+ public BERTaggedObject(
+ int tagNo)
+ {
+ super(false, tagNo, new BERSequence());
+ }
+
+ boolean isConstructed()
+ {
+ if (!empty)
+ {
+ if (explicit)
+ {
+ return true;
+ }
+ else
+ {
+ ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+
+ return primitive.isConstructed();
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ if (!empty)
+ {
+ ASN1Primitive primitive = obj.toASN1Primitive();
+ int length = primitive.encodedLength();
+
+ if (explicit)
+ {
+ return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+ }
+ else
+ {
+ // header length already in calculation
+ length = length - 1;
+
+ return StreamUtil.calculateTagLength(tagNo) + length;
+ }
+ }
+ else
+ {
+ return StreamUtil.calculateTagLength(tagNo) + 1;
+ }
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+ out.write(0x80);
+
+ if (!empty)
+ {
+ if (!explicit)
+ {
+ Enumeration e;
+ if (obj instanceof ASN1OctetString)
+ {
+ if (obj instanceof BEROctetString)
+ {
+ e = ((BEROctetString)obj).getObjects();
+ }
+ else
+ {
+ ASN1OctetString octs = (ASN1OctetString)obj;
+ BEROctetString berO = new BEROctetString(octs.getOctets());
+ e = berO.getObjects();
+ }
+ }
+ else if (obj instanceof ASN1Sequence)
+ {
+ e = ((ASN1Sequence)obj).getObjects();
+ }
+ else if (obj instanceof ASN1Set)
+ {
+ e = ((ASN1Set)obj).getObjects();
+ }
+ else
+ {
+ throw new RuntimeException("not implemented: " + obj.getClass().getName());
+ }
+
+ while (e.hasMoreElements())
+ {
+ out.writeObject((ASN1Encodable)e.nextElement());
+ }
+ }
+ else
+ {
+ out.writeObject(obj);
+ }
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java
new file mode 100644
index 0000000..7cd334a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERTaggedObjectParser.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class BERTaggedObjectParser
+ implements ASN1TaggedObjectParser
+{
+ private boolean _constructed;
+ private int _tagNumber;
+ private ASN1StreamParser _parser;
+
+ BERTaggedObjectParser(
+ boolean constructed,
+ int tagNumber,
+ ASN1StreamParser parser)
+ {
+ _constructed = constructed;
+ _tagNumber = tagNumber;
+ _parser = parser;
+ }
+
+ public boolean isConstructed()
+ {
+ return _constructed;
+ }
+
+ public int getTagNo()
+ {
+ return _tagNumber;
+ }
+
+ public ASN1Encodable getObjectParser(
+ int tag,
+ boolean isExplicit)
+ throws IOException
+ {
+ if (isExplicit)
+ {
+ if (!_constructed)
+ {
+ throw new IOException("Explicit tags must be constructed (see X.690 8.14.2)");
+ }
+ return _parser.readObject();
+ }
+
+ return _parser.readImplicit(_constructed, tag);
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return _parser.readTaggedObject(_constructed, _tagNumber);
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return this.getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException(e.getMessage());
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java b/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java
new file mode 100644
index 0000000..7281a6a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/BERTags.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.asn1;
+
+public interface BERTags
+{
+ public static final int BOOLEAN = 0x01;
+ public static final int INTEGER = 0x02;
+ public static final int BIT_STRING = 0x03;
+ public static final int OCTET_STRING = 0x04;
+ public static final int NULL = 0x05;
+ public static final int OBJECT_IDENTIFIER = 0x06;
+ public static final int EXTERNAL = 0x08;
+ public static final int ENUMERATED = 0x0a;
+ public static final int SEQUENCE = 0x10;
+ public static final int SEQUENCE_OF = 0x10; // for completeness
+ public static final int SET = 0x11;
+ public static final int SET_OF = 0x11; // for completeness
+
+
+ public static final int NUMERIC_STRING = 0x12;
+ public static final int PRINTABLE_STRING = 0x13;
+ public static final int T61_STRING = 0x14;
+ public static final int VIDEOTEX_STRING = 0x15;
+ public static final int IA5_STRING = 0x16;
+ public static final int UTC_TIME = 0x17;
+ public static final int GENERALIZED_TIME = 0x18;
+ public static final int GRAPHIC_STRING = 0x19;
+ public static final int VISIBLE_STRING = 0x1a;
+ public static final int GENERAL_STRING = 0x1b;
+ public static final int UNIVERSAL_STRING = 0x1c;
+ public static final int BMP_STRING = 0x1e;
+ public static final int UTF8_STRING = 0x0c;
+
+ public static final int CONSTRUCTED = 0x20;
+ public static final int APPLICATION = 0x40;
+ public static final int TAGGED = 0x80;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java
new file mode 100644
index 0000000..f247b11
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ConstructedOctetStream.java
@@ -0,0 +1,111 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class ConstructedOctetStream
+ extends InputStream
+{
+ private final ASN1StreamParser _parser;
+
+ private boolean _first = true;
+ private InputStream _currentStream;
+
+ ConstructedOctetStream(
+ ASN1StreamParser parser)
+ {
+ _parser = parser;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ if (_currentStream == null)
+ {
+ if (!_first)
+ {
+ return -1;
+ }
+
+ ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
+
+ if (s == null)
+ {
+ return -1;
+ }
+
+ _first = false;
+ _currentStream = s.getOctetStream();
+ }
+
+ int totalRead = 0;
+
+ for (;;)
+ {
+ int numRead = _currentStream.read(b, off + totalRead, len - totalRead);
+
+ if (numRead >= 0)
+ {
+ totalRead += numRead;
+
+ if (totalRead == len)
+ {
+ return totalRead;
+ }
+ }
+ else
+ {
+ ASN1OctetStringParser aos = (ASN1OctetStringParser)_parser.readObject();
+
+ if (aos == null)
+ {
+ _currentStream = null;
+ return totalRead < 1 ? -1 : totalRead;
+ }
+
+ _currentStream = aos.getOctetStream();
+ }
+ }
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (_currentStream == null)
+ {
+ if (!_first)
+ {
+ return -1;
+ }
+
+ ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
+
+ if (s == null)
+ {
+ return -1;
+ }
+
+ _first = false;
+ _currentStream = s.getOctetStream();
+ }
+
+ for (;;)
+ {
+ int b = _currentStream.read();
+
+ if (b >= 0)
+ {
+ return b;
+ }
+
+ ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject();
+
+ if (s == null)
+ {
+ _currentStream = null;
+ return -1;
+ }
+
+ _currentStream = s.getOctetStream();
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java
new file mode 100644
index 0000000..5b59288
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERApplicationSpecific.java
@@ -0,0 +1,276 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+
+/**
+ * Base class for an application specific object
+ */
+public class DERApplicationSpecific
+ extends ASN1Primitive
+{
+ 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;
+ }
+
+ public DERApplicationSpecific(
+ int tag,
+ byte[] octets)
+ {
+ this(false, tag, octets);
+ }
+
+ public DERApplicationSpecific(
+ int tag,
+ ASN1Encodable object)
+ throws IOException
+ {
+ this(true, tag, object);
+ }
+
+ public DERApplicationSpecific(
+ boolean explicit,
+ int tag,
+ ASN1Encodable object)
+ throws IOException
+ {
+ ASN1Primitive primitive = object.toASN1Primitive();
+
+ byte[] data = primitive.getEncoded(ASN1Encoding.DER);
+
+ this.isConstructed = explicit || (primitive instanceof ASN1Set || primitive instanceof ASN1Sequence);
+ this.tag = tag;
+
+ if (explicit)
+ {
+ this.octets = data;
+ }
+ else
+ {
+ int lenBytes = getLengthOfHeader(data);
+ byte[] tmp = new byte[data.length - lenBytes];
+ System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
+ this.octets = tmp;
+ }
+ }
+
+ public DERApplicationSpecific(int tagNo, ASN1EncodableVector vec)
+ {
+ this.tag = tagNo;
+ this.isConstructed = true;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ for (int i = 0; i != vec.size(); i++)
+ {
+ try
+ {
+ bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ 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;
+ }
+
+ /* (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 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/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java
new file mode 100644
index 0000000..33a09f8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERBMPString.java
@@ -0,0 +1,141 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+
+/**
+ * DER BMPString object.
+ */
+public class DERBMPString
+ extends ASN1Primitive
+ implements ASN1String
+{
+ private 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.
+ */
+ public static DERBMPString getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERBMPString)
+ {
+ return (DERBMPString)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a BMP 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.
+ */
+ public static DERBMPString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERBMPString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERBMPString(ASN1OctetString.getInstance(o).getOctets());
+ }
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ DERBMPString(
+ byte[] string)
+ {
+ char[] cs = new char[string.length / 2];
+
+ for (int i = 0; i != cs.length; i++)
+ {
+ cs[i] = (char)((string[2 * i] << 8) | (string[2 * i + 1] & 0xff));
+ }
+
+ this.string = cs;
+ }
+
+ DERBMPString(char[] string)
+ {
+ this.string = string;
+ }
+
+ /**
+ * basic constructor
+ */
+ public DERBMPString(
+ String string)
+ {
+ this.string = string.toCharArray();
+ }
+
+ public String getString()
+ {
+ return new String(string);
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+
+ protected boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERBMPString))
+ {
+ return false;
+ }
+
+ DERBMPString s = (DERBMPString)o;
+
+ return Arrays.areEqual(string, s.string);
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 1 + StreamUtil.calculateBodyLength(string.length * 2) + (string.length * 2);
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.write(BERTags.BMP_STRING);
+ out.writeLength(string.length * 2);
+
+ for (int i = 0; i != string.length; i++)
+ {
+ char c = string[i];
+
+ out.write((byte)(c >> 8));
+ out.write((byte)c);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java
new file mode 100644
index 0000000..f7f2462
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERBitString.java
@@ -0,0 +1,312 @@
+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;
+
+public class DERBitString
+ 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 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
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERBitString getInstance(
+ Object obj)
+ {
+ if (obj == null || 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.
+ */
+ public static DERBitString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERBitString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return fromOctetString(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ protected DERBitString(
+ byte data,
+ int padBits)
+ {
+ this.data = new byte[1];
+ this.data[0] = data;
+ this.padBits = padBits;
+ }
+
+ /**
+ * @param data the octets making up the bit string.
+ * @param padBits the number of extra bits at the end of the string.
+ */
+ public DERBitString(
+ byte[] data,
+ int padBits)
+ {
+ this.data = data;
+ this.padBits = padBits;
+ }
+
+ public DERBitString(
+ byte[] data)
+ {
+ this(data, 0);
+ }
+
+ public DERBitString(
+ ASN1Encodable obj)
+ {
+ try
+ {
+ this.data = obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ this.padBits = 0;
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("Error processing object : " + e.toString());
+ }
+ }
+
+ 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;
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ byte[] bytes = new byte[getBytes().length + 1];
+
+ bytes[0] = (byte)getPadBits();
+ System.arraycopy(getBytes(), 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)
+ {
+ 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 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/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java
new file mode 100644
index 0000000..a519fa2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERBoolean.java
@@ -0,0 +1,183 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+
+public class DERBoolean
+ extends ASN1Primitive
+{
+ 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 DERBoolean from the passed in boolean.
+ */
+ public static ASN1Boolean getInstance(
+ boolean value)
+ {
+ return (value ? 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 DERBoolean 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);
+ }
+ }
+
+ // BEGIN android-changed
+ protected DERBoolean(
+ 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 == 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("byte 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);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java b/bcprov/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java
new file mode 100644
index 0000000..919ff72
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DEREncodableVector.java
@@ -0,0 +1,18 @@
+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
+ * use that class in preference.
+ */
+public class DEREncodableVector
+ extends ASN1EncodableVector
+{
+ /**
+ * @deprecated use ASN1EncodableVector instead.
+ */
+ public DEREncodableVector()
+ {
+
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
new file mode 100644
index 0000000..2cf17f1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DEREnumerated.java
@@ -0,0 +1,146 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bouncycastle.util.Arrays;
+
+public class DEREnumerated
+ extends ASN1Primitive
+{
+ 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());
+ }
+
+ 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 DEREnumerated getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DEREnumerated)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return fromOctetString(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ public DEREnumerated(
+ int value)
+ {
+ bytes = BigInteger.valueOf(value).toByteArray();
+ }
+
+ public DEREnumerated(
+ BigInteger value)
+ {
+ bytes = value.toByteArray();
+ }
+
+ public DEREnumerated(
+ byte[] bytes)
+ {
+ this.bytes = bytes;
+ }
+
+ public BigInteger getValue()
+ {
+ return new BigInteger(bytes);
+ }
+
+ boolean isConstructed()
+ {
+ 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;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java
new file mode 100644
index 0000000..aed1d27
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERExternal.java
@@ -0,0 +1,294 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * Class representing the DER-type External
+ */
+public class DERExternal
+ extends ASN1Primitive
+{
+ private ASN1ObjectIdentifier directReference;
+ private ASN1Integer indirectReference;
+ private ASN1Primitive dataValueDescriptor;
+ private int encoding;
+ private ASN1Primitive externalContent;
+
+ public DERExternal(ASN1EncodableVector vector)
+ {
+ int offset = 0;
+
+ ASN1Primitive enc = getObjFromVector(vector, offset);
+ if (enc instanceof ASN1ObjectIdentifier)
+ {
+ directReference = (ASN1ObjectIdentifier)enc;
+ offset++;
+ enc = getObjFromVector(vector, offset);
+ }
+ if (enc instanceof ASN1Integer)
+ {
+ indirectReference = (ASN1Integer) enc;
+ offset++;
+ enc = getObjFromVector(vector, offset);
+ }
+ if (!(enc instanceof DERTaggedObject))
+ {
+ dataValueDescriptor = (ASN1Primitive) enc;
+ offset++;
+ enc = getObjFromVector(vector, offset);
+ }
+
+ if (vector.size() != offset + 1)
+ {
+ throw new IllegalArgumentException("input vector too large");
+ }
+
+ if (!(enc instanceof DERTaggedObject))
+ {
+ throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External");
+ }
+ DERTaggedObject obj = (DERTaggedObject)enc;
+ setEncoding(obj.getTagNo());
+ externalContent = obj.getObject();
+ }
+
+ private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index)
+ {
+ if (v.size() <= index)
+ {
+ throw new IllegalArgumentException("too few objects in input vector");
+ }
+
+ return v.get(index).toASN1Primitive();
+ }
+ /**
+ * Creates a new instance of DERExternal
+ * See X.690 for more informations about the meaning of these parameters
+ * @param directReference The direct reference or <code>null</code> if not set.
+ * @param indirectReference The indirect reference or <code>null</code> if not set.
+ * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+ * @param externalData The external data in its encoded form.
+ */
+ public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData)
+ {
+ this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive());
+ }
+
+ /**
+ * Creates a new instance of DERExternal.
+ * See X.690 for more informations about the meaning of these parameters
+ * @param directReference The direct reference or <code>null</code> if not set.
+ * @param indirectReference The indirect reference or <code>null</code> if not set.
+ * @param dataValueDescriptor The data value descriptor or <code>null</code> if not set.
+ * @param encoding The encoding to be used for the external data
+ * @param externalData The external data
+ */
+ public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData)
+ {
+ setDirectReference(directReference);
+ setIndirectReference(indirectReference);
+ setDataValueDescriptor(dataValueDescriptor);
+ setEncoding(encoding);
+ setExternalContent(externalData.toASN1Primitive());
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode()
+ {
+ int ret = 0;
+ if (directReference != null)
+ {
+ ret = directReference.hashCode();
+ }
+ if (indirectReference != null)
+ {
+ ret ^= indirectReference.hashCode();
+ }
+ if (dataValueDescriptor != null)
+ {
+ ret ^= dataValueDescriptor.hashCode();
+ }
+ ret ^= externalContent.hashCode();
+ return ret;
+ }
+
+ boolean isConstructed()
+ {
+ return true;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ return this.getEncoded().length;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.asn1.ASN1Primitive#encode(org.bouncycastle.asn1.DEROutputStream)
+ */
+ void encode(ASN1OutputStream out)
+ throws IOException
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ if (directReference != null)
+ {
+ baos.write(directReference.getEncoded(ASN1Encoding.DER));
+ }
+ if (indirectReference != null)
+ {
+ baos.write(indirectReference.getEncoded(ASN1Encoding.DER));
+ }
+ if (dataValueDescriptor != null)
+ {
+ baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DER));
+ }
+ DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent);
+ baos.write(obj.getEncoded(ASN1Encoding.DER));
+ out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray());
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.asn1.ASN1Primitive#asn1Equals(org.bouncycastle.asn1.ASN1Primitive)
+ */
+ boolean asn1Equals(ASN1Primitive o)
+ {
+ if (!(o instanceof DERExternal))
+ {
+ return false;
+ }
+ if (this == o)
+ {
+ return true;
+ }
+ DERExternal other = (DERExternal)o;
+ if (directReference != null)
+ {
+ if (other.directReference == null || !other.directReference.equals(directReference))
+ {
+ return false;
+ }
+ }
+ if (indirectReference != null)
+ {
+ if (other.indirectReference == null || !other.indirectReference.equals(indirectReference))
+ {
+ return false;
+ }
+ }
+ if (dataValueDescriptor != null)
+ {
+ if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor))
+ {
+ return false;
+ }
+ }
+ return externalContent.equals(other.externalContent);
+ }
+
+ /**
+ * Returns the data value descriptor
+ * @return The descriptor
+ */
+ public ASN1Primitive getDataValueDescriptor()
+ {
+ return dataValueDescriptor;
+ }
+
+ /**
+ * Returns the direct reference of the external element
+ * @return The reference
+ */
+ public ASN1ObjectIdentifier getDirectReference()
+ {
+ return directReference;
+ }
+
+ /**
+ * Returns the encoding of the content. Valid values are
+ * <ul>
+ * <li><code>0</code> single-ASN1-type</li>
+ * <li><code>1</code> OCTET STRING</li>
+ * <li><code>2</code> BIT STRING</li>
+ * </ul>
+ * @return The encoding
+ */
+ public int getEncoding()
+ {
+ return encoding;
+ }
+
+ /**
+ * Returns the content of this element
+ * @return The content
+ */
+ public ASN1Primitive getExternalContent()
+ {
+ return externalContent;
+ }
+
+ /**
+ * Returns the indirect reference of this element
+ * @return The reference
+ */
+ public ASN1Integer getIndirectReference()
+ {
+ return indirectReference;
+ }
+
+ /**
+ * Sets the data value descriptor
+ * @param dataValueDescriptor The descriptor
+ */
+ private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor)
+ {
+ this.dataValueDescriptor = dataValueDescriptor;
+ }
+
+ /**
+ * Sets the direct reference of the external element
+ * @param directReferemce The reference
+ */
+ private void setDirectReference(ASN1ObjectIdentifier directReferemce)
+ {
+ this.directReference = directReferemce;
+ }
+
+ /**
+ * Sets the encoding of the content. Valid values are
+ * <ul>
+ * <li><code>0</code> single-ASN1-type</li>
+ * <li><code>1</code> OCTET STRING</li>
+ * <li><code>2</code> BIT STRING</li>
+ * </ul>
+ * @param encoding The encoding
+ */
+ private void setEncoding(int encoding)
+ {
+ if (encoding < 0 || encoding > 2)
+ {
+ throw new IllegalArgumentException("invalid encoding value: " + encoding);
+ }
+ this.encoding = encoding;
+ }
+
+ /**
+ * Sets the content of this element
+ * @param externalContent The content
+ */
+ private void setExternalContent(ASN1Primitive externalContent)
+ {
+ this.externalContent = externalContent;
+ }
+
+ /**
+ * Sets the indirect reference of this element
+ * @param indirectReference The reference
+ */
+ private void setIndirectReference(ASN1Integer indirectReference)
+ {
+ this.indirectReference = indirectReference;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java
new file mode 100644
index 0000000..b19c84d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERExternalParser.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class DERExternalParser
+ implements ASN1Encodable, InMemoryRepresentable
+{
+ private ASN1StreamParser _parser;
+
+ /**
+ *
+ */
+ public DERExternalParser(ASN1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ return _parser.readObject();
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ try
+ {
+ return new DERExternal(_parser.readVector());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ASN1Exception(e.getMessage(), e);
+ }
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException ioe)
+ {
+ throw new ASN1ParsingException("unable to get DER object", ioe);
+ }
+ catch (IllegalArgumentException ioe)
+ {
+ throw new ASN1ParsingException("unable to get DER object", ioe);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERFactory.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERFactory.java
new file mode 100644
index 0000000..b829e3b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERFactory.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.asn1;
+
+class DERFactory
+{
+ static final ASN1Sequence EMPTY_SEQUENCE = new DERSequence();
+ static final ASN1Set EMPTY_SET = new DERSet();
+
+ static ASN1Sequence createSequence(ASN1EncodableVector v)
+ {
+ return v.size() < 1 ? EMPTY_SEQUENCE : new DLSequence(v);
+ }
+
+ static ASN1Set createSet(ASN1EncodableVector v)
+ {
+ return v.size() < 1 ? EMPTY_SET : new DLSet(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
new file mode 100644
index 0000000..d7cd594
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralString.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+public class DERGeneralString
+ extends ASN1Primitive
+ implements ASN1String
+{
+ private byte[] string;
+
+ public static DERGeneralString getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERGeneralString)
+ {
+ return (DERGeneralString) obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: "
+ + obj.getClass().getName());
+ }
+
+ public static DERGeneralString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERGeneralString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERGeneralString(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ DERGeneralString(byte[] string)
+ {
+ this.string = string;
+ }
+
+ public DERGeneralString(String string)
+ {
+ this.string = Strings.toByteArray(string);
+ }
+
+ public String getString()
+ {
+ return Strings.fromByteArray(string);
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ 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.GENERAL_STRING, string);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+
+ boolean asn1Equals(ASN1Primitive o)
+ {
+ if (!(o instanceof DERGeneralString))
+ {
+ return false;
+ }
+ DERGeneralString s = (DERGeneralString)o;
+
+ return Arrays.areEqual(string, s.string);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
new file mode 100644
index 0000000..bb3b575
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERGeneralizedTime.java
@@ -0,0 +1,338 @@
+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.
+ */
+public class DERGeneralizedTime
+ extends ASN1Primitive
+{
+ 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);
+ }
+
+ 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).
+ * <p>
+ * Normally in a certificate we would expect "Z" rather than "GMT",
+ * however adding the "GMT" means we can just use:
+ * <pre>
+ * dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+ * </pre>
+ * 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()
+ {
+ 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())
+ {
+ 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);
+ }
+
+ private boolean hasFractionalSeconds()
+ {
+ for (int i = 0; i != time.length; i++)
+ {
+ if (time[i] == '.')
+ {
+ if (i == 14)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ 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);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java
new file mode 100644
index 0000000..abb2811
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERIA5String.java
@@ -0,0 +1,171 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+/**
+ * DER IA5String object - this is an ascii string.
+ */
+public class DERIA5String
+ extends ASN1Primitive
+ implements ASN1String
+{
+ private byte[] string;
+
+ /**
+ * return a IA5 string from the passed in object
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERIA5String getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERIA5String)
+ {
+ return (DERIA5String)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an IA5 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.
+ */
+ public static DERIA5String getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERIA5String)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERIA5String(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ /**
+ * basic constructor - with bytes.
+ */
+ DERIA5String(
+ byte[] string)
+ {
+ this.string = string;
+ }
+
+ /**
+ * basic constructor - without validation.
+ */
+ public DERIA5String(
+ String string)
+ {
+ this(string, false);
+ }
+
+ /**
+ * Constructor with optional validation.
+ *
+ * @param string the base string to wrap.
+ * @param validate whether or not to check the string.
+ * @throws IllegalArgumentException if validate is true and the string
+ * contains characters that should not be in an IA5String.
+ */
+ public DERIA5String(
+ String string,
+ boolean validate)
+ {
+ if (string == null)
+ {
+ throw new NullPointerException("string cannot be null");
+ }
+ if (validate && !isIA5String(string))
+ {
+ throw new IllegalArgumentException("string contains illegal characters");
+ }
+
+ this.string = Strings.toByteArray(string);
+ }
+
+ public String getString()
+ {
+ return Strings.fromByteArray(string);
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ 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.IA5_STRING, string);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERIA5String))
+ {
+ return false;
+ }
+
+ DERIA5String s = (DERIA5String)o;
+
+ return Arrays.areEqual(string, s.string);
+ }
+
+ /**
+ * 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.
+ */
+ public static boolean isIA5String(
+ String str)
+ {
+ for (int i = str.length() - 1; i >= 0; i--)
+ {
+ char ch = str.charAt(i);
+
+ if (ch > 0x007f)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java
new file mode 100644
index 0000000..d5e826d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERInteger.java
@@ -0,0 +1,136 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bouncycastle.util.Arrays;
+
+public class DERInteger
+ extends ASN1Primitive
+{
+ 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()));
+ }
+
+ 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.
+ * @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());
+ }
+ }
+
+ public DERInteger(
+ int value)
+ {
+ bytes = BigInteger.valueOf(value).toByteArray();
+ }
+
+ public DERInteger(
+ BigInteger value)
+ {
+ bytes = value.toByteArray();
+ }
+
+ public DERInteger(
+ byte[] bytes)
+ {
+ 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);
+ }
+
+ public String toString()
+ {
+ return getValue().toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERNull.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERNull.java
new file mode 100644
index 0000000..9bbc826
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERNull.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * A NULL object.
+ */
+public class DERNull
+ extends ASN1Null
+{
+ public static final DERNull INSTANCE = new DERNull();
+
+ private static final byte[] zeroBytes = new byte[0];
+
+ // BEGIN android-changed
+ protected DERNull()
+ // END android-changed
+ {
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 2;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.NULL, zeroBytes);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java
new file mode 100644
index 0000000..fae4063
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERNumericString.java
@@ -0,0 +1,174 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+/**
+ * DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
+ */
+public class DERNumericString
+ extends ASN1Primitive
+ implements ASN1String
+{
+ private byte[] string;
+
+ /**
+ * return a Numeric string from the passed in object
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERNumericString getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERNumericString)
+ {
+ return (DERNumericString)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an Numeric 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.
+ */
+ public static DERNumericString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERNumericString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERNumericString(ASN1OctetString.getInstance(o).getOctets());
+ }
+ }
+
+ /**
+ * basic constructor - with bytes.
+ */
+ DERNumericString(
+ byte[] string)
+ {
+ this.string = string;
+ }
+
+ /**
+ * basic constructor - without validation..
+ */
+ public DERNumericString(
+ String string)
+ {
+ this(string, false);
+ }
+
+ /**
+ * Constructor with optional validation.
+ *
+ * @param string the base string to wrap.
+ * @param validate whether or not to check the string.
+ * @throws IllegalArgumentException if validate is true and the string
+ * contains characters that should not be in a NumericString.
+ */
+ public DERNumericString(
+ String string,
+ boolean validate)
+ {
+ if (validate && !isNumericString(string))
+ {
+ throw new IllegalArgumentException("string contains illegal characters");
+ }
+
+ this.string = Strings.toByteArray(string);
+ }
+
+ public String getString()
+ {
+ return Strings.fromByteArray(string);
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ 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.NUMERIC_STRING, string);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERNumericString))
+ {
+ return false;
+ }
+
+ DERNumericString s = (DERNumericString)o;
+
+ return Arrays.areEqual(string, s.string);
+ }
+
+ /**
+ * Return true if the string can be represented as a NumericString ('0'..'9', ' ')
+ *
+ * @param str string to validate.
+ * @return true if numeric, fale otherwise.
+ */
+ public static boolean isNumericString(
+ String str)
+ {
+ for (int i = str.length() - 1; i >= 0; i--)
+ {
+ char ch = str.charAt(i);
+
+ if (ch > 0x007f)
+ {
+ return false;
+ }
+
+ if (('0' <= ch && ch <= '9') || ch == ' ')
+ {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
new file mode 100644
index 0000000..02a0945
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java
@@ -0,0 +1,383 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bouncycastle.util.Arrays;
+
+public class DERObjectIdentifier
+ extends ASN1Primitive
+{
+ String identifier;
+
+ private byte[] body;
+
+ /**
+ * return an OID from the passed in object
+ *
+ * @exception 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());
+ }
+
+ 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.
+ * @exception 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());
+ }
+ }
+
+ DERObjectIdentifier(
+ byte[] bytes)
+ {
+ 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 < 0x80000000000000L)
+ {
+ value = value * 128 + (b & 0x7f);
+ if ((b & 0x80) == 0) // end of number reached
+ {
+ if (first)
+ {
+ switch ((int)value / 40)
+ {
+ case 0:
+ objId.append('0');
+ break;
+ case 1:
+ objId.append('1');
+ value -= 40;
+ break;
+ default:
+ objId.append('2');
+ value -= 80;
+ }
+ first = false;
+ }
+
+ objId.append('.');
+ objId.append(value);
+ value = 0;
+ }
+ }
+ else
+ {
+ if (bigValue == null)
+ {
+ bigValue = BigInteger.valueOf(value);
+ }
+ bigValue = bigValue.shiftLeft(7);
+ bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
+ if ((b & 0x80) == 0)
+ {
+ objId.append('.');
+ objId.append(bigValue);
+ bigValue = null;
+ value = 0;
+ }
+ }
+ }
+
+ // BEGIN android-changed
+ /*
+ * Intern the identifier so there aren't hundreds of duplicates
+ * (in practice).
+ */
+ this.identifier = objId.toString().intern();
+ // END android-changed
+ }
+
+ public DERObjectIdentifier(
+ String identifier)
+ {
+ 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
+ }
+
+ 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);
+
+ writeField(aOut,
+ Integer.parseInt(tok.nextToken()) * 40
+ + Integer.parseInt(tok.nextToken()));
+
+ while (tok.hasMoreTokens())
+ {
+ String token = tok.nextToken();
+ if (token.length() < 18)
+ {
+ writeField(aOut, Long.parseLong(token));
+ }
+ else
+ {
+ writeField(aOut, new BigInteger(token));
+ }
+ }
+ }
+
+ protected 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 isValidIdentifier(
+ String identifier)
+ {
+ if (identifier.length() < 3
+ || identifier.charAt(1) != '.')
+ {
+ return false;
+ }
+
+ char first = identifier.charAt(0);
+ if (first < '0' || first > '2')
+ {
+ return false;
+ }
+
+ boolean periodAllowed = false;
+ for (int i = identifier.length() - 1; i >= 2; i--)
+ {
+ char ch = identifier.charAt(i);
+
+ if ('0' <= ch && ch <= '9')
+ {
+ periodAllowed = true;
+ continue;
+ }
+
+ if (ch == '.')
+ {
+ if (!periodAllowed)
+ {
+ return false;
+ }
+
+ periodAllowed = false;
+ continue;
+ }
+
+ return false;
+ }
+
+ return periodAllowed;
+ }
+
+ private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[255][];
+
+ static ASN1ObjectIdentifier fromOctetString(byte[] enc)
+ {
+ if (enc.length < 3)
+ {
+ return new ASN1ObjectIdentifier(enc);
+ }
+
+ int idx1 = enc[enc.length - 2] & 0xff;
+ ASN1ObjectIdentifier[] first = cache[idx1];
+
+ if (first == null)
+ {
+ first = cache[idx1] = new ASN1ObjectIdentifier[255];
+ }
+
+ int idx2 = enc[enc.length - 1] & 0xff;
+
+ ASN1ObjectIdentifier possibleMatch = first[idx2];
+
+ if (possibleMatch == null)
+ {
+ possibleMatch = first[idx2] = new ASN1ObjectIdentifier(enc);
+ return possibleMatch;
+ }
+
+ if (Arrays.areEqual(enc, possibleMatch.getBody()))
+ {
+ return possibleMatch;
+ }
+ else
+ {
+ idx1 = (idx1 + 1) % 256;
+ first = cache[idx1];
+ if (first == null)
+ {
+ first = cache[idx1] = new ASN1ObjectIdentifier[255];
+ }
+
+ possibleMatch = first[idx2];
+
+ if (possibleMatch == null)
+ {
+ possibleMatch = first[idx2] = new ASN1ObjectIdentifier(enc);
+ return possibleMatch;
+ }
+
+ if (Arrays.areEqual(enc, possibleMatch.getBody()))
+ {
+ return possibleMatch;
+ }
+
+ idx2 = (idx2 + 1) % 256;
+ possibleMatch = first[idx2];
+
+ if (possibleMatch == null)
+ {
+ possibleMatch = first[idx2] = new ASN1ObjectIdentifier(enc);
+ return possibleMatch;
+ }
+
+ if (Arrays.areEqual(enc, possibleMatch.getBody()))
+ {
+ return possibleMatch;
+ }
+ }
+
+ return new ASN1ObjectIdentifier(enc);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetString.java
new file mode 100644
index 0000000..988186f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetString.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class DEROctetString
+ extends ASN1OctetString
+{
+ /**
+ * @param string the octets making up the octet string.
+ */
+ public DEROctetString(
+ byte[] string)
+ {
+ super(string);
+ }
+
+ public DEROctetString(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ super(obj.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.OCTET_STRING, string);
+ }
+
+ static void encode(
+ DEROutputStream derOut,
+ byte[] bytes)
+ throws IOException
+ {
+ derOut.writeEncoded(BERTags.OCTET_STRING, bytes);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java
new file mode 100644
index 0000000..e6e2068
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class DEROctetStringParser
+ implements ASN1OctetStringParser
+{
+ private DefiniteLengthInputStream stream;
+
+ DEROctetStringParser(
+ DefiniteLengthInputStream stream)
+ {
+ this.stream = stream;
+ }
+
+ public InputStream getOctetStream()
+ {
+ return stream;
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new DEROctetString(stream.toByteArray());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException("IOException converting stream to byte array: " + e.getMessage(), e);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DEROutputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/DEROutputStream.java
new file mode 100644
index 0000000..8b18c3d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DEROutputStream.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Stream that outputs encoding based on distinguished encoding rules.
+ */
+public class DEROutputStream
+ extends ASN1OutputStream
+{
+ public DEROutputStream(
+ OutputStream os)
+ {
+ super(os);
+ }
+
+ public void writeObject(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ obj.toASN1Primitive().toDERObject().encode(this);
+ }
+ else
+ {
+ throw new IOException("null object detected");
+ }
+ }
+
+ ASN1OutputStream getDERSubStream()
+ {
+ return this;
+ }
+
+ ASN1OutputStream getDLSubStream()
+ {
+ return this;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
new file mode 100644
index 0000000..6c56e83
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERPrintableString.java
@@ -0,0 +1,203 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+/**
+ * DER PrintableString object.
+ */
+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.
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERPrintableString getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERPrintableString)
+ {
+ return (DERPrintableString)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a Printable 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.
+ */
+ public static DERPrintableString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERPrintableString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERPrintableString(ASN1OctetString.getInstance(o).getOctets());
+ }
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ DERPrintableString(
+ byte[] string)
+ {
+ this.string = string;
+ }
+
+ /**
+ * basic constructor - this does not validate the string
+ */
+ public DERPrintableString(
+ String string)
+ {
+ this(string, false);
+ }
+
+ /**
+ * Constructor with optional validation.
+ *
+ * @param string the base string to wrap.
+ * @param validate whether or not to check the string.
+ * @throws IllegalArgumentException if validate is true and the string
+ * contains characters that should not be in a PrintableString.
+ */
+ public DERPrintableString(
+ String string,
+ boolean validate)
+ {
+ if (validate && !isPrintableString(string))
+ {
+ throw new IllegalArgumentException("string contains illegal characters");
+ }
+
+ this.string = Strings.toByteArray(string);
+ }
+
+ public String getString()
+ {
+ return Strings.fromByteArray(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.PRINTABLE_STRING, string);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERPrintableString))
+ {
+ return false;
+ }
+
+ DERPrintableString s = (DERPrintableString)o;
+
+ return Arrays.areEqual(string, s.string);
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ /**
+ * return true if the passed in String can be represented without
+ * loss as a PrintableString, false otherwise.
+ *
+ * @return true if in printable set, false otherwise.
+ */
+ public static boolean isPrintableString(
+ String str)
+ {
+ for (int i = str.length() - 1; i >= 0; i--)
+ {
+ char ch = str.charAt(i);
+
+ if (ch > 0x007f)
+ {
+ return false;
+ }
+
+ if ('a' <= ch && ch <= 'z')
+ {
+ continue;
+ }
+
+ if ('A' <= ch && ch <= 'Z')
+ {
+ continue;
+ }
+
+ if ('0' <= ch && ch <= '9')
+ {
+ continue;
+ }
+
+ switch (ch)
+ {
+ case ' ':
+ case '\'':
+ case '(':
+ case ')':
+ case '+':
+ case '-':
+ case '.':
+ case ':':
+ case '=':
+ case '?':
+ case '/':
+ case ',':
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java
new file mode 100644
index 0000000..ad48a83
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERSequence.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class DERSequence
+ extends ASN1Sequence
+{
+ private int bodyLength = -1;
+
+ /**
+ * create an empty sequence
+ */
+ public DERSequence()
+ {
+ }
+
+ /**
+ * create a sequence containing one object
+ */
+ public DERSequence(
+ ASN1Encodable obj)
+ {
+ super(obj);
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ public DERSequence(
+ ASN1EncodableVector v)
+ {
+ super(v);
+ }
+
+ /**
+ * create a sequence containing an array of objects.
+ */
+ public DERSequence(
+ ASN1Encodable[] array)
+ {
+ super(array);
+ }
+
+ private int getBodyLength()
+ throws IOException
+ {
+ if (bodyLength < 0)
+ {
+ int length = 0;
+
+ for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength();
+ }
+
+ bodyLength = length;
+ }
+
+ return bodyLength;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = getBodyLength();
+
+ return 1 + StreamUtil.calculateBodyLength(length) + length;
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DER requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputting SEQUENCE,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ ASN1OutputStream dOut = out.getDERSubStream();
+ int length = getBodyLength();
+
+ out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+ out.writeLength(length);
+
+ for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ dOut.writeObject((ASN1Encodable)obj);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
new file mode 100644
index 0000000..376c1fd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERSequenceParser.java
@@ -0,0 +1,38 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class DERSequenceParser
+ implements ASN1SequenceParser
+{
+ private ASN1StreamParser _parser;
+
+ DERSequenceParser(ASN1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ return _parser.readObject();
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new DERSequence(_parser.readVector());
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException(e.getMessage());
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java
new file mode 100644
index 0000000..c1faf84
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERSet.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * A DER encoded set object
+ */
+public class DERSet
+ extends ASN1Set
+{
+ private int bodyLength = -1;
+
+ /**
+ * create an empty set
+ */
+ public DERSet()
+ {
+ }
+
+ /**
+ * @param obj - a single object that makes up the set.
+ */
+ public DERSet(
+ ASN1Encodable obj)
+ {
+ super(obj);
+ }
+
+ /**
+ * @param v - a vector of objects making up the set.
+ */
+ public DERSet(
+ ASN1EncodableVector v)
+ {
+ super(v, true);
+ }
+
+ /**
+ * create a set from an array of objects.
+ */
+ public DERSet(
+ ASN1Encodable[] a)
+ {
+ super(a, true);
+ }
+
+ DERSet(
+ ASN1EncodableVector v,
+ boolean doSort)
+ {
+ super(v, doSort);
+ }
+
+ private int getBodyLength()
+ throws IOException
+ {
+ if (bodyLength < 0)
+ {
+ int length = 0;
+
+ for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength();
+ }
+
+ bodyLength = length;
+ }
+
+ return bodyLength;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = getBodyLength();
+
+ return 1 + StreamUtil.calculateBodyLength(length) + length;
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DER requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputting SET,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ ASN1OutputStream dOut = out.getDERSubStream();
+ int length = getBodyLength();
+
+ out.write(BERTags.SET | BERTags.CONSTRUCTED);
+ out.writeLength(length);
+
+ for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ dOut.writeObject((ASN1Encodable)obj);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERSetParser.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERSetParser.java
new file mode 100644
index 0000000..17702fa
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERSetParser.java
@@ -0,0 +1,38 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public class DERSetParser
+ implements ASN1SetParser
+{
+ private ASN1StreamParser _parser;
+
+ DERSetParser(ASN1StreamParser parser)
+ {
+ this._parser = parser;
+ }
+
+ public ASN1Encodable readObject()
+ throws IOException
+ {
+ return _parser.readObject();
+ }
+
+ public ASN1Primitive getLoadedObject()
+ throws IOException
+ {
+ return new DERSet(_parser.readVector(), false);
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ try
+ {
+ return getLoadedObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java
new file mode 100644
index 0000000..ee2979b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERT61String.java
@@ -0,0 +1,123 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+/**
+ * DER T61String (also the teletex string)
+ */
+public class DERT61String
+ extends ASN1Primitive
+ implements ASN1String
+{
+ private byte[] string;
+
+ /**
+ * return a T61 string from the passed in object.
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERT61String getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERT61String)
+ {
+ return (DERT61String)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an T61 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.
+ */
+ public static DERT61String getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERT61String)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERT61String(ASN1OctetString.getInstance(o).getOctets());
+ }
+ }
+
+ /**
+ * basic constructor - with bytes.
+ */
+ DERT61String(
+ byte[] string)
+ {
+ this.string = string;
+ }
+
+ /**
+ * basic constructor - with string.
+ */
+ public DERT61String(
+ String string)
+ {
+ this.string = Strings.toByteArray(string);
+ }
+
+ public String getString()
+ {
+ return Strings.fromByteArray(string);
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.T61_STRING, string);
+ }
+
+ public byte[] getOctets()
+ {
+ return Arrays.clone(string);
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERT61String))
+ {
+ return false;
+ }
+
+ return Arrays.areEqual(string, ((DERT61String)o).string);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java
new file mode 100644
index 0000000..a87a0dc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERTaggedObject.java
@@ -0,0 +1,118 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * DER TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ */
+public class DERTaggedObject
+ extends ASN1TaggedObject
+{
+ private static final byte[] ZERO_BYTES = new byte[0];
+
+ /**
+ * @param explicit true if an explicitly tagged object.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public DERTaggedObject(
+ boolean explicit,
+ int tagNo,
+ ASN1Encodable obj)
+ {
+ super(explicit, tagNo, obj);
+ }
+
+ public DERTaggedObject(int tagNo, ASN1Encodable encodable)
+ {
+ super(true, tagNo, encodable);
+ }
+
+ boolean isConstructed()
+ {
+ if (!empty)
+ {
+ if (explicit)
+ {
+ return true;
+ }
+ else
+ {
+ ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+
+ return primitive.isConstructed();
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ if (!empty)
+ {
+ ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+ int length = primitive.encodedLength();
+
+ if (explicit)
+ {
+ return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+ }
+ else
+ {
+ // header length already in calculation
+ length = length - 1;
+
+ return StreamUtil.calculateTagLength(tagNo) + length;
+ }
+ }
+ else
+ {
+ return StreamUtil.calculateTagLength(tagNo) + 1;
+ }
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ if (!empty)
+ {
+ ASN1Primitive primitive = obj.toASN1Primitive().toDERObject();
+
+ if (explicit)
+ {
+ out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+ out.writeLength(primitive.encodedLength());
+ out.writeObject(primitive);
+ }
+ else
+ {
+ //
+ // need to mark constructed types...
+ //
+ int flags;
+ if (primitive.isConstructed())
+ {
+ flags = BERTags.CONSTRUCTED | BERTags.TAGGED;
+ }
+ else
+ {
+ flags = BERTags.TAGGED;
+ }
+
+ out.writeTag(flags, tagNo);
+ out.writeImplicitObject(primitive);
+ }
+ }
+ else
+ {
+ out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERTags.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERTags.java
new file mode 100644
index 0000000..83fd7fd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERTags.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.asn1;
+
+/**
+ * @deprecated use BERTags
+ */
+public interface DERTags
+ extends BERTags
+{
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERUTCTime.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
new file mode 100644
index 0000000..a5bdef1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERUTCTime.java
@@ -0,0 +1,266 @@
+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.
+ */
+public class DERUTCTime
+ extends ASN1Primitive
+{
+ 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);
+ }
+
+ 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).
+ * <p>
+ *
+ * @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
+ {
+ 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).
+ * <p>
+ * Normally in a certificate we would expect "Z" rather than "GMT",
+ * however adding the "GMT" means we can just use:
+ * <pre>
+ * dateF = new SimpleDateFormat("yyMMddHHmmssz");
+ * </pre>
+ * To read in the time and get a date which is compatible with our local
+ * time zone.
+ * <p>
+ * <b>Note:</b> 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
+ {
+ 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 DERUTCTime))
+ {
+ return false;
+ }
+
+ return Arrays.areEqual(time, ((DERUTCTime)o).time);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(time);
+ }
+
+ public String toString()
+ {
+ return Strings.fromByteArray(time);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERUTF8String.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
new file mode 100644
index 0000000..f46f558
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERUTF8String.java
@@ -0,0 +1,120 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+/**
+ * DER UTF8String object.
+ */
+public class DERUTF8String
+ extends ASN1Primitive
+ implements ASN1String
+{
+ private byte[] string;
+
+ /**
+ * return an UTF8 string from the passed in object.
+ *
+ * @exception IllegalArgumentException
+ * if the object cannot be converted.
+ */
+ public static DERUTF8String getInstance(Object obj)
+ {
+ if (obj == null || obj instanceof DERUTF8String)
+ {
+ return (DERUTF8String)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: "
+ + obj.getClass().getName());
+ }
+
+ /**
+ * return an UTF8 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.
+ */
+ public static DERUTF8String getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERUTF8String)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERUTF8String(ASN1OctetString.getInstance(o).getOctets());
+ }
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ DERUTF8String(byte[] string)
+ {
+ this.string = string;
+ }
+
+ /**
+ * basic constructor
+ */
+ public DERUTF8String(String string)
+ {
+ this.string = Strings.toUTF8ByteArray(string);
+ }
+
+ public String getString()
+ {
+ return Strings.fromUTF8ByteArray(string);
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+
+ boolean asn1Equals(ASN1Primitive o)
+ {
+ if (!(o instanceof DERUTF8String))
+ {
+ return false;
+ }
+
+ DERUTF8String s = (DERUTF8String)o;
+
+ return Arrays.areEqual(string, s.string);
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+ }
+
+ void encode(ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.UTF8_STRING, string);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
new file mode 100644
index 0000000..4fe82f0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERUniversalString.java
@@ -0,0 +1,136 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+
+/**
+ * DER UniversalString object.
+ */
+public class DERUniversalString
+ 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' };
+ private byte[] string;
+
+ /**
+ * return a Universal String from the passed in object.
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERUniversalString getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERUniversalString)
+ {
+ return (DERUniversalString)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a Universal 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.
+ */
+ public static DERUniversalString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERUniversalString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERUniversalString(((ASN1OctetString)o).getOctets());
+ }
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ public DERUniversalString(
+ byte[] string)
+ {
+ this.string = string;
+ }
+
+ 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();
+ }
+
+ public byte[] getOctets()
+ {
+ return string;
+ }
+
+ boolean isConstructed()
+ {
+ return false;
+ }
+
+ int encodedLength()
+ {
+ return 1 + StreamUtil.calculateBodyLength(string.length) + string.length;
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ out.writeEncoded(BERTags.UNIVERSAL_STRING, this.getOctets());
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERUniversalString))
+ {
+ return false;
+ }
+
+ return Arrays.areEqual(string, ((DERUniversalString)o).string);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DERVisibleString.java b/bcprov/src/main/java/org/bouncycastle/asn1/DERVisibleString.java
new file mode 100644
index 0000000..1c385b7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DERVisibleString.java
@@ -0,0 +1,123 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+/**
+ * DER VisibleString object.
+ */
+public class DERVisibleString
+ extends ASN1Primitive
+ implements ASN1String
+{
+ private byte[] string;
+
+ /**
+ * return a Visible String from the passed in object.
+ *
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERVisibleString getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DERVisibleString)
+ {
+ return (DERVisibleString)obj;
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * 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.
+ */
+ public static DERVisibleString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ ASN1Primitive o = obj.getObject();
+
+ if (explicit || o instanceof DERVisibleString)
+ {
+ return getInstance(o);
+ }
+ else
+ {
+ return new DERVisibleString(ASN1OctetString.getInstance(o).getOctets());
+ }
+ }
+
+ /**
+ * basic constructor - byte encoded string.
+ */
+ DERVisibleString(
+ byte[] string)
+ {
+ this.string = string;
+ }
+
+ /**
+ * basic constructor
+ */
+ public DERVisibleString(
+ String string)
+ {
+ this.string = Strings.toByteArray(string);
+ }
+
+ public String getString()
+ {
+ return Strings.fromByteArray(string);
+ }
+
+ public String toString()
+ {
+ return getString();
+ }
+
+ 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.VISIBLE_STRING, this.string);
+ }
+
+ boolean asn1Equals(
+ ASN1Primitive o)
+ {
+ if (!(o instanceof DERVisibleString))
+ {
+ return false;
+ }
+
+ return Arrays.areEqual(string, ((DERVisibleString)o).string);
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(string);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLOutputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLOutputStream.java
new file mode 100644
index 0000000..68c0ed6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLOutputStream.java
@@ -0,0 +1,31 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Stream that outputs encoding based on definite length.
+ */
+public class DLOutputStream
+ extends ASN1OutputStream
+{
+ public DLOutputStream(
+ OutputStream os)
+ {
+ super(os);
+ }
+
+ public void writeObject(
+ ASN1Encodable obj)
+ throws IOException
+ {
+ if (obj != null)
+ {
+ obj.toASN1Primitive().toDLObject().encode(this);
+ }
+ else
+ {
+ throw new IOException("null object detected");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java
new file mode 100644
index 0000000..bb8ec4e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLSequence.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class DLSequence
+ extends ASN1Sequence
+{
+ private int bodyLength = -1;
+
+ /**
+ * create an empty sequence
+ */
+ public DLSequence()
+ {
+ }
+
+ /**
+ * create a sequence containing one object
+ */
+ public DLSequence(
+ ASN1Encodable obj)
+ {
+ super(obj);
+ }
+
+ /**
+ * create a sequence containing a vector of objects.
+ */
+ public DLSequence(
+ ASN1EncodableVector v)
+ {
+ super(v);
+ }
+
+ /**
+ * create a sequence containing an array of objects.
+ */
+ public DLSequence(
+ ASN1Encodable[] array)
+ {
+ super(array);
+ }
+
+ private int getBodyLength()
+ throws IOException
+ {
+ if (bodyLength < 0)
+ {
+ int length = 0;
+
+ for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();
+ }
+
+ bodyLength = length;
+ }
+
+ return bodyLength;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = getBodyLength();
+
+ return 1 + StreamUtil.calculateBodyLength(length) + length;
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DL requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputting SEQUENCE,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ ASN1OutputStream dOut = out.getDLSubStream();
+ int length = getBodyLength();
+
+ out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED);
+ out.writeLength(length);
+
+ for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ dOut.writeObject((ASN1Encodable)obj);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java
new file mode 100644
index 0000000..755754b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLSet.java
@@ -0,0 +1,101 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * A DER encoded set object
+ */
+public class DLSet
+ extends ASN1Set
+{
+ private int bodyLength = -1;
+
+ /**
+ * create an empty set
+ */
+ public DLSet()
+ {
+ }
+
+ /**
+ * @param obj - a single object that makes up the set.
+ */
+ public DLSet(
+ ASN1Encodable obj)
+ {
+ super(obj);
+ }
+
+ /**
+ * @param v - a vector of objects making up the set.
+ */
+ public DLSet(
+ ASN1EncodableVector v)
+ {
+ super(v, false);
+ }
+
+ /**
+ * create a set from an array of objects.
+ */
+ public DLSet(
+ ASN1Encodable[] a)
+ {
+ super(a, false);
+ }
+
+ private int getBodyLength()
+ throws IOException
+ {
+ if (bodyLength < 0)
+ {
+ int length = 0;
+
+ for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength();
+ }
+
+ bodyLength = length;
+ }
+
+ return bodyLength;
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ int length = getBodyLength();
+
+ return 1 + StreamUtil.calculateBodyLength(length) + length;
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DL requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputting SET,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ ASN1OutputStream dOut = out.getDLSubStream();
+ int length = getBodyLength();
+
+ out.write(BERTags.SET | BERTags.CONSTRUCTED);
+ out.writeLength(length);
+
+ for (Enumeration e = this.getObjects(); e.hasMoreElements();)
+ {
+ Object obj = e.nextElement();
+
+ dOut.writeObject((ASN1Encodable)obj);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java b/bcprov/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java
new file mode 100644
index 0000000..4a245df
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DLTaggedObject.java
@@ -0,0 +1,112 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+/**
+ * Definite Length TaggedObject - in ASN.1 notation this is any object preceded by
+ * a [n] where n is some number - these are assumed to follow the construction
+ * rules (as with sequences).
+ */
+public class DLTaggedObject
+ extends ASN1TaggedObject
+{
+ private static final byte[] ZERO_BYTES = new byte[0];
+
+ /**
+ * @param explicit true if an explicitly tagged object.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public DLTaggedObject(
+ boolean explicit,
+ int tagNo,
+ ASN1Encodable obj)
+ {
+ super(explicit, tagNo, obj);
+ }
+
+ boolean isConstructed()
+ {
+ if (!empty)
+ {
+ if (explicit)
+ {
+ return true;
+ }
+ else
+ {
+ ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();
+
+ return primitive.isConstructed();
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ if (!empty)
+ {
+ int length = obj.toASN1Primitive().toDLObject().encodedLength();
+
+ if (explicit)
+ {
+ return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length;
+ }
+ else
+ {
+ // header length already in calculation
+ length = length - 1;
+
+ return StreamUtil.calculateTagLength(tagNo) + length;
+ }
+ }
+ else
+ {
+ return StreamUtil.calculateTagLength(tagNo) + 1;
+ }
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ if (!empty)
+ {
+ ASN1Primitive primitive = obj.toASN1Primitive().toDLObject();
+
+ if (explicit)
+ {
+ out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo);
+ out.writeLength(primitive.encodedLength());
+ out.writeObject(primitive);
+ }
+ else
+ {
+ //
+ // need to mark constructed types...
+ //
+ int flags;
+ if (primitive.isConstructed())
+ {
+ flags = BERTags.CONSTRUCTED | BERTags.TAGGED;
+ }
+ else
+ {
+ flags = BERTags.TAGGED;
+ }
+
+ out.writeTag(flags, tagNo);
+ out.writeImplicitObject(primitive);
+ }
+ }
+ else
+ {
+ out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java
new file mode 100644
index 0000000..3f6ce22
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/DefiniteLengthInputStream.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.asn1;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.util.io.Streams;
+
+class DefiniteLengthInputStream
+ extends LimitedInputStream
+{
+ private static final byte[] EMPTY_BYTES = new byte[0];
+
+ private final int _originalLength;
+ private int _remaining;
+
+ DefiniteLengthInputStream(
+ InputStream in,
+ int length)
+ throws IOException
+ {
+ super(in, length);
+
+ if (length < 0)
+ {
+ throw new IllegalArgumentException("negative lengths not allowed");
+ }
+
+ this._originalLength = length;
+ this._remaining = length;
+
+ if (length == 0)
+ {
+ setParentEofDetect(true);
+ }
+ }
+
+ int getRemaining()
+ {
+ return _remaining;
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (_remaining == 0)
+ {
+ return -1;
+ }
+
+ int b = _in.read();
+
+ if (b < 0)
+ {
+ throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining);
+ }
+
+ if (--_remaining == 0)
+ {
+ setParentEofDetect(true);
+ }
+
+ return b;
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException
+ {
+ if (_remaining == 0)
+ {
+ return -1;
+ }
+
+ int toRead = Math.min(len, _remaining);
+ int numRead = _in.read(buf, off, toRead);
+
+ if (numRead < 0)
+ {
+ throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining);
+ }
+
+ if ((_remaining -= numRead) == 0)
+ {
+ setParentEofDetect(true);
+ }
+
+ return numRead;
+ }
+
+ byte[] toByteArray()
+ throws IOException
+ {
+ if (_remaining == 0)
+ {
+ return EMPTY_BYTES;
+ }
+
+ byte[] bytes = new byte[_remaining];
+ if ((_remaining -= Streams.readFully(_in, bytes)) != 0)
+ {
+ throw new EOFException("DEF length " + _originalLength + " object truncated by " + _remaining);
+ }
+ setParentEofDetect(true);
+ return bytes;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java b/bcprov/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java
new file mode 100644
index 0000000..a4b1492
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/InMemoryRepresentable.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+
+public interface InMemoryRepresentable
+{
+ ASN1Primitive getLoadedObject()
+ throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java
new file mode 100644
index 0000000..353da3b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/IndefiniteLengthInputStream.java
@@ -0,0 +1,111 @@
+package org.bouncycastle.asn1;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+class IndefiniteLengthInputStream
+ extends LimitedInputStream
+{
+ private int _b1;
+ private int _b2;
+ private boolean _eofReached = false;
+ private boolean _eofOn00 = true;
+
+ IndefiniteLengthInputStream(
+ InputStream in,
+ int limit)
+ throws IOException
+ {
+ super(in, limit);
+
+ _b1 = in.read();
+ _b2 = in.read();
+
+ if (_b2 < 0)
+ {
+ // Corrupted stream
+ throw new EOFException();
+ }
+
+ checkForEof();
+ }
+
+ void setEofOn00(
+ boolean eofOn00)
+ {
+ _eofOn00 = eofOn00;
+ checkForEof();
+ }
+
+ private boolean checkForEof()
+ {
+ if (!_eofReached && _eofOn00 && (_b1 == 0x00 && _b2 == 0x00))
+ {
+ _eofReached = true;
+ setParentEofDetect(true);
+ }
+ return _eofReached;
+ }
+
+ public int read(byte[] b, int off, int len)
+ throws IOException
+ {
+ // Only use this optimisation if we aren't checking for 00
+ if (_eofOn00 || len < 3)
+ {
+ return super.read(b, off, len);
+ }
+
+ if (_eofReached)
+ {
+ return -1;
+ }
+
+ int numRead = _in.read(b, off + 2, len - 2);
+
+ if (numRead < 0)
+ {
+ // Corrupted stream
+ throw new EOFException();
+ }
+
+ b[off] = (byte)_b1;
+ b[off + 1] = (byte)_b2;
+
+ _b1 = _in.read();
+ _b2 = _in.read();
+
+ if (_b2 < 0)
+ {
+ // Corrupted stream
+ throw new EOFException();
+ }
+
+ return numRead + 2;
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (checkForEof())
+ {
+ return -1;
+ }
+
+ int b = _in.read();
+
+ if (b < 0)
+ {
+ // Corrupted stream
+ throw new EOFException();
+ }
+
+ int v = _b1;
+
+ _b1 = _b2;
+ _b2 = b;
+
+ return v;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java b/bcprov/src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java
new file mode 100644
index 0000000..31d988d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/LazyConstructionEnumeration.java
@@ -0,0 +1,43 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+class LazyConstructionEnumeration
+ implements Enumeration
+{
+ private ASN1InputStream aIn;
+ private Object nextObj;
+
+ public LazyConstructionEnumeration(byte[] encoded)
+ {
+ aIn = new ASN1InputStream(encoded, true);
+ nextObj = readObject();
+ }
+
+ public boolean hasMoreElements()
+ {
+ return nextObj != null;
+ }
+
+ public Object nextElement()
+ {
+ Object o = nextObj;
+
+ nextObj = readObject();
+
+ return o;
+ }
+
+ private Object readObject()
+ {
+ try
+ {
+ return aIn.readObject();
+ }
+ catch (IOException e)
+ {
+ throw new ASN1ParsingException("malformed DER construction: " + e, e);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java b/bcprov/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java
new file mode 100644
index 0000000..c7342ad
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/LazyEncodedSequence.java
@@ -0,0 +1,109 @@
+package org.bouncycastle.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * Note: this class is for processing DER/DL encoded sequences only.
+ */
+class LazyEncodedSequence
+ extends ASN1Sequence
+{
+ private byte[] encoded;
+
+ LazyEncodedSequence(
+ byte[] encoded)
+ throws IOException
+ {
+ this.encoded = encoded;
+ }
+
+ private void parse()
+ {
+ Enumeration en = new LazyConstructionEnumeration(encoded);
+
+ while (en.hasMoreElements())
+ {
+ seq.addElement(en.nextElement());
+ }
+
+ encoded = null;
+ }
+
+ public synchronized ASN1Encodable getObjectAt(int index)
+ {
+ if (encoded != null)
+ {
+ parse();
+ }
+
+ return super.getObjectAt(index);
+ }
+
+ public synchronized Enumeration getObjects()
+ {
+ if (encoded == null)
+ {
+ return super.getObjects();
+ }
+
+ return new LazyConstructionEnumeration(encoded);
+ }
+
+ public synchronized int size()
+ {
+ if (encoded != null)
+ {
+ parse();
+ }
+
+ return super.size();
+ }
+
+ ASN1Primitive toDERObject()
+ {
+ if (encoded != null)
+ {
+ parse();
+ }
+
+ return super.toDERObject();
+ }
+
+ ASN1Primitive toDLObject()
+ {
+ if (encoded != null)
+ {
+ parse();
+ }
+
+ return super.toDLObject();
+ }
+
+ int encodedLength()
+ throws IOException
+ {
+ if (encoded != null)
+ {
+ return 1 + StreamUtil.calculateBodyLength(encoded.length) + encoded.length;
+ }
+ else
+ {
+ return super.toDLObject().encodedLength();
+ }
+ }
+
+ void encode(
+ ASN1OutputStream out)
+ throws IOException
+ {
+ if (encoded != null)
+ {
+ out.writeEncoded(BERTags.SEQUENCE | BERTags.CONSTRUCTED, encoded);
+ }
+ else
+ {
+ super.toDLObject().encode(out);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java b/bcprov/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java
new file mode 100644
index 0000000..d94b0bd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/LimitedInputStream.java
@@ -0,0 +1,32 @@
+package org.bouncycastle.asn1;
+
+import java.io.InputStream;
+
+abstract class LimitedInputStream
+ extends InputStream
+{
+ protected final InputStream _in;
+ private int _limit;
+
+ LimitedInputStream(
+ InputStream in,
+ int limit)
+ {
+ this._in = in;
+ this._limit = limit;
+ }
+
+ int getRemaining()
+ {
+ // TODO: maybe one day this can become more accurate
+ return _limit;
+ }
+
+ protected void setParentEofDetect(boolean on)
+ {
+ if (_in instanceof IndefiniteLengthInputStream)
+ {
+ ((IndefiniteLengthInputStream)_in).setEofOn00(on);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java b/bcprov/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java
new file mode 100644
index 0000000..5467944
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/OIDTokenizer.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.asn1;
+
+/**
+ * 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.
+ */
+public class OIDTokenizer
+{
+ private String oid;
+ private int index;
+
+ public OIDTokenizer(
+ String oid)
+ {
+ this.oid = oid;
+ this.index = 0;
+ }
+
+ public boolean hasMoreTokens()
+ {
+ return (index != -1);
+ }
+
+ public String nextToken()
+ {
+ if (index == -1)
+ {
+ return null;
+ }
+
+ String token;
+ int end = oid.indexOf('.', index);
+
+ if (end == -1)
+ {
+ token = oid.substring(index);
+ index = -1;
+ return token;
+ }
+
+ token = oid.substring(index, end);
+
+ index = end + 1;
+ return token;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/StreamUtil.java b/bcprov/src/main/java/org/bouncycastle/asn1/StreamUtil.java
new file mode 100644
index 0000000..0a3c4aa
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/StreamUtil.java
@@ -0,0 +1,112 @@
+package org.bouncycastle.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+class StreamUtil
+{
+ private static final long MAX_MEMORY = Runtime.getRuntime().maxMemory();
+
+ /**
+ * Find out possible longest length...
+ *
+ * @param in input stream of interest
+ * @return length calculation or MAX_VALUE.
+ */
+ static int findLimit(InputStream in)
+ {
+ if (in instanceof LimitedInputStream)
+ {
+ return ((LimitedInputStream)in).getRemaining();
+ }
+ else if (in instanceof ASN1InputStream)
+ {
+ return ((ASN1InputStream)in).getLimit();
+ }
+ else if (in instanceof ByteArrayInputStream)
+ {
+ return ((ByteArrayInputStream)in).available();
+ }
+ else if (in instanceof FileInputStream)
+ {
+ try
+ {
+ long size = ((FileInputStream)in).getChannel().size();
+
+ if (size < Integer.MAX_VALUE)
+ {
+ return (int)size;
+ }
+ }
+ catch (IOException e)
+ {
+ // ignore - they'll find out soon enough!
+ }
+ }
+
+ if (MAX_MEMORY > Integer.MAX_VALUE)
+ {
+ return Integer.MAX_VALUE;
+ }
+
+ return (int)MAX_MEMORY;
+ }
+
+ static int calculateBodyLength(
+ int length)
+ {
+ int count = 1;
+
+ if (length > 127)
+ {
+ int size = 1;
+ int val = length;
+
+ while ((val >>>= 8) != 0)
+ {
+ size++;
+ }
+
+ for (int i = (size - 1) * 8; i >= 0; i -= 8)
+ {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ static int calculateTagLength(int tagNo)
+ throws IOException
+ {
+ int length = 1;
+
+ if (tagNo >= 31)
+ {
+ if (tagNo < 128)
+ {
+ length++;
+ }
+ else
+ {
+ byte[] stack = new byte[5];
+ int pos = stack.length;
+
+ stack[--pos] = (byte)(tagNo & 0x7F);
+
+ do
+ {
+ tagNo >>= 7;
+ stack[--pos] = (byte)(tagNo & 0x7F | 0x80);
+ }
+ while (tagNo > 127);
+
+ length += stack.length - pos;
+ }
+ }
+
+ return length;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
new file mode 100644
index 0000000..18fc66c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
@@ -0,0 +1,51 @@
+package org.bouncycastle.asn1.bc;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface BCObjectIdentifiers
+{
+ /**
+ * iso.org.dod.internet.private.enterprise.legion-of-the-bouncy-castle
+ *
+ * 1.3.6.1.4.1.22554
+ */
+ public static final ASN1ObjectIdentifier bc = new ASN1ObjectIdentifier("1.3.6.1.4.1.22554");
+
+ /**
+ * pbe(1) algorithms
+ */
+ public static final ASN1ObjectIdentifier bc_pbe = new ASN1ObjectIdentifier(bc.getId() + ".1");
+
+ /**
+ * SHA-1(1)
+ */
+ public static final ASN1ObjectIdentifier bc_pbe_sha1 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".1");
+
+ /**
+ * SHA-2(2) . (SHA-256(1)|SHA-384(2)|SHA-512(3)|SHA-224(4))
+ */
+ public static final ASN1ObjectIdentifier bc_pbe_sha256 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.1");
+ public static final ASN1ObjectIdentifier bc_pbe_sha384 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.2");
+ public static final ASN1ObjectIdentifier bc_pbe_sha512 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.3");
+ public static final ASN1ObjectIdentifier bc_pbe_sha224 = new ASN1ObjectIdentifier(bc_pbe.getId() + ".2.4");
+
+ /**
+ * PKCS-5(1)|PKCS-12(2)
+ */
+ public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".1");
+ public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha1.getId() + ".2");
+
+ public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs5 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".1");
+ public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12 = new ASN1ObjectIdentifier(bc_pbe_sha256.getId() + ".2");
+
+ /**
+ * AES(1) . (CBC-128(2)|CBC-192(22)|CBC-256(42))
+ */
+ public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.2");
+ public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.22");
+ public static final ASN1ObjectIdentifier bc_pbe_sha1_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha1_pkcs12.getId() + ".1.42");
+
+ public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes128_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.2");
+ public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes192_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.22");
+ public static final ASN1ObjectIdentifier bc_pbe_sha256_pkcs12_aes256_cbc = new ASN1ObjectIdentifier(bc_pbe_sha256_pkcs12.getId() + ".1.42");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
new file mode 100644
index 0000000..b5a2f34
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attribute.java
@@ -0,0 +1,100 @@
+package org.bouncycastle.asn1.cms;
+
+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.ASN1Set;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+public class Attribute
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier attrType;
+ private ASN1Set attrValues;
+
+ /**
+ * return an Attribute object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static Attribute getInstance(
+ Object o)
+ {
+ if (o instanceof Attribute)
+ {
+ return (Attribute)o;
+ }
+
+ if (o != null)
+ {
+ return new Attribute(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ private Attribute(
+ ASN1Sequence seq)
+ {
+ attrType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ 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)
+ {
+ this.attrType = attrType;
+ this.attrValues = attrValues;
+ }
+
+ public ASN1ObjectIdentifier getAttrType()
+ {
+ return attrType;
+ }
+
+ public ASN1Set getAttrValues()
+ {
+ return attrValues;
+ }
+
+ public ASN1Encodable[] getAttributeValues()
+ {
+ return attrValues.toArray();
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * Attribute ::= SEQUENCE {
+ * attrType OBJECT IDENTIFIER,
+ * attrValues SET OF AttributeValue
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attrType);
+ v.add(attrValues);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
new file mode 100644
index 0000000..4c88c7b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java
@@ -0,0 +1,248 @@
+package org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+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;
+
+public class AttributeTable
+{
+ private Hashtable attributes = new Hashtable();
+
+ public AttributeTable(
+ Hashtable attrs)
+ {
+ attributes = copyTable(attrs);
+ }
+
+ public AttributeTable(
+ ASN1EncodableVector v)
+ {
+ for (int i = 0; i != v.size(); i++)
+ {
+ Attribute a = Attribute.getInstance(v.get(i));
+
+ addAttribute(a.getAttrType(), a);
+ }
+ }
+
+ public AttributeTable(
+ ASN1Set s)
+ {
+ for (int i = 0; i != s.size(); i++)
+ {
+ Attribute a = Attribute.getInstance(s.getObjectAt(i));
+
+ addAttribute(a.getAttrType(), a);
+ }
+ }
+
+ public AttributeTable(
+ Attributes attrs)
+ {
+ this(ASN1Set.getInstance(attrs.toASN1Primitive()));
+ }
+
+ private void addAttribute(
+ ASN1ObjectIdentifier oid,
+ Attribute a)
+ {
+ Object value = attributes.get(oid);
+
+ if (value == null)
+ {
+ attributes.put(oid, a);
+ }
+ else
+ {
+ Vector v;
+
+ if (value instanceof Attribute)
+ {
+ v = new Vector();
+
+ v.addElement(value);
+ v.addElement(a);
+ }
+ else
+ {
+ v = (Vector)value;
+
+ v.addElement(a);
+ }
+
+ attributes.put(oid, v);
+ }
+ }
+
+ /**
+ * @deprecated use ASN1ObjectIdentifier
+ */
+ public Attribute get(DERObjectIdentifier oid)
+ {
+ return get(new ASN1ObjectIdentifier(oid.getId()));
+ }
+
+ /**
+ * Return the first attribute matching the OBJECT IDENTIFIER oid.
+ *
+ * @param oid type of attribute required.
+ * @return first attribute found of type oid.
+ */
+ public Attribute get(
+ ASN1ObjectIdentifier oid)
+ {
+ Object value = attributes.get(oid);
+
+ if (value instanceof Vector)
+ {
+ return (Attribute)((Vector)value).elementAt(0);
+ }
+
+ 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.
+ *
+ * @param oid type of attribute required.
+ * @return a vector of all the attributes found of type oid.
+ */
+ public ASN1EncodableVector getAll(
+ ASN1ObjectIdentifier oid)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ Object value = attributes.get(oid);
+
+ if (value instanceof Vector)
+ {
+ Enumeration e = ((Vector)value).elements();
+
+ while (e.hasMoreElements())
+ {
+ v.add((Attribute)e.nextElement());
+ }
+ }
+ else if (value != null)
+ {
+ v.add((Attribute)value);
+ }
+
+ return v;
+ }
+
+ public int size()
+ {
+ int size = 0;
+
+ for (Enumeration en = attributes.elements(); en.hasMoreElements();)
+ {
+ Object o = en.nextElement();
+
+ if (o instanceof Vector)
+ {
+ size += ((Vector)o).size();
+ }
+ else
+ {
+ size++;
+ }
+ }
+
+ return size;
+ }
+
+ public Hashtable toHashtable()
+ {
+ return copyTable(attributes);
+ }
+
+ public ASN1EncodableVector toASN1EncodableVector()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ Enumeration e = attributes.elements();
+
+ while (e.hasMoreElements())
+ {
+ Object value = e.nextElement();
+
+ if (value instanceof Vector)
+ {
+ Enumeration en = ((Vector)value).elements();
+
+ while (en.hasMoreElements())
+ {
+ v.add(Attribute.getInstance(en.nextElement()));
+ }
+ }
+ else
+ {
+ v.add(Attribute.getInstance(value));
+ }
+ }
+
+ return v;
+ }
+
+ public Attributes toASN1Structure()
+ {
+ return new Attributes(this.toASN1EncodableVector());
+ }
+
+ private Hashtable copyTable(
+ Hashtable in)
+ {
+ Hashtable out = new Hashtable();
+ Enumeration e = in.keys();
+
+ while (e.hasMoreElements())
+ {
+ Object key = e.nextElement();
+
+ out.put(key, in.get(key));
+ }
+
+ return out;
+ }
+
+ /**
+ * Return a new table with the passed in attribute added.
+ *
+ * @param attrType
+ * @param attrValue
+ * @return
+ */
+ public AttributeTable add(ASN1ObjectIdentifier attrType, ASN1Encodable attrValue)
+ {
+ AttributeTable newTable = new AttributeTable(attributes);
+
+ newTable.addAttribute(attrType, new Attribute(attrType, new DERSet(attrValue)));
+
+ return newTable;
+ }
+
+ public AttributeTable remove(ASN1ObjectIdentifier attrType)
+ {
+ AttributeTable newTable = new AttributeTable(attributes);
+
+ newTable.attributes.remove(attrType);
+
+ return newTable;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java
new file mode 100644
index 0000000..0c5a518
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Attributes.java
@@ -0,0 +1,49 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.BERSet;
+
+public class Attributes
+ extends ASN1Object
+{
+ private ASN1Set attributes;
+
+ private Attributes(ASN1Set set)
+ {
+ attributes = set;
+ }
+
+ public Attributes(ASN1EncodableVector v)
+ {
+ attributes = new BERSet(v);
+ }
+
+ public static Attributes getInstance(Object obj)
+ {
+ if (obj instanceof Attributes)
+ {
+ return (Attributes)obj;
+ }
+ else if (obj != null)
+ {
+ return new Attributes(ASN1Set.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * <pre>
+ * Attributes ::=
+ * SET SIZE(1..MAX) OF Attribute -- according to RFC 5652
+ * </pre>
+ * @return
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return attributes;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java
new file mode 100644
index 0000000..5e97324
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSAttributes.java
@@ -0,0 +1,13 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+public interface CMSAttributes
+{
+ public static final ASN1ObjectIdentifier contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType;
+ public static final ASN1ObjectIdentifier messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest;
+ public static final ASN1ObjectIdentifier signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime;
+ public static final ASN1ObjectIdentifier counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature;
+ public static final ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
new file mode 100644
index 0000000..e8f4541
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.asn1.cms;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+
+public interface CMSObjectIdentifiers
+{
+ static final ASN1ObjectIdentifier data = PKCSObjectIdentifiers.data;
+ static final ASN1ObjectIdentifier signedData = PKCSObjectIdentifiers.signedData;
+ static final ASN1ObjectIdentifier envelopedData = PKCSObjectIdentifiers.envelopedData;
+ static final ASN1ObjectIdentifier signedAndEnvelopedData = PKCSObjectIdentifiers.signedAndEnvelopedData;
+ static final ASN1ObjectIdentifier digestedData = PKCSObjectIdentifiers.digestedData;
+ static final ASN1ObjectIdentifier encryptedData = PKCSObjectIdentifiers.encryptedData;
+ static final ASN1ObjectIdentifier authenticatedData = PKCSObjectIdentifiers.id_ct_authData;
+ static final ASN1ObjectIdentifier compressedData = PKCSObjectIdentifiers.id_ct_compressedData;
+ static final ASN1ObjectIdentifier authEnvelopedData = PKCSObjectIdentifiers.id_ct_authEnvelopedData;
+ static final ASN1ObjectIdentifier timestampedData = PKCSObjectIdentifiers.id_ct_timestampedData;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
new file mode 100644
index 0000000..a66c4a1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java
@@ -0,0 +1,99 @@
+package org.bouncycastle.asn1.cms;
+
+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.ASN1TaggedObject;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.BERTaggedObject;
+
+public class ContentInfo
+ extends ASN1Object
+ // BEGIN android-removed
+ // implements CMSObjectIdentifiers
+ // END android-removed
+{
+ private ASN1ObjectIdentifier contentType;
+ private ASN1Encodable content;
+
+ public static ContentInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof ContentInfo)
+ {
+ return (ContentInfo)obj;
+ }
+ else if (obj != null)
+ {
+ return new ContentInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ContentInfo(
+ ASN1Sequence seq)
+ {
+ if (seq.size() < 1 || seq.size() > 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+ }
+
+ contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+
+ if (seq.size() > 1)
+ {
+ ASN1TaggedObject tagged = (ASN1TaggedObject)seq.getObjectAt(1);
+ if (!tagged.isExplicit() || tagged.getTagNo() != 0)
+ {
+ throw new IllegalArgumentException("Bad tag for 'content'");
+ }
+
+ content = tagged.getObject();
+ }
+ }
+
+ public ContentInfo(
+ ASN1ObjectIdentifier contentType,
+ ASN1Encodable content)
+ {
+ this.contentType = contentType;
+ this.content = content;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return contentType;
+ }
+
+ public ASN1Encodable getContent()
+ {
+ return content;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * ContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * content
+ * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(contentType);
+
+ if (content != null)
+ {
+ v.add(new BERTaggedObject(0, content));
+ }
+
+ return new BERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java
new file mode 100644
index 0000000..29348d2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java
@@ -0,0 +1,107 @@
+package org.bouncycastle.asn1.cms;
+
+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.DERSequence;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.Certificate;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Name;
+
+public class IssuerAndSerialNumber
+ extends ASN1Object
+{
+ private X500Name name;
+ private ASN1Integer serialNumber;
+
+ public static IssuerAndSerialNumber getInstance(
+ Object obj)
+ {
+ if (obj instanceof IssuerAndSerialNumber)
+ {
+ return (IssuerAndSerialNumber)obj;
+ }
+ else if (obj != null)
+ {
+ return new IssuerAndSerialNumber(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public IssuerAndSerialNumber(
+ ASN1Sequence seq)
+ {
+ this.name = X500Name.getInstance(seq.getObjectAt(0));
+ this.serialNumber = (ASN1Integer)seq.getObjectAt(1);
+ }
+
+ public IssuerAndSerialNumber(
+ Certificate certificate)
+ {
+ this.name = certificate.getIssuer();
+ this.serialNumber = certificate.getSerialNumber();
+ }
+
+ public IssuerAndSerialNumber(
+ X509CertificateStructure certificate)
+ {
+ this.name = certificate.getIssuer();
+ this.serialNumber = certificate.getSerialNumber();
+ }
+
+ public IssuerAndSerialNumber(
+ X500Name name,
+ BigInteger serialNumber)
+ {
+ this.name = name;
+ this.serialNumber = new ASN1Integer(serialNumber);
+ }
+
+ /**
+ * @deprecated use X500Name constructor
+ */
+ public IssuerAndSerialNumber(
+ X509Name name,
+ BigInteger serialNumber)
+ {
+ this.name = X500Name.getInstance(name);
+ this.serialNumber = new ASN1Integer(serialNumber);
+ }
+
+ /**
+ * @deprecated use X500Name constructor
+ */
+ public IssuerAndSerialNumber(
+ X509Name name,
+ ASN1Integer serialNumber)
+ {
+ this.name = X500Name.getInstance(name);
+ this.serialNumber = serialNumber;
+ }
+
+ public X500Name getName()
+ {
+ return name;
+ }
+
+ public ASN1Integer getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(name);
+ v.add(serialNumber);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java
new file mode 100644
index 0000000..a0a34ef
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignedData.java
@@ -0,0 +1,302 @@
+package org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.BERSet;
+import org.bouncycastle.asn1.BERTaggedObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * a signed data object.
+ */
+public class SignedData
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private ASN1Set digestAlgorithms;
+ private ContentInfo contentInfo;
+ private ASN1Set certificates;
+ private ASN1Set crls;
+ private ASN1Set signerInfos;
+ private boolean certsBer;
+ private boolean crlsBer;
+
+ public static SignedData getInstance(
+ Object o)
+ {
+ if (o instanceof SignedData)
+ {
+ return (SignedData)o;
+ }
+ else if (o != null)
+ {
+ return new SignedData(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public SignedData(
+ ASN1Set digestAlgorithms,
+ ContentInfo contentInfo,
+ ASN1Set certificates,
+ ASN1Set crls,
+ ASN1Set signerInfos)
+ {
+ this.version = calculateVersion(contentInfo.getContentType(), certificates, crls, signerInfos);
+ this.digestAlgorithms = digestAlgorithms;
+ this.contentInfo = contentInfo;
+ this.certificates = certificates;
+ this.crls = crls;
+ this.signerInfos = signerInfos;
+ this.crlsBer = crls instanceof BERSet;
+ this.certsBer = certificates instanceof BERSet;
+ }
+
+
+ // RFC3852, section 5.1:
+ // IF ((certificates is present) AND
+ // (any certificates with a type of other are present)) OR
+ // ((crls is present) AND
+ // (any crls with a type of other are present))
+ // THEN version MUST be 5
+ // ELSE
+ // IF (certificates is present) AND
+ // (any version 2 attribute certificates are present)
+ // THEN version MUST be 4
+ // ELSE
+ // IF ((certificates is present) AND
+ // (any version 1 attribute certificates are present)) OR
+ // (any SignerInfo structures are version 3) OR
+ // (encapContentInfo eContentType is other than id-data)
+ // THEN version MUST be 3
+ // ELSE version MUST be 1
+ //
+ private ASN1Integer calculateVersion(
+ ASN1ObjectIdentifier contentOid,
+ ASN1Set certs,
+ ASN1Set crls,
+ ASN1Set signerInfs)
+ {
+ boolean otherCert = false;
+ boolean otherCrl = false;
+ boolean attrCertV1Found = false;
+ boolean attrCertV2Found = false;
+
+ if (certs != null)
+ {
+ for (Enumeration en = certs.getObjects(); en.hasMoreElements();)
+ {
+ Object obj = en.nextElement();
+ if (obj instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(obj);
+
+ if (tagged.getTagNo() == 1)
+ {
+ attrCertV1Found = true;
+ }
+ else if (tagged.getTagNo() == 2)
+ {
+ attrCertV2Found = true;
+ }
+ else if (tagged.getTagNo() == 3)
+ {
+ otherCert = true;
+ }
+ }
+ }
+ }
+
+ if (otherCert)
+ {
+ return new ASN1Integer(5);
+ }
+
+ if (crls != null) // no need to check if otherCert is true
+ {
+ for (Enumeration en = crls.getObjects(); en.hasMoreElements();)
+ {
+ Object obj = en.nextElement();
+ if (obj instanceof ASN1TaggedObject)
+ {
+ otherCrl = true;
+ }
+ }
+ }
+
+ if (otherCrl)
+ {
+ return new ASN1Integer(5);
+ }
+
+ if (attrCertV2Found)
+ {
+ return new ASN1Integer(4);
+ }
+
+ if (attrCertV1Found)
+ {
+ return new ASN1Integer(3);
+ }
+
+ if (checkForVersion3(signerInfs))
+ {
+ return new ASN1Integer(3);
+ }
+
+ if (!CMSObjectIdentifiers.data.equals(contentOid))
+ {
+ return new ASN1Integer(3);
+ }
+
+ return new ASN1Integer(1);
+ }
+
+ private boolean checkForVersion3(ASN1Set signerInfs)
+ {
+ for (Enumeration e = signerInfs.getObjects(); e.hasMoreElements();)
+ {
+ SignerInfo s = SignerInfo.getInstance(e.nextElement());
+
+ if (s.getVersion().getValue().intValue() == 3)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private SignedData(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ version = ASN1Integer.getInstance(e.nextElement());
+ digestAlgorithms = ((ASN1Set)e.nextElement());
+ contentInfo = ContentInfo.getInstance(e.nextElement());
+
+ while (e.hasMoreElements())
+ {
+ ASN1Primitive o = (ASN1Primitive)e.nextElement();
+
+ //
+ // an interesting feature of SignedData is that there appear
+ // to be varying implementations...
+ // for the moment we ignore anything which doesn't fit.
+ //
+ if (o instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tagged = (ASN1TaggedObject)o;
+
+ switch (tagged.getTagNo())
+ {
+ case 0:
+ certsBer = tagged instanceof BERTaggedObject;
+ certificates = ASN1Set.getInstance(tagged, false);
+ break;
+ case 1:
+ crlsBer = tagged instanceof BERTaggedObject;
+ crls = ASN1Set.getInstance(tagged, false);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
+ }
+ }
+ else
+ {
+ signerInfos = (ASN1Set)o;
+ }
+ }
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public ASN1Set getDigestAlgorithms()
+ {
+ return digestAlgorithms;
+ }
+
+ public ContentInfo getEncapContentInfo()
+ {
+ return contentInfo;
+ }
+
+ public ASN1Set getCertificates()
+ {
+ return certificates;
+ }
+
+ public ASN1Set getCRLs()
+ {
+ return crls;
+ }
+
+ public ASN1Set getSignerInfos()
+ {
+ return signerInfos;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * SignedData ::= SEQUENCE {
+ * version CMSVersion,
+ * digestAlgorithms DigestAlgorithmIdentifiers,
+ * encapContentInfo EncapsulatedContentInfo,
+ * certificates [0] IMPLICIT CertificateSet OPTIONAL,
+ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ * signerInfos SignerInfos
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(digestAlgorithms);
+ v.add(contentInfo);
+
+ if (certificates != null)
+ {
+ if (certsBer)
+ {
+ v.add(new BERTaggedObject(false, 0, certificates));
+ }
+ else
+ {
+ v.add(new DERTaggedObject(false, 0, certificates));
+ }
+ }
+
+ if (crls != null)
+ {
+ if (crlsBer)
+ {
+ v.add(new BERTaggedObject(false, 1, crls));
+ }
+ else
+ {
+ v.add(new DERTaggedObject(false, 1, crls));
+ }
+ }
+
+ v.add(signerInfos);
+
+ return new BERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java
new file mode 100644
index 0000000..37b6b31
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.asn1.cms;
+
+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.DERTaggedObject;
+
+public class SignerIdentifier
+ extends ASN1Object
+ implements ASN1Choice
+{
+ private ASN1Encodable id;
+
+ public SignerIdentifier(
+ IssuerAndSerialNumber id)
+ {
+ this.id = id;
+ }
+
+ public SignerIdentifier(
+ ASN1OctetString id)
+ {
+ this.id = new DERTaggedObject(false, 0, id);
+ }
+
+ public SignerIdentifier(
+ ASN1Primitive id)
+ {
+ this.id = id;
+ }
+
+ /**
+ * return a SignerIdentifier object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static SignerIdentifier getInstance(
+ Object o)
+ {
+ if (o == null || o instanceof SignerIdentifier)
+ {
+ return (SignerIdentifier)o;
+ }
+
+ if (o instanceof IssuerAndSerialNumber)
+ {
+ return new SignerIdentifier((IssuerAndSerialNumber)o);
+ }
+
+ if (o instanceof ASN1OctetString)
+ {
+ return new SignerIdentifier((ASN1OctetString)o);
+ }
+
+ if (o instanceof ASN1Primitive)
+ {
+ return new SignerIdentifier((ASN1Primitive)o);
+ }
+
+ throw new IllegalArgumentException(
+ "Illegal object in SignerIdentifier: " + o.getClass().getName());
+ }
+
+ public boolean isTagged()
+ {
+ return (id instanceof ASN1TaggedObject);
+ }
+
+ public ASN1Encodable getId()
+ {
+ if (id instanceof ASN1TaggedObject)
+ {
+ return ASN1OctetString.getInstance((ASN1TaggedObject)id, false);
+ }
+
+ return id;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * SignerIdentifier ::= CHOICE {
+ * issuerAndSerialNumber IssuerAndSerialNumber,
+ * subjectKeyIdentifier [0] SubjectKeyIdentifier
+ * }
+ *
+ * SubjectKeyIdentifier ::= OCTET STRING
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return id.toASN1Primitive();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java
new file mode 100644
index 0000000..0727b68
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java
@@ -0,0 +1,183 @@
+package org.bouncycastle.asn1.cms;
+
+import java.util.Enumeration;
+
+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.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class SignerInfo
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private SignerIdentifier sid;
+ private AlgorithmIdentifier digAlgorithm;
+ private ASN1Set authenticatedAttributes;
+ private AlgorithmIdentifier digEncryptionAlgorithm;
+ private ASN1OctetString encryptedDigest;
+ private ASN1Set unauthenticatedAttributes;
+
+ public static SignerInfo getInstance(
+ Object o)
+ throws IllegalArgumentException
+ {
+ if (o == null || o instanceof SignerInfo)
+ {
+ return (SignerInfo)o;
+ }
+ else if (o instanceof ASN1Sequence)
+ {
+ return new SignerInfo((ASN1Sequence)o);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName());
+ }
+
+ public SignerInfo(
+ SignerIdentifier sid,
+ AlgorithmIdentifier digAlgorithm,
+ ASN1Set authenticatedAttributes,
+ AlgorithmIdentifier digEncryptionAlgorithm,
+ ASN1OctetString encryptedDigest,
+ ASN1Set unauthenticatedAttributes)
+ {
+ if (sid.isTagged())
+ {
+ this.version = new ASN1Integer(3);
+ }
+ else
+ {
+ this.version = new ASN1Integer(1);
+ }
+
+ this.sid = sid;
+ this.digAlgorithm = digAlgorithm;
+ this.authenticatedAttributes = authenticatedAttributes;
+ this.digEncryptionAlgorithm = digEncryptionAlgorithm;
+ this.encryptedDigest = encryptedDigest;
+ this.unauthenticatedAttributes = unauthenticatedAttributes;
+ }
+
+ public SignerInfo(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ version = (ASN1Integer)e.nextElement();
+ sid = SignerIdentifier.getInstance(e.nextElement());
+ digAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+
+ Object obj = e.nextElement();
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ authenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)obj, false);
+
+ digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement());
+ }
+ else
+ {
+ authenticatedAttributes = null;
+ digEncryptionAlgorithm = AlgorithmIdentifier.getInstance(obj);
+ }
+
+ encryptedDigest = DEROctetString.getInstance(e.nextElement());
+
+ if (e.hasMoreElements())
+ {
+ unauthenticatedAttributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false);
+ }
+ else
+ {
+ unauthenticatedAttributes = null;
+ }
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public SignerIdentifier getSID()
+ {
+ return sid;
+ }
+
+ public ASN1Set getAuthenticatedAttributes()
+ {
+ return authenticatedAttributes;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ return digAlgorithm;
+ }
+
+ public ASN1OctetString getEncryptedDigest()
+ {
+ return encryptedDigest;
+ }
+
+ public AlgorithmIdentifier getDigestEncryptionAlgorithm()
+ {
+ return digEncryptionAlgorithm;
+ }
+
+ public ASN1Set getUnauthenticatedAttributes()
+ {
+ return unauthenticatedAttributes;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * SignerInfo ::= SEQUENCE {
+ * version Version,
+ * SignerIdentifier sid,
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+ * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+ * encryptedDigest EncryptedDigest,
+ * unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+ * }
+ *
+ * EncryptedDigest ::= OCTET STRING
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(sid);
+ v.add(digAlgorithm);
+
+ if (authenticatedAttributes != null)
+ {
+ v.add(new DERTaggedObject(false, 0, authenticatedAttributes));
+ }
+
+ v.add(digEncryptionAlgorithm);
+ v.add(encryptedDigest);
+
+ if (unauthenticatedAttributes != null)
+ {
+ v.add(new DERTaggedObject(false, 1, unauthenticatedAttributes));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java
new file mode 100644
index 0000000..2087248
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/cms/Time.java
@@ -0,0 +1,128 @@
+package org.bouncycastle.asn1.cms;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.SimpleTimeZone;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERUTCTime;
+
+public class Time
+ extends ASN1Object
+ implements ASN1Choice
+{
+ ASN1Primitive time;
+
+ public static Time getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(obj.getObject());
+ }
+
+ public Time(
+ ASN1Primitive time)
+ {
+ if (!(time instanceof DERUTCTime)
+ && !(time instanceof DERGeneralizedTime))
+ {
+ throw new IllegalArgumentException("unknown object passed to Time");
+ }
+
+ this.time = time;
+ }
+
+ /**
+ * 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.
+ */
+ public Time(
+ Date date)
+ {
+ SimpleTimeZone tz = new SimpleTimeZone(0, "Z");
+ SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss");
+
+ dateF.setTimeZone(tz);
+
+ String d = dateF.format(date) + "Z";
+ int year = Integer.parseInt(d.substring(0, 4));
+
+ if (year < 1950 || year > 2049)
+ {
+ time = new DERGeneralizedTime(d);
+ }
+ else
+ {
+ time = new DERUTCTime(d.substring(2));
+ }
+ }
+
+ public static Time getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof Time)
+ {
+ return (Time)obj;
+ }
+ else if (obj instanceof DERUTCTime)
+ {
+ return new Time((DERUTCTime)obj);
+ }
+ else if (obj instanceof DERGeneralizedTime)
+ {
+ return new Time((DERGeneralizedTime)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ public String getTime()
+ {
+ if (time instanceof DERUTCTime)
+ {
+ return ((DERUTCTime)time).getAdjustedTime();
+ }
+ else
+ {
+ return ((DERGeneralizedTime)time).getTime();
+ }
+ }
+
+ public Date getDate()
+ {
+ try
+ {
+ if (time instanceof DERUTCTime)
+ {
+ return ((DERUTCTime)time).getAdjustedDate();
+ }
+ else
+ {
+ return ((DERGeneralizedTime)time).getDate();
+ }
+ }
+ catch (ParseException e)
+ { // this should never happen
+ throw new IllegalStateException("invalid date string: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return time;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java
new file mode 100644
index 0000000..bef8620
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/eac/EACObjectIdentifiers.java
@@ -0,0 +1,55 @@
+package org.bouncycastle.asn1.eac;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface EACObjectIdentifiers
+{
+ // bsi-de OBJECT IDENTIFIER ::= {
+ // itu-t(0) identified-organization(4) etsi(0)
+ // reserved(127) etsi-identified-organization(0) 7
+ // }
+ static final ASN1ObjectIdentifier bsi_de = new ASN1ObjectIdentifier("0.4.0.127.0.7");
+
+ // id-PK OBJECT IDENTIFIER ::= {
+ // bsi-de protocols(2) smartcard(2) 1
+ // }
+ static final ASN1ObjectIdentifier id_PK = bsi_de.branch("2.2.1");
+
+ static final ASN1ObjectIdentifier id_PK_DH = id_PK.branch("1");
+ static final ASN1ObjectIdentifier id_PK_ECDH = id_PK.branch("2");
+
+ // id-CA OBJECT IDENTIFIER ::= {
+ // bsi-de protocols(2) smartcard(2) 3
+ // }
+ static final ASN1ObjectIdentifier id_CA = bsi_de.branch("2.2.3");
+ static final ASN1ObjectIdentifier id_CA_DH = id_CA.branch("1");
+ static final ASN1ObjectIdentifier id_CA_DH_3DES_CBC_CBC = id_CA_DH.branch("1");
+ static final ASN1ObjectIdentifier id_CA_ECDH = id_CA.branch("2");
+ static final ASN1ObjectIdentifier id_CA_ECDH_3DES_CBC_CBC = id_CA_ECDH.branch("1");
+
+ //
+ // id-TA OBJECT IDENTIFIER ::= {
+ // bsi-de protocols(2) smartcard(2) 2
+ // }
+ static final ASN1ObjectIdentifier id_TA = bsi_de.branch("2.2.2");
+
+ static final ASN1ObjectIdentifier id_TA_RSA = id_TA.branch("1");
+ static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_1 = id_TA_RSA .branch("1");
+ static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_256 = id_TA_RSA.branch("2");
+ static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_1 = id_TA_RSA.branch("3");
+ static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_256 = id_TA_RSA.branch("4");
+ static final ASN1ObjectIdentifier id_TA_RSA_v1_5_SHA_512 = id_TA_RSA.branch("5");
+ static final ASN1ObjectIdentifier id_TA_RSA_PSS_SHA_512 = id_TA_RSA.branch("6");
+ static final ASN1ObjectIdentifier id_TA_ECDSA = id_TA.branch("2");
+ static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_1 = id_TA_ECDSA.branch("1");
+ static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_224 = id_TA_ECDSA.branch("2");
+ static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_256 = id_TA_ECDSA.branch("3");
+ static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_384 = id_TA_ECDSA.branch("4");
+ static final ASN1ObjectIdentifier id_TA_ECDSA_SHA_512 = id_TA_ECDSA.branch("5");
+
+ /**
+ * id-EAC-ePassport OBJECT IDENTIFIER ::= {
+ * bsi-de applications(3) mrtd(1) roles(2) 1}
+ */
+ static final ASN1ObjectIdentifier id_EAC_ePassport = bsi_de.branch("3.1.2.1");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
new file mode 100644
index 0000000..e9ab8d6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.asn1.iana;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface IANAObjectIdentifiers
+{
+ // id-SHA1 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
+ //
+
+ static final ASN1ObjectIdentifier isakmpOakley = new ASN1ObjectIdentifier("1.3.6.1.5.5.8.1");
+
+ static final ASN1ObjectIdentifier hmacMD5 = new ASN1ObjectIdentifier(isakmpOakley + ".1");
+ static final ASN1ObjectIdentifier hmacSHA1 = new ASN1ObjectIdentifier(isakmpOakley + ".2");
+
+ static final ASN1ObjectIdentifier hmacTIGER = new ASN1ObjectIdentifier(isakmpOakley + ".3");
+
+ static final ASN1ObjectIdentifier hmacRIPEMD160 = new ASN1ObjectIdentifier(isakmpOakley + ".4");
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
new file mode 100644
index 0000000..bc2ac8d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java
@@ -0,0 +1,180 @@
+package org.bouncycastle.asn1.isismtt;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface ISISMTTObjectIdentifiers
+{
+
+ static final ASN1ObjectIdentifier id_isismtt = new ASN1ObjectIdentifier("1.3.36.8");
+
+ static final ASN1ObjectIdentifier id_isismtt_cp = id_isismtt.branch("1");
+
+ /**
+ * The id-isismtt-cp-accredited OID indicates that the certificate is a
+ * qualified certificate according to Directive 1999/93/EC of the European
+ * Parliament and of the Council of 13 December 1999 on a Community
+ * Framework for Electronic Signatures, which additionally conforms the
+ * special requirements of the SigG and has been issued by an accredited CA.
+ */
+ static final ASN1ObjectIdentifier id_isismtt_cp_accredited = id_isismtt_cp.branch("1");
+
+ static final ASN1ObjectIdentifier id_isismtt_at = id_isismtt.branch("3");
+
+ /**
+ * Certificate extensionDate of certificate generation
+ *
+ * <pre>
+ * DateOfCertGenSyntax ::= GeneralizedTime
+ * </pre>
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_dateOfCertGen = id_isismtt_at.branch("1");
+
+ /**
+ * Attribute to indicate that the certificate holder may sign in the name of
+ * a third person. May also be used as extension in a certificate.
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_procuration = id_isismtt_at.branch("2");
+
+ /**
+ * Attribute to indicate admissions to certain professions. May be used as
+ * attribute in attribute certificate or as extension in a certificate
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_admission = id_isismtt_at.branch("3");
+
+ /**
+ * Monetary limit for transactions. The QcEuMonetaryLimit QC statement MUST
+ * be used in new certificates in place of the extension/attribute
+ * MonetaryLimit since January 1, 2004. For the sake of backward
+ * compatibility with certificates already in use, SigG conforming
+ * components MUST support MonetaryLimit (as well as QcEuLimitValue).
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_monetaryLimit = id_isismtt_at.branch("4");
+
+ /**
+ * A declaration of majority. May be used as attribute in attribute
+ * certificate or as extension in a certificate
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_declarationOfMajority = id_isismtt_at.branch("5");
+
+ /**
+ *
+ * Serial number of the smart card containing the corresponding private key
+ *
+ * <pre>
+ * ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
+ * </pre>
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_iCCSN = id_isismtt_at.branch("6");
+
+ /**
+ *
+ * Reference for a file of a smartcard that stores the public key of this
+ * certificate and that is used as �security anchor�.
+ *
+ * <pre>
+ * PKReferenceSyntax ::= OCTET STRING (SIZE(20))
+ * </pre>
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_PKReference = id_isismtt_at.branch("7");
+
+ /**
+ * Some other restriction regarding the usage of this certificate. May be
+ * used as attribute in attribute certificate or as extension in a
+ * certificate.
+ *
+ * <pre>
+ * RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+ * </pre>
+ *
+ * @see org.bouncycastle.asn1.isismtt.x509.Restriction
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_restriction = id_isismtt_at.branch("8");
+
+ /**
+ *
+ * (Single)Request extension: Clients may include this extension in a
+ * (single) Request to request the responder to send the certificate in the
+ * response message along with the status information. Besides the LDAP
+ * service, this extension provides another mechanism for the distribution
+ * of certificates, which MAY optionally be provided by certificate
+ * repositories.
+ *
+ * <pre>
+ * RetrieveIfAllowed ::= BOOLEAN
+ *
+ * </pre>
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_retrieveIfAllowed = id_isismtt_at.branch("9");
+
+ /**
+ * SingleOCSPResponse extension: The certificate requested by the client by
+ * inserting the RetrieveIfAllowed extension in the request, will be
+ * returned in this extension.
+ *
+ * @see org.bouncycastle.asn1.isismtt.ocsp.RequestedCertificate
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_requestedCertificate = id_isismtt_at.branch("10");
+
+ /**
+ * Base ObjectIdentifier for naming authorities
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_namingAuthorities = id_isismtt_at.branch("11");
+
+ /**
+ * SingleOCSPResponse extension: Date, when certificate has been published
+ * in the directory and status information has become available. Currently,
+ * accrediting authorities enforce that SigG-conforming OCSP servers include
+ * this extension in the responses.
+ *
+ * <pre>
+ * CertInDirSince ::= GeneralizedTime
+ * </pre>
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_certInDirSince = id_isismtt_at.branch("12");
+
+ /**
+ * Hash of a certificate in OCSP.
+ *
+ * @see org.bouncycastle.asn1.isismtt.ocsp.CertHash
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_certHash = id_isismtt_at.branch("13");
+
+ /**
+ * <pre>
+ * NameAtBirth ::= DirectoryString(SIZE(1..64)
+ * </pre>
+ *
+ * Used in
+ * {@link org.bouncycastle.asn1.x509.SubjectDirectoryAttributes SubjectDirectoryAttributes}
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_nameAtBirth = id_isismtt_at.branch("14");
+
+ /**
+ * Some other information of non-restrictive nature regarding the usage of
+ * this certificate. May be used as attribute in atribute certificate or as
+ * extension in a certificate.
+ *
+ * <pre>
+ * AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+ * </pre>
+ *
+ * @see org.bouncycastle.asn1.isismtt.x509.AdditionalInformationSyntax
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_additionalInformation = id_isismtt_at.branch("15");
+
+ /**
+ * Indicates that an attribute certificate exists, which limits the
+ * usability of this public key certificate. Whenever verifying a signature
+ * with the help of this certificate, the content of the corresponding
+ * attribute certificate should be concerned. This extension MUST be
+ * included in a PKC, if a corresponding attribute certificate (having the
+ * PKC as base certificate) contains some attribute that restricts the
+ * usability of the PKC too. Attribute certificates with restricting content
+ * MUST always be included in the signed document.
+ *
+ * <pre>
+ * LiabilityLimitationFlagSyntax ::= BOOLEAN
+ * </pre>
+ */
+ static final ASN1ObjectIdentifier id_isismtt_at_liabilityLimitationFlag = new ASN1ObjectIdentifier("0.2.262.1.10.12.0");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
new file mode 100644
index 0000000..73e0c58
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.asn1.kisa;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface KISAObjectIdentifiers
+{
+ public static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4");
+ public static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
new file mode 100644
index 0000000..debf268
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.asn1.misc;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface MiscObjectIdentifiers
+{
+ //
+ // Netscape
+ // iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) }
+ //
+ static final ASN1ObjectIdentifier netscape = new ASN1ObjectIdentifier("2.16.840.1.113730.1");
+ static final ASN1ObjectIdentifier netscapeCertType = netscape.branch("1");
+ static final ASN1ObjectIdentifier netscapeBaseURL = netscape.branch("2");
+ static final ASN1ObjectIdentifier netscapeRevocationURL = netscape.branch("3");
+ static final ASN1ObjectIdentifier netscapeCARevocationURL = netscape.branch("4");
+ static final ASN1ObjectIdentifier netscapeRenewalURL = netscape.branch("7");
+ static final ASN1ObjectIdentifier netscapeCApolicyURL = netscape.branch("8");
+ static final ASN1ObjectIdentifier netscapeSSLServerName = netscape.branch("12");
+ static final ASN1ObjectIdentifier netscapeCertComment = netscape.branch("13");
+
+ //
+ // Verisign
+ // iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
+ //
+ static final ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1");
+
+ //
+ // CZAG - country, zip, age, and gender
+ //
+ static final ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3");
+ // D&B D-U-N-S number
+ static final ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15");
+
+ //
+ // Novell
+ // iso/itu(2) country(16) us(840) organization(1) novell(113719)
+ //
+ static final ASN1ObjectIdentifier novell = new ASN1ObjectIdentifier("2.16.840.1.113719");
+ static final ASN1ObjectIdentifier novellSecurityAttribs = novell.branch("1.9.4.1");
+
+ //
+ // Entrust
+ // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
+ //
+ static final ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7");
+ static final ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java b/bcprov/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
new file mode 100644
index 0000000..846a205
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
@@ -0,0 +1,54 @@
+package org.bouncycastle.asn1.misc;
+
+import org.bouncycastle.asn1.DERBitString;
+
+/**
+ * The NetscapeCertType object.
+ * <pre>
+ * NetscapeCertType ::= BIT STRING {
+ * SSLClient (0),
+ * SSLServer (1),
+ * S/MIME (2),
+ * Object Signing (3),
+ * Reserved (4),
+ * SSL CA (5),
+ * S/MIME CA (6),
+ * Object Signing CA (7) }
+ * </pre>
+ */
+public class NetscapeCertType
+ extends DERBitString
+{
+ public static final int sslClient = (1 << 7);
+ public static final int sslServer = (1 << 6);
+ public static final int smime = (1 << 5);
+ public static final int objectSigning = (1 << 4);
+ public static final int reserved = (1 << 3);
+ public static final int sslCA = (1 << 2);
+ public static final int smimeCA = (1 << 1);
+ public static final int objectSigningCA = (1 << 0);
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA)
+ */
+ public NetscapeCertType(
+ int usage)
+ {
+ super(getBytes(usage), getPadBits(usage));
+ }
+
+ public NetscapeCertType(
+ DERBitString usage)
+ {
+ super(usage.getBytes(), usage.getPadBits());
+ }
+
+ public String toString()
+ {
+ return "NetscapeCertType: 0x" + Integer.toHexString(data[0] & 0xff);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java b/bcprov/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
new file mode 100644
index 0000000..c0347da
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.asn1.misc;
+
+import org.bouncycastle.asn1.DERIA5String;
+
+public class NetscapeRevocationURL
+ extends DERIA5String
+{
+ public NetscapeRevocationURL(
+ DERIA5String str)
+ {
+ super(str.getString());
+ }
+
+ public String toString()
+ {
+ return "NetscapeRevocationURL: " + this.getString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java b/bcprov/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
new file mode 100644
index 0000000..f09880a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.asn1.misc;
+
+import org.bouncycastle.asn1.DERIA5String;
+
+public class VerisignCzagExtension
+ extends DERIA5String
+{
+ public VerisignCzagExtension(
+ DERIA5String str)
+ {
+ super(str.getString());
+ }
+
+ public String toString()
+ {
+ return "VerisignCzagExtension: " + this.getString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
new file mode 100644
index 0000000..97712b5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTNamedCurves.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.asn1.nist;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.util.Strings;
+
+/**
+ * Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-2
+ */
+public class NISTNamedCurves
+{
+ static final Hashtable objIds = new Hashtable();
+ static final Hashtable names = new Hashtable();
+
+ static void defineCurve(String name, ASN1ObjectIdentifier oid)
+ {
+ objIds.put(name, oid);
+ names.put(oid, name);
+ }
+
+ static
+ {
+ // TODO Missing the "K-" curves
+
+ 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("P-521", SECObjectIdentifiers.secp521r1);
+ defineCurve("P-384", SECObjectIdentifiers.secp384r1);
+ defineCurve("P-256", SECObjectIdentifiers.secp256r1);
+ defineCurve("P-224", SECObjectIdentifiers.secp224r1);
+ defineCurve("P-192", SECObjectIdentifiers.secp192r1);
+ }
+
+ public static X9ECParameters getByName(
+ String name)
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toUpperCase(name));
+
+ if (oid != null)
+ {
+ return getByOID(oid);
+ }
+
+ return null;
+ }
+
+ /**
+ * 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)
+ {
+ return SECNamedCurves.getByOID(oid);
+ }
+
+ /**
+ * 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)objIds.get(Strings.toUpperCase(name));
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static String getName(
+ ASN1ObjectIdentifier oid)
+ {
+ return (String)names.get(oid);
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static Enumeration getNames()
+ {
+ return objIds.keys();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
new file mode 100644
index 0000000..258f269
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/nist/NISTObjectIdentifiers.java
@@ -0,0 +1,56 @@
+package org.bouncycastle.asn1.nist;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface NISTObjectIdentifiers
+{
+ //
+ // NIST
+ // iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3)
+
+ //
+ // nistalgorithms(4)
+ //
+ static final ASN1ObjectIdentifier nistAlgorithm = new ASN1ObjectIdentifier("2.16.840.1.101.3.4");
+
+ static final ASN1ObjectIdentifier id_sha256 = nistAlgorithm.branch("2.1");
+ static final ASN1ObjectIdentifier id_sha384 = nistAlgorithm.branch("2.2");
+ static final ASN1ObjectIdentifier id_sha512 = nistAlgorithm.branch("2.3");
+ static final ASN1ObjectIdentifier id_sha224 = nistAlgorithm.branch("2.4");
+
+ static final ASN1ObjectIdentifier aes = nistAlgorithm.branch("1");
+
+ static final ASN1ObjectIdentifier id_aes128_ECB = aes.branch("1");
+ static final ASN1ObjectIdentifier id_aes128_CBC = aes.branch("2");
+ static final ASN1ObjectIdentifier id_aes128_OFB = aes.branch("3");
+ static final ASN1ObjectIdentifier id_aes128_CFB = aes.branch("4");
+ static final ASN1ObjectIdentifier id_aes128_wrap = aes.branch("5");
+ static final ASN1ObjectIdentifier id_aes128_GCM = aes.branch("6");
+ static final ASN1ObjectIdentifier id_aes128_CCM = aes.branch("7");
+
+ static final ASN1ObjectIdentifier id_aes192_ECB = aes.branch("21");
+ static final ASN1ObjectIdentifier id_aes192_CBC = aes.branch("22");
+ static final ASN1ObjectIdentifier id_aes192_OFB = aes.branch("23");
+ static final ASN1ObjectIdentifier id_aes192_CFB = aes.branch("24");
+ static final ASN1ObjectIdentifier id_aes192_wrap = aes.branch("25");
+ static final ASN1ObjectIdentifier id_aes192_GCM = aes.branch("26");
+ static final ASN1ObjectIdentifier id_aes192_CCM = aes.branch("27");
+
+ static final ASN1ObjectIdentifier id_aes256_ECB = aes.branch("41");
+ static final ASN1ObjectIdentifier id_aes256_CBC = aes.branch("42");
+ static final ASN1ObjectIdentifier id_aes256_OFB = aes.branch("43");
+ static final ASN1ObjectIdentifier id_aes256_CFB = aes.branch("44");
+ static final ASN1ObjectIdentifier id_aes256_wrap = aes.branch("45");
+ static final ASN1ObjectIdentifier id_aes256_GCM = aes.branch("46");
+ static final ASN1ObjectIdentifier id_aes256_CCM = aes.branch("47");
+
+ //
+ // signatures
+ //
+ static final ASN1ObjectIdentifier id_dsa_with_sha2 = nistAlgorithm.branch("3");
+
+ static final ASN1ObjectIdentifier dsa_with_sha224 = id_dsa_with_sha2.branch("1");
+ static final ASN1ObjectIdentifier dsa_with_sha256 = id_dsa_with_sha2.branch("2");
+ static final ASN1ObjectIdentifier dsa_with_sha384 = id_dsa_with_sha2.branch("3");
+ static final ASN1ObjectIdentifier dsa_with_sha512 = id_dsa_with_sha2.branch("4");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
new file mode 100644
index 0000000..2e4132a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.asn1.ntt;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * From RFC 3657
+ */
+public interface NTTObjectIdentifiers
+{
+ public static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.2");
+ public static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.3");
+ public static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.4");
+
+ public static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.2");
+ public static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.3");
+ public static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.4");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
new file mode 100644
index 0000000..c8ce26b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
@@ -0,0 +1,31 @@
+package org.bouncycastle.asn1.oiw;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface OIWObjectIdentifiers
+{
+ // id-SHA1 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } //
+ static final ASN1ObjectIdentifier md4WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.2");
+ static final ASN1ObjectIdentifier md5WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.3");
+ static final ASN1ObjectIdentifier md4WithRSAEncryption = new ASN1ObjectIdentifier("1.3.14.3.2.4");
+
+ static final ASN1ObjectIdentifier desECB = new ASN1ObjectIdentifier("1.3.14.3.2.6");
+ static final ASN1ObjectIdentifier desCBC = new ASN1ObjectIdentifier("1.3.14.3.2.7");
+ static final ASN1ObjectIdentifier desOFB = new ASN1ObjectIdentifier("1.3.14.3.2.8");
+ static final ASN1ObjectIdentifier desCFB = new ASN1ObjectIdentifier("1.3.14.3.2.9");
+
+ static final ASN1ObjectIdentifier desEDE = new ASN1ObjectIdentifier("1.3.14.3.2.17");
+
+ static final ASN1ObjectIdentifier idSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26");
+
+ static final ASN1ObjectIdentifier dsaWithSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.27");
+
+ static final ASN1ObjectIdentifier sha1WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.29");
+
+ // ElGamal Algorithm OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
+ //
+ static final ASN1ObjectIdentifier elGamalAlgorithm = new ASN1ObjectIdentifier("1.3.14.7.2.1.1");
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java
new file mode 100644
index 0000000..ea4779b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java
@@ -0,0 +1,74 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.DLSequence;
+
+public class AuthenticatedSafe
+ extends ASN1Object
+{
+ private ContentInfo[] info;
+ private boolean isBer = true;
+
+ private AuthenticatedSafe(
+ ASN1Sequence seq)
+ {
+ info = new ContentInfo[seq.size()];
+
+ for (int i = 0; i != info.length; i++)
+ {
+ info[i] = ContentInfo.getInstance(seq.getObjectAt(i));
+ }
+
+ isBer = seq instanceof BERSequence;
+ }
+
+ public static AuthenticatedSafe getInstance(
+ Object o)
+ {
+ if (o instanceof AuthenticatedSafe)
+ {
+ return (AuthenticatedSafe)o;
+ }
+
+ if (o != null)
+ {
+ return new AuthenticatedSafe(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public AuthenticatedSafe(
+ ContentInfo[] info)
+ {
+ this.info = info;
+ }
+
+ public ContentInfo[] getContentInfo()
+ {
+ return info;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (int i = 0; i != info.length; i++)
+ {
+ v.add(info[i]);
+ }
+
+ if (isBer)
+ {
+ return new BERSequence(v);
+ }
+ else
+ {
+ return new DLSequence(v);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java
new file mode 100644
index 0000000..b91c1a5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CRLBag.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.asn1.pkcs;
+
+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.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class CRLBag
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier crlId;
+ private ASN1Encodable crlValue;
+
+ private CRLBag(
+ ASN1Sequence seq)
+ {
+ this.crlId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ this.crlValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject();
+ }
+
+ public static CRLBag getInstance(Object o)
+ {
+ if (o instanceof CRLBag)
+ {
+ return (CRLBag)o;
+ }
+ else if (o != null)
+ {
+ return new CRLBag(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public CRLBag(
+ ASN1ObjectIdentifier crlId,
+ ASN1Encodable crlValue)
+ {
+ this.crlId = crlId;
+ this.crlValue = crlValue;
+ }
+
+ public ASN1ObjectIdentifier getcrlId()
+ {
+ return crlId;
+ }
+
+ public ASN1Encodable getCRLValue()
+ {
+ return crlValue;
+ }
+
+ /**
+ * <pre>
+ 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
+ }
+ </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(crlId);
+ v.add(new DERTaggedObject(0, crlValue));
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java
new file mode 100644
index 0000000..4a73028
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertBag.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.asn1.pkcs;
+
+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.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class CertBag
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier certId;
+ private ASN1Encodable certValue;
+
+ private CertBag(
+ ASN1Sequence seq)
+ {
+ this.certId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ this.certValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject();
+ }
+
+ public static CertBag getInstance(Object o)
+ {
+ if (o instanceof CertBag)
+ {
+ return (CertBag)o;
+ }
+ else if (o != null)
+ {
+ return new CertBag(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public CertBag(
+ ASN1ObjectIdentifier certId,
+ ASN1Encodable certValue)
+ {
+ this.certId = certId;
+ this.certValue = certValue;
+ }
+
+ public ASN1ObjectIdentifier getCertId()
+ {
+ return certId;
+ }
+
+ public ASN1Encodable getCertValue()
+ {
+ return certValue;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(certId);
+ v.add(new DERTaggedObject(0, certValue));
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
new file mode 100644
index 0000000..987d4eb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequest.java
@@ -0,0 +1,91 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * PKCS10 Certification request object.
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
+ * signature BIT STRING
+ * }
+ * </pre>
+ */
+public class CertificationRequest
+ extends ASN1Object
+{
+ protected CertificationRequestInfo reqInfo = null;
+ protected AlgorithmIdentifier sigAlgId = null;
+ protected DERBitString sigBits = null;
+
+ public static CertificationRequest getInstance(Object o)
+ {
+ if (o instanceof CertificationRequest)
+ {
+ return (CertificationRequest)o;
+ }
+
+ if (o != null)
+ {
+ return new CertificationRequest(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ protected CertificationRequest()
+ {
+ }
+
+ public CertificationRequest(
+ CertificationRequestInfo requestInfo,
+ AlgorithmIdentifier algorithm,
+ DERBitString signature)
+ {
+ this.reqInfo = requestInfo;
+ this.sigAlgId = algorithm;
+ this.sigBits = signature;
+ }
+
+ public CertificationRequest(
+ ASN1Sequence seq)
+ {
+ reqInfo = CertificationRequestInfo.getInstance(seq.getObjectAt(0));
+ sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+ sigBits = (DERBitString)seq.getObjectAt(2);
+ }
+
+ public CertificationRequestInfo getCertificationRequestInfo()
+ {
+ return reqInfo;
+ }
+
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return sigAlgId;
+ }
+
+ public DERBitString getSignature()
+ {
+ return sigBits;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ // Construct the CertificateRequest
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(reqInfo);
+ v.add(sigAlgId);
+ v.add(sigBits);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
new file mode 100644
index 0000000..aac2bb7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java
@@ -0,0 +1,148 @@
+package org.bouncycastle.asn1.pkcs;
+
+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.ASN1Set;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * PKCS10 CertificationRequestInfo object.
+ * <pre>
+ * CertificationRequestInfo ::= SEQUENCE {
+ * version INTEGER { v1(0) } (v1,...),
+ * subject Name,
+ * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ * attributes [0] Attributes{{ CRIAttributes }}
+ * }
+ *
+ * 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})
+ * }
+ * </pre>
+ */
+public class CertificationRequestInfo
+ extends ASN1Object
+{
+ ASN1Integer version = new ASN1Integer(0);
+ X500Name subject;
+ SubjectPublicKeyInfo subjectPKInfo;
+ ASN1Set attributes = null;
+
+ public static CertificationRequestInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof CertificationRequestInfo)
+ {
+ return (CertificationRequestInfo)obj;
+ }
+ else if (obj != null)
+ {
+ return new CertificationRequestInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public CertificationRequestInfo(
+ X500Name subject,
+ SubjectPublicKeyInfo pkInfo,
+ ASN1Set attributes)
+ {
+ this.subject = subject;
+ this.subjectPKInfo = pkInfo;
+ this.attributes = attributes;
+
+ if ((subject == null) || (version == null) || (subjectPKInfo == null))
+ {
+ throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
+ }
+ }
+
+ /**
+ * @deprecated use X500Name method.
+ */
+ public CertificationRequestInfo(
+ X509Name subject,
+ SubjectPublicKeyInfo pkInfo,
+ ASN1Set attributes)
+ {
+ this.subject = X500Name.getInstance(subject.toASN1Primitive());
+ this.subjectPKInfo = pkInfo;
+ this.attributes = attributes;
+
+ if ((subject == null) || (version == null) || (subjectPKInfo == null))
+ {
+ throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
+ }
+ }
+
+ public CertificationRequestInfo(
+ ASN1Sequence seq)
+ {
+ version = (ASN1Integer)seq.getObjectAt(0);
+
+ subject = X500Name.getInstance(seq.getObjectAt(1));
+ subjectPKInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(2));
+
+ //
+ // some CertificationRequestInfo objects seem to treat this field
+ // as optional.
+ //
+ if (seq.size() > 3)
+ {
+ DERTaggedObject tagobj = (DERTaggedObject)seq.getObjectAt(3);
+ attributes = ASN1Set.getInstance(tagobj, false);
+ }
+
+ if ((subject == null) || (version == null) || (subjectPKInfo == null))
+ {
+ throw new IllegalArgumentException("Not all mandatory fields set in CertificationRequestInfo generator.");
+ }
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public X500Name getSubject()
+ {
+ return subject;
+ }
+
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return subjectPKInfo;
+ }
+
+ public ASN1Set getAttributes()
+ {
+ return attributes;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(subject);
+ v.add(subjectPKInfo);
+
+ if (attributes != null)
+ {
+ v.add(new DERTaggedObject(false, 0, attributes));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java
new file mode 100644
index 0000000..1ee920f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/ContentInfo.java
@@ -0,0 +1,102 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+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.ASN1TaggedObject;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.BERTaggedObject;
+import org.bouncycastle.asn1.DLSequence;
+
+public class ContentInfo
+ extends ASN1Object
+ implements PKCSObjectIdentifiers
+{
+ private ASN1ObjectIdentifier contentType;
+ private ASN1Encodable content;
+ private boolean isBer = true;
+
+ public static ContentInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof ContentInfo)
+ {
+ return (ContentInfo)obj;
+ }
+
+ if (obj != null)
+ {
+ return new ContentInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private ContentInfo(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ contentType = (ASN1ObjectIdentifier)e.nextElement();
+
+ if (e.hasMoreElements())
+ {
+ content = ((ASN1TaggedObject)e.nextElement()).getObject();
+ }
+
+ isBer = seq instanceof BERSequence;
+ }
+
+ public ContentInfo(
+ ASN1ObjectIdentifier contentType,
+ ASN1Encodable content)
+ {
+ this.contentType = contentType;
+ this.content = content;
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return contentType;
+ }
+
+ public ASN1Encodable getContent()
+ {
+ return content;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * ContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * content
+ * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(contentType);
+
+ if (content != null)
+ {
+ v.add(new BERTaggedObject(true, 0, content));
+ }
+
+ if (isBer)
+ {
+ return new BERSequence(v);
+ }
+ else
+ {
+ return new DLSequence(v);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java
new file mode 100644
index 0000000..fa22f79
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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.DERSequence;
+
+public class DHParameter
+ extends ASN1Object
+{
+ ASN1Integer p, g, l;
+
+ public DHParameter(
+ BigInteger p,
+ BigInteger g,
+ int l)
+ {
+ this.p = new ASN1Integer(p);
+ this.g = new ASN1Integer(g);
+
+ if (l != 0)
+ {
+ this.l = new ASN1Integer(l);
+ }
+ else
+ {
+ this.l = null;
+ }
+ }
+
+ public static DHParameter getInstance(
+ Object obj)
+ {
+ if (obj instanceof DHParameter)
+ {
+ return (DHParameter)obj;
+ }
+
+ if (obj != null)
+ {
+ return new DHParameter(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private DHParameter(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ p = ASN1Integer.getInstance(e.nextElement());
+ g = ASN1Integer.getInstance(e.nextElement());
+
+ if (e.hasMoreElements())
+ {
+ l = (ASN1Integer)e.nextElement();
+ }
+ else
+ {
+ l = null;
+ }
+ }
+
+ public BigInteger getP()
+ {
+ return p.getPositiveValue();
+ }
+
+ public BigInteger getG()
+ {
+ return g.getPositiveValue();
+ }
+
+ public BigInteger getL()
+ {
+ if (l == null)
+ {
+ return null;
+ }
+
+ return l.getPositiveValue();
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(p);
+ v.add(g);
+
+ if (this.getL() != null)
+ {
+ v.add(l);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
new file mode 100644
index 0000000..e0f5efd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java
@@ -0,0 +1,115 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+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.BERSequence;
+import org.bouncycastle.asn1.BERTaggedObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+/**
+ * The EncryptedData object.
+ * <pre>
+ * EncryptedData ::= SEQUENCE {
+ * version Version,
+ * encryptedContentInfo EncryptedContentInfo
+ * }
+ *
+ *
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+ * }
+ *
+ * EncryptedContent ::= OCTET STRING
+ * </pre>
+ */
+public class EncryptedData
+ extends ASN1Object
+{
+ ASN1Sequence data;
+ ASN1ObjectIdentifier bagId;
+ ASN1Primitive bagValue;
+
+ public static EncryptedData getInstance(
+ Object obj)
+ {
+ if (obj instanceof EncryptedData)
+ {
+ return (EncryptedData)obj;
+ }
+
+ if (obj != null)
+ {
+ return new EncryptedData(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private EncryptedData(
+ ASN1Sequence seq)
+ {
+ int version = ((ASN1Integer)seq.getObjectAt(0)).getValue().intValue();
+
+ if (version != 0)
+ {
+ throw new IllegalArgumentException("sequence not version 0");
+ }
+
+ this.data = ASN1Sequence.getInstance(seq.getObjectAt(1));
+ }
+
+ public EncryptedData(
+ ASN1ObjectIdentifier contentType,
+ AlgorithmIdentifier encryptionAlgorithm,
+ ASN1Encodable content)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(contentType);
+ v.add(encryptionAlgorithm.toASN1Primitive());
+ v.add(new BERTaggedObject(false, 0, content));
+
+ data = new BERSequence(v);
+ }
+
+ public ASN1ObjectIdentifier getContentType()
+ {
+ return ASN1ObjectIdentifier.getInstance(data.getObjectAt(0));
+ }
+
+ public AlgorithmIdentifier getEncryptionAlgorithm()
+ {
+ return AlgorithmIdentifier.getInstance(data.getObjectAt(1));
+ }
+
+ public ASN1OctetString getContent()
+ {
+ if (data.size() == 3)
+ {
+ ASN1TaggedObject o = ASN1TaggedObject.getInstance(data.getObjectAt(2));
+
+ return ASN1OctetString.getInstance(o, false);
+ }
+
+ return null;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(0));
+ v.add(data);
+
+ return new BERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
new file mode 100644
index 0000000..2aa2fae
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class EncryptedPrivateKeyInfo
+ extends ASN1Object
+{
+ private AlgorithmIdentifier algId;
+ private ASN1OctetString data;
+
+ private EncryptedPrivateKeyInfo(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ algId = AlgorithmIdentifier.getInstance(e.nextElement());
+ data = ASN1OctetString.getInstance(e.nextElement());
+ }
+
+ public EncryptedPrivateKeyInfo(
+ AlgorithmIdentifier algId,
+ byte[] encoding)
+ {
+ this.algId = algId;
+ this.data = new DEROctetString(encoding);
+ }
+
+ public static EncryptedPrivateKeyInfo getInstance(
+ Object obj)
+ {
+ // BEGIN android-changed
+ // fix copy and paste error in instanceof call
+ if (obj instanceof EncryptedPrivateKeyInfo)
+ {
+ return (EncryptedPrivateKeyInfo)obj;
+ }
+ // END android-changed
+ else if (obj != null)
+ {
+ return new EncryptedPrivateKeyInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public AlgorithmIdentifier getEncryptionAlgorithm()
+ {
+ return algId;
+ }
+
+ public byte[] getEncryptedData()
+ {
+ return data.getOctets();
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * EncryptedPrivateKeyInfo ::= SEQUENCE {
+ * encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
+ * encryptedData EncryptedData
+ * }
+ *
+ * EncryptedData ::= OCTET STRING
+ *
+ * KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * ... -- For local profiles
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(algId);
+ v.add(data);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
new file mode 100644
index 0000000..613c3f4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/EncryptionScheme.java
@@ -0,0 +1,55 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+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;
+
+public class EncryptionScheme
+ extends AlgorithmIdentifier
+{
+ public EncryptionScheme(
+ ASN1ObjectIdentifier objectId,
+ ASN1Encodable parameters)
+ {
+ super(objectId, parameters);
+ }
+
+ EncryptionScheme(
+ ASN1Sequence seq)
+ {
+ this((ASN1ObjectIdentifier)seq.getObjectAt(0), seq.getObjectAt(1));
+ }
+
+ public static final AlgorithmIdentifier getInstance(Object obj)
+ {
+ if (obj instanceof EncryptionScheme)
+ {
+ return (EncryptionScheme)obj;
+ }
+ else if (obj instanceof ASN1Sequence)
+ {
+ return new EncryptionScheme((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ public ASN1Primitive getObject()
+ {
+ return (ASN1Primitive)getParameters();
+ }
+
+ public ASN1Primitive getASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(getObjectId());
+ v.add(getParameters());
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java
new file mode 100644
index 0000000..bb94440
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java
@@ -0,0 +1,85 @@
+package org.bouncycastle.asn1.pkcs;
+
+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.DERSequence;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.X509Name;
+
+public class IssuerAndSerialNumber
+ extends ASN1Object
+{
+ X500Name name;
+ ASN1Integer certSerialNumber;
+
+ public static IssuerAndSerialNumber getInstance(
+ Object obj)
+ {
+ if (obj instanceof IssuerAndSerialNumber)
+ {
+ return (IssuerAndSerialNumber)obj;
+ }
+ else if (obj instanceof ASN1Sequence)
+ {
+ return new IssuerAndSerialNumber((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ public IssuerAndSerialNumber(
+ ASN1Sequence seq)
+ {
+ this.name = X500Name.getInstance(seq.getObjectAt(0));
+ this.certSerialNumber = (ASN1Integer)seq.getObjectAt(1);
+ }
+
+ public IssuerAndSerialNumber(
+ X509Name name,
+ BigInteger certSerialNumber)
+ {
+ this.name = X500Name.getInstance(name.toASN1Primitive());
+ this.certSerialNumber = new ASN1Integer(certSerialNumber);
+ }
+
+ public IssuerAndSerialNumber(
+ X509Name name,
+ ASN1Integer certSerialNumber)
+ {
+ this.name = X500Name.getInstance(name.toASN1Primitive());
+ this.certSerialNumber = certSerialNumber;
+ }
+
+ public IssuerAndSerialNumber(
+ X500Name name,
+ BigInteger certSerialNumber)
+ {
+ this.name = name;
+ this.certSerialNumber = new ASN1Integer(certSerialNumber);
+ }
+
+ public X500Name getName()
+ {
+ return name;
+ }
+
+ public ASN1Integer getCertificateSerialNumber()
+ {
+ return certSerialNumber;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(name);
+ v.add(certSerialNumber);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
new file mode 100644
index 0000000..fef4f07
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/KeyDerivationFunc.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class KeyDerivationFunc
+ extends AlgorithmIdentifier
+{
+ KeyDerivationFunc(
+ ASN1Sequence seq)
+ {
+ super(seq);
+ }
+
+ public KeyDerivationFunc(
+ ASN1ObjectIdentifier id,
+ ASN1Encodable params)
+ {
+ super(id, params);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
new file mode 100644
index 0000000..1d8f582
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/MacData.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+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.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.DigestInfo;
+
+public class MacData
+ extends ASN1Object
+{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
+ DigestInfo digInfo;
+ byte[] salt;
+ BigInteger iterationCount;
+
+ public static MacData getInstance(
+ Object obj)
+ {
+ if (obj instanceof MacData)
+ {
+ return (MacData)obj;
+ }
+ else if (obj != null)
+ {
+ return new MacData(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private MacData(
+ ASN1Sequence seq)
+ {
+ this.digInfo = DigestInfo.getInstance(seq.getObjectAt(0));
+
+ this.salt = ((ASN1OctetString)seq.getObjectAt(1)).getOctets();
+
+ if (seq.size() == 3)
+ {
+ this.iterationCount = ((ASN1Integer)seq.getObjectAt(2)).getValue();
+ }
+ else
+ {
+ this.iterationCount = ONE;
+ }
+ }
+
+ public MacData(
+ DigestInfo digInfo,
+ byte[] salt,
+ int iterationCount)
+ {
+ this.digInfo = digInfo;
+ this.salt = salt;
+ this.iterationCount = BigInteger.valueOf(iterationCount);
+ }
+
+ public DigestInfo getMac()
+ {
+ return digInfo;
+ }
+
+ public byte[] getSalt()
+ {
+ return salt;
+ }
+
+ public BigInteger getIterationCount()
+ {
+ return iterationCount;
+ }
+
+ /**
+ * <pre>
+ * MacData ::= SEQUENCE {
+ * mac DigestInfo,
+ * macSalt OCTET STRING,
+ * iterations INTEGER DEFAULT 1
+ * -- Note: The default is for historic reasons and its use is deprecated. A
+ * -- higher value, like 1024 is recommended.
+ * </pre>
+ * @return the basic ASN1Primitive construction.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(digInfo);
+ v.add(new DEROctetString(salt));
+
+ if (!iterationCount.equals(ONE))
+ {
+ v.add(new ASN1Integer(iterationCount));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java
new file mode 100644
index 0000000..06180df
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+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.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PBEParameter
+ extends ASN1Object
+{
+ ASN1Integer iterations;
+ ASN1OctetString salt;
+
+ public PBEParameter(
+ byte[] salt,
+ int iterations)
+ {
+ if (salt.length != 8)
+ {
+ throw new IllegalArgumentException("salt length must be 8");
+ }
+ this.salt = new DEROctetString(salt);
+ this.iterations = new ASN1Integer(iterations);
+ }
+
+ private PBEParameter(
+ ASN1Sequence seq)
+ {
+ salt = (ASN1OctetString)seq.getObjectAt(0);
+ iterations = (ASN1Integer)seq.getObjectAt(1);
+ }
+
+ public static PBEParameter getInstance(
+ Object obj)
+ {
+ if (obj instanceof PBEParameter)
+ {
+ return (PBEParameter)obj;
+ }
+ else if (obj != null)
+ {
+ return new PBEParameter(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public BigInteger getIterationCount()
+ {
+ return iterations.getValue();
+ }
+
+ public byte[] getSalt()
+ {
+ return salt.getOctets();
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(salt);
+ v.add(iterations);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java
new file mode 100644
index 0000000..06c9455
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Algorithms.java
@@ -0,0 +1,77 @@
+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 = new KeyDerivationFunc(funcSeq);
+ }
+
+ scheme = new EncryptionScheme((ASN1Sequence)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/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
new file mode 100644
index 0000000..5ada493
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBES2Parameters.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PBES2Parameters
+ extends ASN1Object
+ implements PKCSObjectIdentifiers
+{
+ private KeyDerivationFunc func;
+ private EncryptionScheme scheme;
+
+ public static PBES2Parameters getInstance(
+ Object obj)
+ {
+ if (obj== null || obj instanceof PBES2Parameters)
+ {
+ return (PBES2Parameters)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new PBES2Parameters((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ public PBES2Parameters(
+ ASN1Sequence obj)
+ {
+ Enumeration e = obj.getObjects();
+ ASN1Sequence funcSeq = ASN1Sequence.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive());
+
+ if (funcSeq.getObjectAt(0).equals(id_PBKDF2))
+ {
+ func = new KeyDerivationFunc(id_PBKDF2, PBKDF2Params.getInstance(funcSeq.getObjectAt(1)));
+ }
+ else
+ {
+ func = new KeyDerivationFunc(funcSeq);
+ }
+
+ scheme = (EncryptionScheme)EncryptionScheme.getInstance(e.nextElement());
+ }
+
+ public KeyDerivationFunc getKeyDerivationFunc()
+ {
+ return func;
+ }
+
+ public EncryptionScheme getEncryptionScheme()
+ {
+ return scheme;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(func);
+ v.add(scheme);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
new file mode 100644
index 0000000..f46c294
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PBKDF2Params
+ extends ASN1Object
+{
+ private ASN1OctetString octStr;
+ private ASN1Integer iterationCount;
+ private ASN1Integer keyLength;
+
+ public static PBKDF2Params getInstance(
+ Object obj)
+ {
+ if (obj instanceof PBKDF2Params)
+ {
+ return (PBKDF2Params)obj;
+ }
+
+ if (obj != null)
+ {
+ return new PBKDF2Params(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public PBKDF2Params(
+ byte[] salt,
+ int iterationCount)
+ {
+ this.octStr = new DEROctetString(salt);
+ this.iterationCount = new ASN1Integer(iterationCount);
+ }
+
+ public PBKDF2Params(
+ byte[] salt,
+ int iterationCount,
+ int keyLength)
+ {
+ this(salt, iterationCount);
+
+ this.keyLength = new ASN1Integer(keyLength);
+ }
+
+ private PBKDF2Params(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ octStr = (ASN1OctetString)e.nextElement();
+ iterationCount = (ASN1Integer)e.nextElement();
+
+ if (e.hasMoreElements())
+ {
+ keyLength = (ASN1Integer)e.nextElement();
+ }
+ else
+ {
+ keyLength = null;
+ }
+ }
+
+ public byte[] getSalt()
+ {
+ return octStr.getOctets();
+ }
+
+ public BigInteger getIterationCount()
+ {
+ return iterationCount.getValue();
+ }
+
+ public BigInteger getKeyLength()
+ {
+ if (keyLength != null)
+ {
+ return keyLength.getValue();
+ }
+
+ return null;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(octStr);
+ v.add(iterationCount);
+
+ if (keyLength != null)
+ {
+ v.add(keyLength);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java
new file mode 100644
index 0000000..0ddf5c3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java
@@ -0,0 +1,69 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+
+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.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class PKCS12PBEParams
+ extends ASN1Object
+{
+ ASN1Integer iterations;
+ ASN1OctetString iv;
+
+ public PKCS12PBEParams(
+ byte[] salt,
+ int iterations)
+ {
+ this.iv = new DEROctetString(salt);
+ this.iterations = new ASN1Integer(iterations);
+ }
+
+ private PKCS12PBEParams(
+ ASN1Sequence seq)
+ {
+ iv = (ASN1OctetString)seq.getObjectAt(0);
+ iterations = ASN1Integer.getInstance(seq.getObjectAt(1));
+ }
+
+ public static PKCS12PBEParams getInstance(
+ Object obj)
+ {
+ if (obj instanceof PKCS12PBEParams)
+ {
+ return (PKCS12PBEParams)obj;
+ }
+ else if (obj != null)
+ {
+ return new PKCS12PBEParams(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public BigInteger getIterations()
+ {
+ return iterations.getValue();
+ }
+
+ public byte[] getIV()
+ {
+ return iv.getOctets();
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(iv);
+ v.add(iterations);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
new file mode 100644
index 0000000..fa4c20e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java
@@ -0,0 +1,267 @@
+package org.bouncycastle.asn1.pkcs;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface PKCSObjectIdentifiers
+{
+ //
+ // pkcs-1 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+ //
+ static final ASN1ObjectIdentifier pkcs_1 = new ASN1ObjectIdentifier("1.2.840.113549.1.1");
+ static final ASN1ObjectIdentifier rsaEncryption = pkcs_1.branch("1");
+ // BEGIN android-removed
+ // static final ASN1ObjectIdentifier md2WithRSAEncryption = pkcs_1.branch("2");
+ // static final ASN1ObjectIdentifier md4WithRSAEncryption = pkcs_1.branch("3");
+ // END android-removed
+ static final ASN1ObjectIdentifier md5WithRSAEncryption = pkcs_1.branch("4");
+ static final ASN1ObjectIdentifier sha1WithRSAEncryption = pkcs_1.branch("5");
+ static final ASN1ObjectIdentifier srsaOAEPEncryptionSET = pkcs_1.branch("6");
+ static final ASN1ObjectIdentifier id_RSAES_OAEP = pkcs_1.branch("7");
+ static final ASN1ObjectIdentifier id_mgf1 = pkcs_1.branch("8");
+ static final ASN1ObjectIdentifier id_pSpecified = pkcs_1.branch("9");
+ static final ASN1ObjectIdentifier id_RSASSA_PSS = pkcs_1.branch("10");
+ static final ASN1ObjectIdentifier sha256WithRSAEncryption = pkcs_1.branch("11");
+ static final ASN1ObjectIdentifier sha384WithRSAEncryption = pkcs_1.branch("12");
+ static final ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13");
+ // BEGIN android-removed
+ // static final ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14");
+ // END android-removed
+
+ //
+ // pkcs-3 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 }
+ //
+ static final ASN1ObjectIdentifier pkcs_3 = new ASN1ObjectIdentifier("1.2.840.113549.1.3");
+ static final ASN1ObjectIdentifier dhKeyAgreement = pkcs_3.branch("1");
+
+ //
+ // pkcs-5 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 }
+ //
+ static final ASN1ObjectIdentifier pkcs_5 = new ASN1ObjectIdentifier("1.2.840.113549.1.5");
+
+ static final ASN1ObjectIdentifier pbeWithMD2AndDES_CBC = pkcs_5.branch("1");
+ static final ASN1ObjectIdentifier pbeWithMD2AndRC2_CBC = pkcs_5.branch("4");
+ static final ASN1ObjectIdentifier pbeWithMD5AndDES_CBC = pkcs_5.branch("3");
+ static final ASN1ObjectIdentifier pbeWithMD5AndRC2_CBC = pkcs_5.branch("6");
+ static final ASN1ObjectIdentifier pbeWithSHA1AndDES_CBC = pkcs_5.branch("10");
+ static final ASN1ObjectIdentifier pbeWithSHA1AndRC2_CBC = pkcs_5.branch("11");
+
+ static final ASN1ObjectIdentifier id_PBES2 = pkcs_5.branch("13");
+
+ static final ASN1ObjectIdentifier id_PBKDF2 = pkcs_5.branch("12");
+
+ //
+ // encryptionAlgorithm OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) 3 }
+ //
+ static final ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.3");
+
+ static final ASN1ObjectIdentifier des_EDE3_CBC = encryptionAlgorithm.branch("7");
+ static final ASN1ObjectIdentifier RC2_CBC = encryptionAlgorithm.branch("2");
+
+ //
+ // object identifiers for digests
+ //
+ static final ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.2");
+ //
+ // md2 OBJECT IDENTIFIER ::=
+ // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2}
+ //
+ // BEGIN android-removed
+ // static final ASN1ObjectIdentifier md2 = digestAlgorithm.branch("2");
+ // END android-removed
+
+ //
+ // md4 OBJECT IDENTIFIER ::=
+ // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4}
+ //
+ // BEGIN android-removed
+ // static final ASN1ObjectIdentifier md4 = digestAlgorithm.branch("4");
+ // END android-removed
+
+ //
+ // md5 OBJECT IDENTIFIER ::=
+ // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}
+ //
+ static final ASN1ObjectIdentifier md5 = digestAlgorithm.branch("5");
+
+ static final ASN1ObjectIdentifier id_hmacWithSHA1 = digestAlgorithm.branch("7");
+ // BEGIN android-removed
+ // static final ASN1ObjectIdentifier id_hmacWithSHA224 = digestAlgorithm.branch("8");
+ // END android-removed
+ static final ASN1ObjectIdentifier id_hmacWithSHA256 = digestAlgorithm.branch("9");
+ static final ASN1ObjectIdentifier id_hmacWithSHA384 = digestAlgorithm.branch("10");
+ static final ASN1ObjectIdentifier id_hmacWithSHA512 = digestAlgorithm.branch("11");
+
+ //
+ // pkcs-7 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 }
+ //
+ static final String pkcs_7 = "1.2.840.113549.1.7";
+ static final ASN1ObjectIdentifier data = new ASN1ObjectIdentifier(pkcs_7 + ".1");
+ static final ASN1ObjectIdentifier signedData = new ASN1ObjectIdentifier(pkcs_7 + ".2");
+ static final ASN1ObjectIdentifier envelopedData = new ASN1ObjectIdentifier(pkcs_7 + ".3");
+ static final ASN1ObjectIdentifier signedAndEnvelopedData = new ASN1ObjectIdentifier(pkcs_7 + ".4");
+ static final ASN1ObjectIdentifier digestedData = new ASN1ObjectIdentifier(pkcs_7 + ".5");
+ static final ASN1ObjectIdentifier encryptedData = new ASN1ObjectIdentifier(pkcs_7 + ".6");
+
+ //
+ // pkcs-9 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 }
+ //
+ static final ASN1ObjectIdentifier pkcs_9 = new ASN1ObjectIdentifier("1.2.840.113549.1.9");
+
+ static final ASN1ObjectIdentifier pkcs_9_at_emailAddress = pkcs_9.branch("1");
+ static final ASN1ObjectIdentifier pkcs_9_at_unstructuredName = pkcs_9.branch("2");
+ static final ASN1ObjectIdentifier pkcs_9_at_contentType = pkcs_9.branch("3");
+ static final ASN1ObjectIdentifier pkcs_9_at_messageDigest = pkcs_9.branch("4");
+ static final ASN1ObjectIdentifier pkcs_9_at_signingTime = pkcs_9.branch("5");
+ static final ASN1ObjectIdentifier pkcs_9_at_counterSignature = pkcs_9.branch("6");
+ static final ASN1ObjectIdentifier pkcs_9_at_challengePassword = pkcs_9.branch("7");
+ static final ASN1ObjectIdentifier pkcs_9_at_unstructuredAddress = pkcs_9.branch("8");
+ static final ASN1ObjectIdentifier pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9");
+
+ static final ASN1ObjectIdentifier pkcs_9_at_signingDescription = pkcs_9.branch("13");
+ static final ASN1ObjectIdentifier pkcs_9_at_extensionRequest = pkcs_9.branch("14");
+ static final ASN1ObjectIdentifier pkcs_9_at_smimeCapabilities = pkcs_9.branch("15");
+
+ static final ASN1ObjectIdentifier pkcs_9_at_friendlyName = pkcs_9.branch("20");
+ static final ASN1ObjectIdentifier pkcs_9_at_localKeyId = pkcs_9.branch("21");
+
+ /** @deprecated use x509Certificate instead */
+ static final ASN1ObjectIdentifier x509certType = pkcs_9.branch("22.1");
+
+ static final ASN1ObjectIdentifier certTypes = pkcs_9.branch("22");
+ static final ASN1ObjectIdentifier x509Certificate = certTypes.branch("1");
+ static final ASN1ObjectIdentifier sdsiCertificate = certTypes.branch("2");
+
+ static final ASN1ObjectIdentifier crlTypes = pkcs_9.branch("23");
+ static final ASN1ObjectIdentifier x509Crl = crlTypes.branch("1");
+
+ static final ASN1ObjectIdentifier id_alg_PWRI_KEK = pkcs_9.branch("16.3.9");
+
+ //
+ // SMIME capability sub oids.
+ //
+ static final ASN1ObjectIdentifier preferSignedData = pkcs_9.branch("15.1");
+ static final ASN1ObjectIdentifier canNotDecryptAny = pkcs_9.branch("15.2");
+ static final ASN1ObjectIdentifier sMIMECapabilitiesVersions = pkcs_9.branch("15.3");
+
+ //
+ // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+ // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)}
+ //
+ static final ASN1ObjectIdentifier id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1");
+
+ static final ASN1ObjectIdentifier id_ct_authData = id_ct.branch("2");
+ static final ASN1ObjectIdentifier id_ct_TSTInfo = id_ct.branch("4");
+ static final ASN1ObjectIdentifier id_ct_compressedData = id_ct.branch("9");
+ static final ASN1ObjectIdentifier id_ct_authEnvelopedData = id_ct.branch("23");
+ static final ASN1ObjectIdentifier id_ct_timestampedData = id_ct.branch("31");
+
+ //
+ // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+ // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)}
+ //
+ static final ASN1ObjectIdentifier id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6");
+
+ static final ASN1ObjectIdentifier id_cti_ets_proofOfOrigin = id_cti.branch("1");
+ static final ASN1ObjectIdentifier id_cti_ets_proofOfReceipt = id_cti.branch("2");
+ static final ASN1ObjectIdentifier id_cti_ets_proofOfDelivery = id_cti.branch("3");
+ static final ASN1ObjectIdentifier id_cti_ets_proofOfSender = id_cti.branch("4");
+ static final ASN1ObjectIdentifier id_cti_ets_proofOfApproval = id_cti.branch("5");
+ static final ASN1ObjectIdentifier id_cti_ets_proofOfCreation = id_cti.branch("6");
+
+ //
+ // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+ // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)}
+ //
+ static final ASN1ObjectIdentifier id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2");
+
+
+ static final ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1");
+
+ static final ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch("4"); // See RFC 2634
+ static final ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch("5");
+ static final ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch("10");
+ /*
+ * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11}
+ *
+ */
+ static final ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11");
+ static final ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12");
+ static final ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47");
+
+ static final ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch("7"); // See RFC 2634
+
+ /*
+ * RFC 3126
+ */
+ static final ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch("14");
+
+ static final ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15");
+ static final ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16");
+ static final ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17");
+ static final ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch("18");
+ static final ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19");
+ static final ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20");
+ static final ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21");
+ static final ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22");
+ static final ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23");
+ static final ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24");
+ static final ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25");
+ static final ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26");
+ static final ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27");
+
+ /** @deprecated use id_aa_ets_sigPolicyId instead */
+ static final ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId;
+ /** @deprecated use id_aa_ets_commitmentType instead */
+ static final ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType;
+ /** @deprecated use id_aa_ets_signerLocation instead */
+ static final ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation;
+ /** @deprecated use id_aa_ets_otherSigCert instead */
+ static final ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert;
+
+ //
+ // id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840)
+ // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) id-spq(5)}
+ //
+ final String id_spq = "1.2.840.113549.1.9.16.5";
+
+ static final ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1");
+ static final ASN1ObjectIdentifier id_spq_ets_unotice = new ASN1ObjectIdentifier(id_spq + ".2");
+
+ //
+ // pkcs-12 OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 }
+ //
+ static final ASN1ObjectIdentifier pkcs_12 = new ASN1ObjectIdentifier("1.2.840.113549.1.12");
+ static final ASN1ObjectIdentifier bagtypes = pkcs_12.branch("10.1");
+
+ static final ASN1ObjectIdentifier keyBag = bagtypes.branch("1");
+ static final ASN1ObjectIdentifier pkcs8ShroudedKeyBag = bagtypes.branch("2");
+ static final ASN1ObjectIdentifier certBag = bagtypes.branch("3");
+ static final ASN1ObjectIdentifier crlBag = bagtypes.branch("4");
+ static final ASN1ObjectIdentifier secretBag = bagtypes.branch("5");
+ static final ASN1ObjectIdentifier safeContentsBag = bagtypes.branch("6");
+
+ static final ASN1ObjectIdentifier pkcs_12PbeIds = pkcs_12.branch("1");
+
+ static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1");
+ static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC4 = pkcs_12PbeIds.branch("2");
+ static final ASN1ObjectIdentifier pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3");
+ static final ASN1ObjectIdentifier pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4");
+ static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5");
+ static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6");
+
+ /**
+ * @deprecated use pbeWithSHAAnd40BitRC2_CBC
+ */
+ static final ASN1ObjectIdentifier pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6");
+
+ static final ASN1ObjectIdentifier id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6");
+ static final ASN1ObjectIdentifier id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7");
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
new file mode 100644
index 0000000..7885a79
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
@@ -0,0 +1,87 @@
+package org.bouncycastle.asn1.pkcs;
+
+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.BERSequence;
+
+/**
+ * the infamous Pfx from PKCS12
+ */
+public class Pfx
+ extends ASN1Object
+ implements PKCSObjectIdentifiers
+{
+ private ContentInfo contentInfo;
+ private MacData macData = null;
+
+ private Pfx(
+ ASN1Sequence seq)
+ {
+ BigInteger version = ((ASN1Integer)seq.getObjectAt(0)).getValue();
+ if (version.intValue() != 3)
+ {
+ throw new IllegalArgumentException("wrong version for PFX PDU");
+ }
+
+ contentInfo = ContentInfo.getInstance(seq.getObjectAt(1));
+
+ if (seq.size() == 3)
+ {
+ macData = MacData.getInstance(seq.getObjectAt(2));
+ }
+ }
+
+ public static Pfx getInstance(
+ Object obj)
+ {
+ if (obj instanceof Pfx)
+ {
+ return (Pfx)obj;
+ }
+
+ if (obj != null)
+ {
+ return new Pfx(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public Pfx(
+ ContentInfo contentInfo,
+ MacData macData)
+ {
+ this.contentInfo = contentInfo;
+ this.macData = macData;
+ }
+
+ public ContentInfo getAuthSafe()
+ {
+ return contentInfo;
+ }
+
+ public MacData getMacData()
+ {
+ return macData;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(3));
+ v.add(contentInfo);
+
+ if (macData != null)
+ {
+ v.add(macData);
+ }
+
+ return new BERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
new file mode 100644
index 0000000..6b42763
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java
@@ -0,0 +1,160 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+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.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class PrivateKeyInfo
+ extends ASN1Object
+{
+ private ASN1OctetString privKey;
+ private AlgorithmIdentifier algId;
+ private ASN1Set attributes;
+
+ public static PrivateKeyInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static PrivateKeyInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof PrivateKeyInfo)
+ {
+ return (PrivateKeyInfo)obj;
+ }
+ else if (obj != null)
+ {
+ return new PrivateKeyInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public PrivateKeyInfo(
+ AlgorithmIdentifier algId,
+ ASN1Encodable privateKey)
+ throws IOException
+ {
+ this(algId, privateKey, null);
+ }
+
+ public PrivateKeyInfo(
+ AlgorithmIdentifier algId,
+ ASN1Encodable privateKey,
+ ASN1Set attributes)
+ throws IOException
+ {
+ this.privKey = new DEROctetString(privateKey.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ this.algId = algId;
+ this.attributes = attributes;
+ }
+
+ public PrivateKeyInfo(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ BigInteger version = ((ASN1Integer)e.nextElement()).getValue();
+ if (version.intValue() != 0)
+ {
+ throw new IllegalArgumentException("wrong version for private key info");
+ }
+
+ algId = AlgorithmIdentifier.getInstance(e.nextElement());
+ privKey = ASN1OctetString.getInstance(e.nextElement());
+
+ if (e.hasMoreElements())
+ {
+ attributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false);
+ }
+ }
+
+ public AlgorithmIdentifier getPrivateKeyAlgorithm()
+ {
+ return algId;
+ }
+ /**
+ * @deprecated use getPrivateKeyAlgorithm()
+ */
+ public AlgorithmIdentifier getAlgorithmId()
+ {
+ return algId;
+ }
+
+ public ASN1Encodable parsePrivateKey()
+ throws IOException
+ {
+ return ASN1Primitive.fromByteArray(privKey.getOctets());
+ }
+
+ /**
+ * @deprecated use parsePrivateKey()
+ */
+ public ASN1Primitive getPrivateKey()
+ {
+ try
+ {
+ return parsePrivateKey().toASN1Primitive();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("unable to parse private key");
+ }
+ }
+
+ public ASN1Set getAttributes()
+ {
+ return attributes;
+ }
+
+ /**
+ * write out an RSA private key with its associated information
+ * as described in PKCS8.
+ * <pre>
+ * PrivateKeyInfo ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
+ * privateKey PrivateKey,
+ * attributes [0] IMPLICIT Attributes OPTIONAL
+ * }
+ * Version ::= INTEGER {v1(0)} (v1,...)
+ *
+ * PrivateKey ::= OCTET STRING
+ *
+ * Attributes ::= SET OF Attribute
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(0));
+ v.add(algId);
+ v.add(privKey);
+
+ if (attributes != null)
+ {
+ v.add(new DERTaggedObject(false, 0, attributes));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
new file mode 100644
index 0000000..25ff98d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
@@ -0,0 +1,153 @@
+package org.bouncycastle.asn1.pkcs;
+
+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.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class RSAESOAEPparams
+ extends ASN1Object
+{
+ private AlgorithmIdentifier hashAlgorithm;
+ private AlgorithmIdentifier maskGenAlgorithm;
+ private AlgorithmIdentifier pSourceAlgorithm;
+
+ // BEGIN android-changed
+ public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+ // END android-changed
+ public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
+ public final static AlgorithmIdentifier DEFAULT_P_SOURCE_ALGORITHM = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]));
+
+ public static RSAESOAEPparams getInstance(
+ Object obj)
+ {
+ if (obj instanceof RSAESOAEPparams)
+ {
+ return (RSAESOAEPparams)obj;
+ }
+ else if (obj != null)
+ {
+ return new RSAESOAEPparams(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * The default version
+ */
+ public RSAESOAEPparams()
+ {
+ hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+ maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+ pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM;
+ }
+
+ public RSAESOAEPparams(
+ AlgorithmIdentifier hashAlgorithm,
+ AlgorithmIdentifier maskGenAlgorithm,
+ AlgorithmIdentifier pSourceAlgorithm)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ this.maskGenAlgorithm = maskGenAlgorithm;
+ this.pSourceAlgorithm = pSourceAlgorithm;
+ }
+
+ public RSAESOAEPparams(
+ ASN1Sequence seq)
+ {
+ hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+ maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+ pSourceAlgorithm = DEFAULT_P_SOURCE_ALGORITHM;
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(i);
+
+ switch (o.getTagNo())
+ {
+ case 0:
+ hashAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+ break;
+ case 1:
+ maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+ break;
+ case 2:
+ pSourceAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown tag");
+ }
+ }
+ }
+
+ public AlgorithmIdentifier getHashAlgorithm()
+ {
+ return hashAlgorithm;
+ }
+
+ public AlgorithmIdentifier getMaskGenAlgorithm()
+ {
+ return maskGenAlgorithm;
+ }
+
+ public AlgorithmIdentifier getPSourceAlgorithm()
+ {
+ return pSourceAlgorithm;
+ }
+
+ /**
+ * <pre>
+ * RSAES-OAEP-params ::= SEQUENCE {
+ * hashAlgorithm [0] OAEP-PSSDigestAlgorithms DEFAULT sha1,
+ * maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1,
+ * pSourceAlgorithm [2] PKCS1PSourceAlgorithms DEFAULT pSpecifiedEmpty
+ * }
+ *
+ * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-sha1 PARAMETERS NULL }|
+ * { OID id-sha256 PARAMETERS NULL }|
+ * { OID id-sha384 PARAMETERS NULL }|
+ * { OID id-sha512 PARAMETERS NULL },
+ * ... -- Allows for future expansion --
+ * }
+ * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+ * ... -- Allows for future expansion --
+ * }
+ * PKCS1PSourceAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-pSpecified PARAMETERS OCTET STRING },
+ * ... -- Allows for future expansion --
+ * }
+ * </pre>
+ * @return the asn1 primitive representing the parameters.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM))
+ {
+ v.add(new DERTaggedObject(true, 0, hashAlgorithm));
+ }
+
+ if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION))
+ {
+ v.add(new DERTaggedObject(true, 1, maskGenAlgorithm));
+ }
+
+ if (!pSourceAlgorithm.equals(DEFAULT_P_SOURCE_ALGORITHM))
+ {
+ v.add(new DERTaggedObject(true, 2, pSourceAlgorithm));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java
new file mode 100644
index 0000000..36992cf
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java
@@ -0,0 +1,187 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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;
+
+public class RSAPrivateKey
+ extends ASN1Object
+{
+ private BigInteger version;
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+ private BigInteger privateExponent;
+ private BigInteger prime1;
+ private BigInteger prime2;
+ private BigInteger exponent1;
+ private BigInteger exponent2;
+ private BigInteger coefficient;
+ private ASN1Sequence otherPrimeInfos = null;
+
+ public static RSAPrivateKey getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static RSAPrivateKey getInstance(
+ Object obj)
+ {
+ if (obj instanceof RSAPrivateKey)
+ {
+ return (RSAPrivateKey)obj;
+ }
+
+ if (obj != null)
+ {
+ return new RSAPrivateKey(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public RSAPrivateKey(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger prime1,
+ BigInteger prime2,
+ BigInteger exponent1,
+ BigInteger exponent2,
+ BigInteger coefficient)
+ {
+ this.version = BigInteger.valueOf(0);
+ this.modulus = modulus;
+ this.publicExponent = publicExponent;
+ this.privateExponent = privateExponent;
+ this.prime1 = prime1;
+ this.prime2 = prime2;
+ this.exponent1 = exponent1;
+ this.exponent2 = exponent2;
+ this.coefficient = coefficient;
+ }
+
+ private RSAPrivateKey(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ BigInteger v = ((ASN1Integer)e.nextElement()).getValue();
+ if (v.intValue() != 0 && v.intValue() != 1)
+ {
+ throw new IllegalArgumentException("wrong version for RSA private key");
+ }
+
+ version = v;
+ modulus = ((ASN1Integer)e.nextElement()).getValue();
+ publicExponent = ((ASN1Integer)e.nextElement()).getValue();
+ privateExponent = ((ASN1Integer)e.nextElement()).getValue();
+ prime1 = ((ASN1Integer)e.nextElement()).getValue();
+ prime2 = ((ASN1Integer)e.nextElement()).getValue();
+ exponent1 = ((ASN1Integer)e.nextElement()).getValue();
+ exponent2 = ((ASN1Integer)e.nextElement()).getValue();
+ coefficient = ((ASN1Integer)e.nextElement()).getValue();
+
+ if (e.hasMoreElements())
+ {
+ otherPrimeInfos = (ASN1Sequence)e.nextElement();
+ }
+ }
+
+ public BigInteger getVersion()
+ {
+ return version;
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ public BigInteger getPrivateExponent()
+ {
+ return privateExponent;
+ }
+
+ public BigInteger getPrime1()
+ {
+ return prime1;
+ }
+
+ public BigInteger getPrime2()
+ {
+ return prime2;
+ }
+
+ public BigInteger getExponent1()
+ {
+ return exponent1;
+ }
+
+ public BigInteger getExponent2()
+ {
+ return exponent2;
+ }
+
+ public BigInteger getCoefficient()
+ {
+ return coefficient;
+ }
+
+ /**
+ * This outputs the key in PKCS1v2 format.
+ * <pre>
+ * RSAPrivateKey ::= SEQUENCE {
+ * version Version,
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ *
+ * Version ::= INTEGER { two-prime(0), multi(1) }
+ * (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})
+ * </pre>
+ * <p>
+ * This routine is written to output PKCS1 version 2.1, private keys.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(version)); // version
+ v.add(new ASN1Integer(getModulus()));
+ v.add(new ASN1Integer(getPublicExponent()));
+ v.add(new ASN1Integer(getPrivateExponent()));
+ v.add(new ASN1Integer(getPrime1()));
+ v.add(new ASN1Integer(getPrime2()));
+ v.add(new ASN1Integer(getExponent1()));
+ v.add(new ASN1Integer(getExponent2()));
+ v.add(new ASN1Integer(getCoefficient()));
+
+ if (otherPrimeInfos != null)
+ {
+ v.add(otherPrimeInfos);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
new file mode 100644
index 0000000..5912d5e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
@@ -0,0 +1,189 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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;
+
+/**
+ * @deprecated use RSAPrivateKey
+ */
+public class RSAPrivateKeyStructure
+ extends ASN1Object
+{
+ private int version;
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+ private BigInteger privateExponent;
+ private BigInteger prime1;
+ private BigInteger prime2;
+ private BigInteger exponent1;
+ private BigInteger exponent2;
+ private BigInteger coefficient;
+ private ASN1Sequence otherPrimeInfos = null;
+
+ public static RSAPrivateKeyStructure getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static RSAPrivateKeyStructure getInstance(
+ Object obj)
+ {
+ if (obj instanceof RSAPrivateKeyStructure)
+ {
+ return (RSAPrivateKeyStructure)obj;
+ }
+ else if (obj instanceof ASN1Sequence)
+ {
+ return new RSAPrivateKeyStructure((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ public RSAPrivateKeyStructure(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger prime1,
+ BigInteger prime2,
+ BigInteger exponent1,
+ BigInteger exponent2,
+ BigInteger coefficient)
+ {
+ this.version = 0;
+ this.modulus = modulus;
+ this.publicExponent = publicExponent;
+ this.privateExponent = privateExponent;
+ this.prime1 = prime1;
+ this.prime2 = prime2;
+ this.exponent1 = exponent1;
+ this.exponent2 = exponent2;
+ this.coefficient = coefficient;
+ }
+
+ public RSAPrivateKeyStructure(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ BigInteger v = ((ASN1Integer)e.nextElement()).getValue();
+ if (v.intValue() != 0 && v.intValue() != 1)
+ {
+ throw new IllegalArgumentException("wrong version for RSA private key");
+ }
+
+ version = v.intValue();
+ modulus = ((ASN1Integer)e.nextElement()).getValue();
+ publicExponent = ((ASN1Integer)e.nextElement()).getValue();
+ privateExponent = ((ASN1Integer)e.nextElement()).getValue();
+ prime1 = ((ASN1Integer)e.nextElement()).getValue();
+ prime2 = ((ASN1Integer)e.nextElement()).getValue();
+ exponent1 = ((ASN1Integer)e.nextElement()).getValue();
+ exponent2 = ((ASN1Integer)e.nextElement()).getValue();
+ coefficient = ((ASN1Integer)e.nextElement()).getValue();
+
+ if (e.hasMoreElements())
+ {
+ otherPrimeInfos = (ASN1Sequence)e.nextElement();
+ }
+ }
+
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ public BigInteger getPrivateExponent()
+ {
+ return privateExponent;
+ }
+
+ public BigInteger getPrime1()
+ {
+ return prime1;
+ }
+
+ public BigInteger getPrime2()
+ {
+ return prime2;
+ }
+
+ public BigInteger getExponent1()
+ {
+ return exponent1;
+ }
+
+ public BigInteger getExponent2()
+ {
+ return exponent2;
+ }
+
+ public BigInteger getCoefficient()
+ {
+ return coefficient;
+ }
+
+ /**
+ * This outputs the key in PKCS1v2 format.
+ * <pre>
+ * RSAPrivateKey ::= SEQUENCE {
+ * version Version,
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ *
+ * Version ::= INTEGER { two-prime(0), multi(1) }
+ * (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})
+ * </pre>
+ * <p>
+ * This routine is written to output PKCS1 version 2.1, private keys.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(version)); // version
+ v.add(new ASN1Integer(getModulus()));
+ v.add(new ASN1Integer(getPublicExponent()));
+ v.add(new ASN1Integer(getPrivateExponent()));
+ v.add(new ASN1Integer(getPrime1()));
+ v.add(new ASN1Integer(getPrime2()));
+ v.add(new ASN1Integer(getExponent1()));
+ v.add(new ASN1Integer(getExponent2()));
+ v.add(new ASN1Integer(getCoefficient()));
+
+ if (otherPrimeInfos != null)
+ {
+ v.add(otherPrimeInfos);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java
new file mode 100644
index 0000000..6c43298
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSAPublicKey.java
@@ -0,0 +1,95 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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;
+
+public class RSAPublicKey
+ extends ASN1Object
+{
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+
+ public static RSAPublicKey getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static RSAPublicKey getInstance(
+ Object obj)
+ {
+ if (obj instanceof RSAPublicKey)
+ {
+ return (RSAPublicKey)obj;
+ }
+
+ if (obj != null)
+ {
+ return new RSAPublicKey(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public RSAPublicKey(
+ BigInteger modulus,
+ BigInteger publicExponent)
+ {
+ this.modulus = modulus;
+ this.publicExponent = publicExponent;
+ }
+
+ private RSAPublicKey(
+ ASN1Sequence seq)
+ {
+ if (seq.size() != 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ Enumeration e = seq.getObjects();
+
+ modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+ publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ /**
+ * This outputs the key in PKCS1v2 format.
+ * <pre>
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * }
+ * </pre>
+ * <p>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(getModulus()));
+ v.add(new ASN1Integer(getPublicExponent()));
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
new file mode 100644
index 0000000..73cfcdc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
@@ -0,0 +1,174 @@
+package org.bouncycastle.asn1.pkcs;
+
+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.DERNull;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+
+public class RSASSAPSSparams
+ extends ASN1Object
+{
+ private AlgorithmIdentifier hashAlgorithm;
+ private AlgorithmIdentifier maskGenAlgorithm;
+ private ASN1Integer saltLength;
+ private ASN1Integer trailerField;
+
+ // BEGIN android-changed
+ public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+ // END android-changed
+ public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
+ public final static ASN1Integer DEFAULT_SALT_LENGTH = new ASN1Integer(20);
+ public final static ASN1Integer DEFAULT_TRAILER_FIELD = new ASN1Integer(1);
+
+ public static RSASSAPSSparams getInstance(
+ Object obj)
+ {
+ if (obj instanceof RSASSAPSSparams)
+ {
+ return (RSASSAPSSparams)obj;
+ }
+ else if (obj != null)
+ {
+ return new RSASSAPSSparams(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * The default version
+ */
+ public RSASSAPSSparams()
+ {
+ hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+ maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+ saltLength = DEFAULT_SALT_LENGTH;
+ trailerField = DEFAULT_TRAILER_FIELD;
+ }
+
+ public RSASSAPSSparams(
+ AlgorithmIdentifier hashAlgorithm,
+ AlgorithmIdentifier maskGenAlgorithm,
+ ASN1Integer saltLength,
+ ASN1Integer trailerField)
+ {
+ this.hashAlgorithm = hashAlgorithm;
+ this.maskGenAlgorithm = maskGenAlgorithm;
+ this.saltLength = saltLength;
+ this.trailerField = trailerField;
+ }
+
+ private RSASSAPSSparams(
+ ASN1Sequence seq)
+ {
+ hashAlgorithm = DEFAULT_HASH_ALGORITHM;
+ maskGenAlgorithm = DEFAULT_MASK_GEN_FUNCTION;
+ saltLength = DEFAULT_SALT_LENGTH;
+ trailerField = DEFAULT_TRAILER_FIELD;
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(i);
+
+ switch (o.getTagNo())
+ {
+ case 0:
+ hashAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+ break;
+ case 1:
+ maskGenAlgorithm = AlgorithmIdentifier.getInstance(o, true);
+ break;
+ case 2:
+ saltLength = ASN1Integer.getInstance(o, true);
+ break;
+ case 3:
+ trailerField = ASN1Integer.getInstance(o, true);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown tag");
+ }
+ }
+ }
+
+ public AlgorithmIdentifier getHashAlgorithm()
+ {
+ return hashAlgorithm;
+ }
+
+ public AlgorithmIdentifier getMaskGenAlgorithm()
+ {
+ return maskGenAlgorithm;
+ }
+
+ public BigInteger getSaltLength()
+ {
+ return saltLength.getValue();
+ }
+
+ public BigInteger getTrailerField()
+ {
+ return trailerField.getValue();
+ }
+
+ /**
+ * <pre>
+ * RSASSA-PSS-params ::= SEQUENCE {
+ * hashAlgorithm [0] OAEP-PSSDigestAlgorithms DEFAULT sha1,
+ * maskGenAlgorithm [1] PKCS1MGFAlgorithms DEFAULT mgf1SHA1,
+ * saltLength [2] INTEGER DEFAULT 20,
+ * trailerField [3] TrailerField DEFAULT trailerFieldBC
+ * }
+ *
+ * OAEP-PSSDigestAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-sha1 PARAMETERS NULL }|
+ * { OID id-sha256 PARAMETERS NULL }|
+ * { OID id-sha384 PARAMETERS NULL }|
+ * { OID id-sha512 PARAMETERS NULL },
+ * ... -- Allows for future expansion --
+ * }
+ *
+ * PKCS1MGFAlgorithms ALGORITHM-IDENTIFIER ::= {
+ * { OID id-mgf1 PARAMETERS OAEP-PSSDigestAlgorithms },
+ * ... -- Allows for future expansion --
+ * }
+ *
+ * TrailerField ::= INTEGER { trailerFieldBC(1) }
+ * </pre>
+ * @return the asn1 primitive representing the parameters.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM))
+ {
+ v.add(new DERTaggedObject(true, 0, hashAlgorithm));
+ }
+
+ if (!maskGenAlgorithm.equals(DEFAULT_MASK_GEN_FUNCTION))
+ {
+ v.add(new DERTaggedObject(true, 1, maskGenAlgorithm));
+ }
+
+ if (!saltLength.equals(DEFAULT_SALT_LENGTH))
+ {
+ v.add(new DERTaggedObject(true, 2, saltLength));
+ }
+
+ if (!trailerField.equals(DEFAULT_TRAILER_FIELD))
+ {
+ v.add(new DERTaggedObject(true, 3, trailerField));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java
new file mode 100644
index 0000000..00ca0a2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/SafeBag.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.asn1.pkcs;
+
+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.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DLSequence;
+import org.bouncycastle.asn1.DLTaggedObject;
+
+public class SafeBag
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier bagId;
+ private ASN1Encodable bagValue;
+ private ASN1Set bagAttributes;
+
+ public SafeBag(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable obj)
+ {
+ this.bagId = oid;
+ this.bagValue = obj;
+ this.bagAttributes = null;
+ }
+
+ public SafeBag(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable obj,
+ ASN1Set bagAttributes)
+ {
+ this.bagId = oid;
+ this.bagValue = obj;
+ this.bagAttributes = bagAttributes;
+ }
+
+ public static SafeBag getInstance(
+ Object obj)
+ {
+ if (obj instanceof SafeBag)
+ {
+ return (SafeBag)obj;
+ }
+
+ if (obj != null)
+ {
+ return new SafeBag(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private SafeBag(
+ ASN1Sequence seq)
+ {
+ this.bagId = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ this.bagValue = ((ASN1TaggedObject)seq.getObjectAt(1)).getObject();
+ if (seq.size() == 3)
+ {
+ this.bagAttributes = (ASN1Set)seq.getObjectAt(2);
+ }
+ }
+
+ public ASN1ObjectIdentifier getBagId()
+ {
+ return bagId;
+ }
+
+ public ASN1Encodable getBagValue()
+ {
+ return bagValue;
+ }
+
+ public ASN1Set getBagAttributes()
+ {
+ return bagAttributes;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(bagId);
+ v.add(new DLTaggedObject(true, 0, bagValue));
+
+ if (bagAttributes != null)
+ {
+ v.add(bagAttributes);
+ }
+
+ return new DLSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java
new file mode 100644
index 0000000..234eb2e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/pkcs/SignedData.java
@@ -0,0 +1,166 @@
+package org.bouncycastle.asn1.pkcs;
+
+import java.util.Enumeration;
+
+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.ASN1Set;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * a PKCS#7 signed data object.
+ */
+public class SignedData
+ extends ASN1Object
+ implements PKCSObjectIdentifiers
+{
+ private ASN1Integer version;
+ private ASN1Set digestAlgorithms;
+ private ContentInfo contentInfo;
+ private ASN1Set certificates;
+ private ASN1Set crls;
+ private ASN1Set signerInfos;
+
+ public static SignedData getInstance(
+ Object o)
+ {
+ if (o instanceof SignedData)
+ {
+ return (SignedData)o;
+ }
+ else if (o != null)
+ {
+ return new SignedData(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public SignedData(
+ ASN1Integer _version,
+ ASN1Set _digestAlgorithms,
+ ContentInfo _contentInfo,
+ ASN1Set _certificates,
+ ASN1Set _crls,
+ ASN1Set _signerInfos)
+ {
+ version = _version;
+ digestAlgorithms = _digestAlgorithms;
+ contentInfo = _contentInfo;
+ certificates = _certificates;
+ crls = _crls;
+ signerInfos = _signerInfos;
+ }
+
+ public SignedData(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ version = (ASN1Integer)e.nextElement();
+ digestAlgorithms = ((ASN1Set)e.nextElement());
+ contentInfo = ContentInfo.getInstance(e.nextElement());
+
+ while (e.hasMoreElements())
+ {
+ ASN1Primitive o = (ASN1Primitive)e.nextElement();
+
+ //
+ // an interesting feature of SignedData is that there appear to be varying implementations...
+ // for the moment we ignore anything which doesn't fit.
+ //
+ if (o instanceof DERTaggedObject)
+ {
+ DERTaggedObject tagged = (DERTaggedObject)o;
+
+ switch (tagged.getTagNo())
+ {
+ case 0:
+ certificates = ASN1Set.getInstance(tagged, false);
+ break;
+ case 1:
+ crls = ASN1Set.getInstance(tagged, false);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown tag value " + tagged.getTagNo());
+ }
+ }
+ else
+ {
+ signerInfos = (ASN1Set)o;
+ }
+ }
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public ASN1Set getDigestAlgorithms()
+ {
+ return digestAlgorithms;
+ }
+
+ public ContentInfo getContentInfo()
+ {
+ return contentInfo;
+ }
+
+ public ASN1Set getCertificates()
+ {
+ return certificates;
+ }
+
+ public ASN1Set getCRLs()
+ {
+ return crls;
+ }
+
+ public ASN1Set getSignerInfos()
+ {
+ return signerInfos;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * SignedData ::= SEQUENCE {
+ * version Version,
+ * digestAlgorithms DigestAlgorithmIdentifiers,
+ * contentInfo ContentInfo,
+ * certificates
+ * [0] IMPLICIT ExtendedCertificatesAndCertificates
+ * OPTIONAL,
+ * crls
+ * [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ * signerInfos SignerInfos }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(digestAlgorithms);
+ v.add(contentInfo);
+
+ if (certificates != null)
+ {
+ v.add(new DERTaggedObject(false, 0, certificates));
+ }
+
+ if (crls != null)
+ {
+ v.add(new DERTaggedObject(false, 1, crls));
+ }
+
+ v.add(signerInfos);
+
+ return new BERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
new file mode 100644
index 0000000..4bf6b2b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
@@ -0,0 +1,143 @@
+package org.bouncycastle.asn1.sec;
+
+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.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.util.BigIntegers;
+
+/**
+ * the elliptic curve private key object from SEC 1
+ */
+public class ECPrivateKey
+ extends ASN1Object
+{
+ private ASN1Sequence seq;
+
+ private ECPrivateKey(
+ ASN1Sequence seq)
+ {
+ this.seq = seq;
+ }
+
+ public static ECPrivateKey getInstance(
+ Object obj)
+ {
+ if (obj instanceof ECPrivateKey)
+ {
+ return (ECPrivateKey)obj;
+ }
+
+ if (obj != null)
+ {
+ return new ECPrivateKey(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ECPrivateKey(
+ BigInteger key)
+ {
+ byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(1));
+ v.add(new DEROctetString(bytes));
+
+ seq = new DERSequence(v);
+ }
+
+ public ECPrivateKey(
+ BigInteger key,
+ ASN1Object parameters)
+ {
+ this(key, null, parameters);
+ }
+
+ public ECPrivateKey(
+ BigInteger key,
+ DERBitString publicKey,
+ ASN1Object parameters)
+ {
+ byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(1));
+ v.add(new DEROctetString(bytes));
+
+ if (parameters != null)
+ {
+ v.add(new DERTaggedObject(true, 0, parameters));
+ }
+
+ if (publicKey != null)
+ {
+ v.add(new DERTaggedObject(true, 1, publicKey));
+ }
+
+ seq = new DERSequence(v);
+ }
+
+ public BigInteger getKey()
+ {
+ ASN1OctetString octs = (ASN1OctetString)seq.getObjectAt(1);
+
+ return new BigInteger(1, octs.getOctets());
+ }
+
+ public DERBitString getPublicKey()
+ {
+ return (DERBitString)getObjectInTag(1);
+ }
+
+ public ASN1Primitive getParameters()
+ {
+ return getObjectInTag(0);
+ }
+
+ private ASN1Primitive getObjectInTag(int tagNo)
+ {
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ ASN1Encodable obj = (ASN1Encodable)e.nextElement();
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tag = (ASN1TaggedObject)obj;
+ if (tag.getTagNo() == tagNo)
+ {
+ return tag.getObject().toASN1Primitive();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ * privateKey OCTET STRING,
+ * parameters [0] Parameters OPTIONAL,
+ * publicKey [1] BIT STRING OPTIONAL }
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
new file mode 100644
index 0000000..3b1bcc3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
@@ -0,0 +1,128 @@
+package org.bouncycastle.asn1.sec;
+
+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.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.util.BigIntegers;
+
+/**
+ * the elliptic curve private key object from SEC 1
+ * @deprecated use ECPrivateKey
+ */
+public class ECPrivateKeyStructure
+ extends ASN1Object
+{
+ private ASN1Sequence seq;
+
+ public ECPrivateKeyStructure(
+ ASN1Sequence seq)
+ {
+ this.seq = seq;
+ }
+
+ public ECPrivateKeyStructure(
+ BigInteger key)
+ {
+ byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(1));
+ v.add(new DEROctetString(bytes));
+
+ seq = new DERSequence(v);
+ }
+
+ public ECPrivateKeyStructure(
+ BigInteger key,
+ ASN1Encodable parameters)
+ {
+ this(key, null, parameters);
+ }
+
+ public ECPrivateKeyStructure(
+ BigInteger key,
+ DERBitString publicKey,
+ ASN1Encodable parameters)
+ {
+ byte[] bytes = BigIntegers.asUnsignedByteArray(key);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(1));
+ v.add(new DEROctetString(bytes));
+
+ if (parameters != null)
+ {
+ v.add(new DERTaggedObject(true, 0, parameters));
+ }
+
+ if (publicKey != null)
+ {
+ v.add(new DERTaggedObject(true, 1, publicKey));
+ }
+
+ seq = new DERSequence(v);
+ }
+
+ public BigInteger getKey()
+ {
+ ASN1OctetString octs = (ASN1OctetString)seq.getObjectAt(1);
+
+ return new BigInteger(1, octs.getOctets());
+ }
+
+ public DERBitString getPublicKey()
+ {
+ return (DERBitString)getObjectInTag(1);
+ }
+
+ public ASN1Primitive getParameters()
+ {
+ return getObjectInTag(0);
+ }
+
+ private ASN1Primitive getObjectInTag(int tagNo)
+ {
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ ASN1Encodable obj = (ASN1Encodable)e.nextElement();
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tag = (ASN1TaggedObject)obj;
+ if (tag.getTagNo() == tagNo)
+ {
+ return (ASN1Primitive)((ASN1Encodable)tag.getObject()).toASN1Primitive();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ * privateKey OCTET STRING,
+ * parameters [0] Parameters OPTIONAL,
+ * publicKey [1] BIT STRING OPTIONAL }
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
new file mode 100644
index 0000000..44c811b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java
@@ -0,0 +1,1029 @@
+package org.bouncycastle.asn1.sec;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECParametersHolder;
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+public class SECNamedCurves
+{
+ private static BigInteger fromHex(
+ String hex)
+ {
+ return new BigInteger(1, Hex.decode(hex));
+ }
+
+ /*
+ * secp112r1
+ */
+ static X9ECParametersHolder secp112r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = (2^128 - 3) / 76439
+ BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B");
+ BigInteger a = fromHex("DB7C2ABF62E35E668076BEAD2088");
+ BigInteger b = fromHex("659EF8BA043916EEDE8911702B22");
+ byte[] S = Hex.decode("00F50B028E4D696E676875615175290472783FB1");
+ BigInteger n = fromHex("DB7C2ABF62E35E7628DFAC6561C5");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("02"
+ //+ "09487239995A5EE76B55F9C2F098"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "09487239995A5EE76B55F9C2F098"
+ + "A89CE5AF8724C0A23E0E0FF77500"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp112r2
+ */
+ static X9ECParametersHolder secp112r2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = (2^128 - 3) / 76439
+ BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B");
+ BigInteger a = fromHex("6127C24C05F38A0AAAF65C0EF02C");
+ BigInteger b = fromHex("51DEF1815DB5ED74FCC34C85D709");
+ byte[] S = Hex.decode("002757A1114D696E6768756151755316C05E0BD4");
+ BigInteger n = fromHex("36DF0AAFD8B8D7597CA10520D04B");
+ BigInteger h = BigInteger.valueOf(4);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "4BA30AB5E892B4E1649DD0928643"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "4BA30AB5E892B4E1649DD0928643"
+ + "ADCD46F5882E3747DEF36E956E97"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp128r1
+ */
+ static X9ECParametersHolder secp128r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^128 - 2^97 - 1
+ BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+ BigInteger a = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC");
+ BigInteger b = fromHex("E87579C11079F43DD824993C2CEE5ED3");
+ byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679");
+ BigInteger n = fromHex("FFFFFFFE0000000075A30D1B9038A115");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "161FF7528B899B2D0C28607CA52C5B86"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "161FF7528B899B2D0C28607CA52C5B86"
+ + "CF5AC8395BAFEB13C02DA292DDED7A83"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp128r2
+ */
+ static X9ECParametersHolder secp128r2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^128 - 2^97 - 1
+ BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF");
+ BigInteger a = fromHex("D6031998D1B3BBFEBF59CC9BBFF9AEE1");
+ BigInteger b = fromHex("5EEEFCA380D02919DC2C6558BB6D8A5D");
+ byte[] S = Hex.decode("004D696E67687561517512D8F03431FCE63B88F4");
+ BigInteger n = fromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3");
+ BigInteger h = BigInteger.valueOf(4);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("02"
+ //+ "7B6AA5D85E572983E6FB32A7CDEBC140"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "7B6AA5D85E572983E6FB32A7CDEBC140"
+ + "27B6916A894D3AEE7106FE805FC34B44"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp160k1
+ */
+ static X9ECParametersHolder secp160k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+ BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+ BigInteger a = ECConstants.ZERO;
+ BigInteger b = BigInteger.valueOf(7);
+ byte[] S = null;
+ BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+// ECPoint G = curve.decodePoint(Hex.decode("02"
+// + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
+ + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp160r1
+ */
+ static X9ECParametersHolder secp160r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^160 - 2^31 - 1
+ BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF");
+ BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC");
+ BigInteger b = fromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45");
+ byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345");
+ BigInteger n = fromHex("0100000000000000000001F4C8F927AED3CA752257");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("02"
+ //+ "4A96B5688EF573284664698968C38BB913CBFC82"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "4A96B5688EF573284664698968C38BB913CBFC82"
+ + "23A628553168947D59DCC912042351377AC5FB32"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp160r2
+ */
+ static X9ECParametersHolder secp160r2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^160 - 2^32 - 2^14 - 2^12 - 2^9 - 2^8 - 2^7 - 2^3 - 2^2 - 1
+ BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73");
+ BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70");
+ BigInteger b = fromHex("B4E134D3FB59EB8BAB57274904664D5AF50388BA");
+ byte[] S = Hex.decode("B99B99B099B323E02709A4D696E6768756151751");
+ BigInteger n = fromHex("0100000000000000000000351EE786A818F3A1A16B");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("02"
+ //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
+ + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp192k1
+ */
+ static X9ECParametersHolder secp192k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1
+ BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37");
+ BigInteger a = ECConstants.ZERO;
+ BigInteger b = BigInteger.valueOf(3);
+ byte[] S = null;
+ BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
+ + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp192r1
+ */
+ static X9ECParametersHolder secp192r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^192 - 2^64 - 1
+ BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF");
+ BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC");
+ BigInteger b = fromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1");
+ byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
+ BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
+ + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp224k1
+ */
+ static X9ECParametersHolder secp224k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1
+ BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D");
+ BigInteger a = ECConstants.ZERO;
+ BigInteger b = BigInteger.valueOf(5);
+ byte[] S = null;
+ BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
+ + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp224r1
+ */
+ static X9ECParametersHolder secp224r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^224 - 2^96 + 1
+ BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001");
+ BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE");
+ BigInteger b = fromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4");
+ byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
+ BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("02"
+ //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
+ + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp256k1
+ */
+ static X9ECParametersHolder secp256k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1
+ BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F");
+ BigInteger a = ECConstants.ZERO;
+ BigInteger b = BigInteger.valueOf(7);
+ byte[] S = null;
+ BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("02"
+ //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
+ + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp256r1
+ */
+ static X9ECParametersHolder secp256r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^224 (2^32 - 1) + 2^192 + 2^96 - 1
+ BigInteger p = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
+ BigInteger a = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
+ BigInteger b = fromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
+ byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90");
+ BigInteger n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+ + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp384r1
+ */
+ static X9ECParametersHolder secp384r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^384 - 2^128 - 2^96 + 2^32 - 1
+ BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF");
+ BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC");
+ BigInteger b = fromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF");
+ byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
+ BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
+ + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * secp521r1
+ */
+ static X9ECParametersHolder secp521r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ // p = 2^521 - 1
+ BigInteger p = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+ BigInteger a = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC");
+ BigInteger b = fromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00");
+ byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
+ BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409");
+ BigInteger h = BigInteger.valueOf(1);
+
+ ECCurve curve = new ECCurve.Fp(p, a, b);
+ //ECPoint G = curve.decodePoint(Hex.decode("02"
+ //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
+ + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect113r1
+ */
+ static X9ECParametersHolder sect113r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 113;
+ int k = 9;
+
+ BigInteger a = fromHex("003088250CA6E7C7FE649CE85820F7");
+ BigInteger b = fromHex("00E8BEE4D3E2260744188BE0E9C723");
+ byte[] S = Hex.decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
+ BigInteger n = fromHex("0100000000000000D9CCEC8A39E56F");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "009D73616F35F4AB1407D73562C10F"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "009D73616F35F4AB1407D73562C10F"
+ + "00A52830277958EE84D1315ED31886"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect113r2
+ */
+ static X9ECParametersHolder sect113r2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 113;
+ int k = 9;
+
+ BigInteger a = fromHex("00689918DBEC7E5A0DD6DFC0AA55C7");
+ BigInteger b = fromHex("0095E9A9EC9B297BD4BF36E059184F");
+ byte[] S = Hex.decode("10C0FB15760860DEF1EEF4D696E676875615175D");
+ BigInteger n = fromHex("010000000000000108789B2496AF93");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "01A57A6A7B26CA5EF52FCDB8164797"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "01A57A6A7B26CA5EF52FCDB8164797"
+ + "00B3ADC94ED1FE674C06E695BABA1D"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect131r1
+ */
+ static X9ECParametersHolder sect131r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 131;
+ int k1 = 2;
+ int k2 = 3;
+ int k3 = 8;
+
+ BigInteger a = fromHex("07A11B09A76B562144418FF3FF8C2570B8");
+ BigInteger b = fromHex("0217C05610884B63B9C6C7291678F9D341");
+ byte[] S = Hex.decode("4D696E676875615175985BD3ADBADA21B43A97E2");
+ BigInteger n = fromHex("0400000000000000023123953A9464B54D");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = 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"
+ + "0081BAF91FDF9833C40F9C181343638399"
+ + "078C6E7EA38C001F73C8134B1B4EF9E150"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect131r2
+ */
+ static X9ECParametersHolder sect131r2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 131;
+ int k1 = 2;
+ int k2 = 3;
+ int k3 = 8;
+
+ BigInteger a = fromHex("03E5A88919D7CAFCBF415F07C2176573B2");
+ BigInteger b = fromHex("04B8266A46C55657AC734CE38F018F2192");
+ byte[] S = Hex.decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
+ BigInteger n = fromHex("0400000000000000016954A233049BA98F");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = 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"
+ + "0356DCD8F2F95031AD652D23951BB366A8"
+ + "0648F06D867940A5366D9E265DE9EB240F"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect163k1
+ */
+ static X9ECParametersHolder sect163k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 163;
+ int k1 = 3;
+ int k2 = 6;
+ int k3 = 7;
+
+ BigInteger a = BigInteger.valueOf(1);
+ BigInteger b = BigInteger.valueOf(1);
+ byte[] S = null;
+ BigInteger n = fromHex("04000000000000000000020108A2E0CC0D99F8A5EF");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = 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"
+ + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
+ + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect163r1
+ */
+ static X9ECParametersHolder sect163r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 163;
+ int k1 = 3;
+ int k2 = 6;
+ int k3 = 7;
+
+ BigInteger a = fromHex("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2");
+ BigInteger b = fromHex("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9");
+ byte[] S = Hex.decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
+ BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = 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"
+ + "0369979697AB43897789566789567F787A7876A654"
+ + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect163r2
+ */
+ static X9ECParametersHolder sect163r2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 163;
+ int k1 = 3;
+ int k2 = 6;
+ int k3 = 7;
+
+ BigInteger a = BigInteger.valueOf(1);
+ BigInteger b = fromHex("020A601907B8C953CA1481EB10512F78744A3205FD");
+ byte[] S = Hex.decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
+ BigInteger n = fromHex("040000000000000000000292FE77E70C12A4234C33");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = 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"
+ + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
+ + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect193r1
+ */
+ static X9ECParametersHolder sect193r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 193;
+ int k = 15;
+
+ BigInteger a = fromHex("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01");
+ BigInteger b = fromHex("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814");
+ byte[] S = Hex.decode("103FAEC74D696E676875615175777FC5B191EF30");
+ BigInteger n = fromHex("01000000000000000000000000C7F34A778F443ACC920EBA49");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
+ + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect193r2
+ */
+ static X9ECParametersHolder sect193r2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 193;
+ int k = 15;
+
+ BigInteger a = fromHex("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B");
+ BigInteger b = fromHex("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE");
+ byte[] S = Hex.decode("10B7B4D696E676875615175137C8A16FD0DA2211");
+ BigInteger n = fromHex("010000000000000000000000015AAB561B005413CCD4EE99D5");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
+ + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect233k1
+ */
+ static X9ECParametersHolder sect233k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 233;
+ int k = 74;
+
+ BigInteger a = ECConstants.ZERO;
+ BigInteger b = BigInteger.valueOf(1);
+ byte[] S = null;
+ BigInteger n = fromHex("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF");
+ BigInteger h = BigInteger.valueOf(4);
+
+ ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+ //ECPoint G = curve.decodePoint(Hex.decode("02"
+ //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
+ + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect233r1
+ */
+ static X9ECParametersHolder sect233r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 233;
+ int k = 74;
+
+ BigInteger a = BigInteger.valueOf(1);
+ BigInteger b = fromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD");
+ byte[] S = Hex.decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
+ BigInteger n = fromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
+ + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect239k1
+ */
+ static X9ECParametersHolder sect239k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 239;
+ int k = 158;
+
+ BigInteger a = ECConstants.ZERO;
+ BigInteger b = BigInteger.valueOf(1);
+ byte[] S = null;
+ BigInteger n = fromHex("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5");
+ BigInteger h = BigInteger.valueOf(4);
+
+ ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
+ + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect283k1
+ */
+ static X9ECParametersHolder sect283k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 283;
+ int k1 = 5;
+ int k2 = 7;
+ int k3 = 12;
+
+ BigInteger a = ECConstants.ZERO;
+ BigInteger b = BigInteger.valueOf(1);
+ byte[] S = null;
+ BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61");
+ BigInteger h = BigInteger.valueOf(4);
+
+ ECCurve curve = 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"
+ + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
+ + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect283r1
+ */
+ static X9ECParametersHolder sect283r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 283;
+ int k1 = 5;
+ int k2 = 7;
+ int k3 = 12;
+
+ BigInteger a = BigInteger.valueOf(1);
+ BigInteger b = fromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5");
+ byte[] S = Hex.decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
+ BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = 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"
+ + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
+ + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect409k1
+ */
+ static X9ECParametersHolder sect409k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 409;
+ int k = 87;
+
+ BigInteger a = ECConstants.ZERO;
+ BigInteger b = BigInteger.valueOf(1);
+ byte[] S = null;
+ BigInteger n = fromHex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF");
+ BigInteger h = BigInteger.valueOf(4);
+
+ ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
+ + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect409r1
+ */
+ static X9ECParametersHolder sect409r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 409;
+ int k = 87;
+
+ BigInteger a = BigInteger.valueOf(1);
+ BigInteger b = fromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F");
+ byte[] S = Hex.decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
+ BigInteger n = fromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = new ECCurve.F2m(m, k, a, b, n, h);
+ //ECPoint G = curve.decodePoint(Hex.decode("03"
+ //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"));
+ ECPoint G = curve.decodePoint(Hex.decode("04"
+ + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
+ + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect571k1
+ */
+ static X9ECParametersHolder sect571k1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 571;
+ int k1 = 2;
+ int k2 = 5;
+ int k3 = 10;
+
+ BigInteger a = ECConstants.ZERO;
+ BigInteger b = BigInteger.valueOf(1);
+ byte[] S = null;
+ BigInteger n = fromHex("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001");
+ BigInteger h = BigInteger.valueOf(4);
+
+ ECCurve curve = 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"
+ + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
+ + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+ /*
+ * sect571r1
+ */
+ static X9ECParametersHolder sect571r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ int m = 571;
+ int k1 = 2;
+ int k2 = 5;
+ int k3 = 10;
+
+ BigInteger a = BigInteger.valueOf(1);
+ BigInteger b = fromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A");
+ byte[] S = Hex.decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
+ BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47");
+ BigInteger h = BigInteger.valueOf(2);
+
+ ECCurve curve = 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"
+ + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
+ + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
+
+ return new X9ECParameters(curve, G, n, h, S);
+ }
+ };
+
+
+ static final Hashtable objIds = new Hashtable();
+ static final Hashtable curves = new Hashtable();
+ static final Hashtable names = new Hashtable();
+
+ static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
+ {
+ objIds.put(name, oid);
+ names.put(oid, name);
+ curves.put(oid, holder);
+ }
+
+ static
+ {
+ defineCurve("secp112r1", SECObjectIdentifiers.secp112r1, secp112r1);
+ defineCurve("secp112r2", SECObjectIdentifiers.secp112r2, secp112r2);
+ defineCurve("secp128r1", SECObjectIdentifiers.secp128r1, secp128r1);
+ defineCurve("secp128r2", SECObjectIdentifiers.secp128r2, secp128r2);
+ defineCurve("secp160k1", SECObjectIdentifiers.secp160k1, secp160k1);
+ defineCurve("secp160r1", SECObjectIdentifiers.secp160r1, secp160r1);
+ defineCurve("secp160r2", SECObjectIdentifiers.secp160r2, secp160r2);
+ defineCurve("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1);
+ defineCurve("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1);
+ defineCurve("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1);
+ defineCurve("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1);
+ defineCurve("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1);
+ defineCurve("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1);
+ defineCurve("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1);
+ defineCurve("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1);
+
+ defineCurve("sect113r1", SECObjectIdentifiers.sect113r1, sect113r1);
+ defineCurve("sect113r2", SECObjectIdentifiers.sect113r2, sect113r2);
+ defineCurve("sect131r1", SECObjectIdentifiers.sect131r1, sect131r1);
+ defineCurve("sect131r2", SECObjectIdentifiers.sect131r2, sect131r2);
+ defineCurve("sect163k1", SECObjectIdentifiers.sect163k1, sect163k1);
+ defineCurve("sect163r1", SECObjectIdentifiers.sect163r1, sect163r1);
+ defineCurve("sect163r2", SECObjectIdentifiers.sect163r2, sect163r2);
+ defineCurve("sect193r1", SECObjectIdentifiers.sect193r1, sect193r1);
+ defineCurve("sect193r2", SECObjectIdentifiers.sect193r2, sect193r2);
+ defineCurve("sect233k1", SECObjectIdentifiers.sect233k1, sect233k1);
+ defineCurve("sect233r1", SECObjectIdentifiers.sect233r1, sect233r1);
+ defineCurve("sect239k1", SECObjectIdentifiers.sect239k1, sect239k1);
+ defineCurve("sect283k1", SECObjectIdentifiers.sect283k1, sect283k1);
+ defineCurve("sect283r1", SECObjectIdentifiers.sect283r1, sect283r1);
+ defineCurve("sect409k1", SECObjectIdentifiers.sect409k1, sect409k1);
+ defineCurve("sect409r1", SECObjectIdentifiers.sect409r1, sect409r1);
+ defineCurve("sect571k1", SECObjectIdentifiers.sect571k1, sect571k1);
+ defineCurve("sect571r1", SECObjectIdentifiers.sect571r1, sect571r1);
+ }
+
+ public static X9ECParameters getByName(
+ String name)
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+
+ if (oid != null)
+ {
+ return getByOID(oid);
+ }
+
+ return null;
+ }
+
+ /**
+ * 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)curves.get(oid);
+
+ if (holder != null)
+ {
+ return holder.getParameters();
+ }
+
+ return null;
+ }
+
+ /**
+ * 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)objIds.get(Strings.toLowerCase(name));
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static String getName(
+ ASN1ObjectIdentifier oid)
+ {
+ return (String)names.get(oid);
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static Enumeration getNames()
+ {
+ return objIds.keys();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
new file mode 100644
index 0000000..8b19cd6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.asn1.sec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+
+public interface SECObjectIdentifiers
+{
+ /**
+ * ellipticCurve OBJECT IDENTIFIER ::= {
+ * iso(1) identified-organization(3) certicom(132) curve(0)
+ * }
+ */
+ static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.132.0");
+
+ static final ASN1ObjectIdentifier sect163k1 = ellipticCurve.branch("1");
+ static final ASN1ObjectIdentifier sect163r1 = ellipticCurve.branch("2");
+ static final ASN1ObjectIdentifier sect239k1 = ellipticCurve.branch("3");
+ static final ASN1ObjectIdentifier sect113r1 = ellipticCurve.branch("4");
+ static final ASN1ObjectIdentifier sect113r2 = ellipticCurve.branch("5");
+ static final ASN1ObjectIdentifier secp112r1 = ellipticCurve.branch("6");
+ static final ASN1ObjectIdentifier secp112r2 = ellipticCurve.branch("7");
+ static final ASN1ObjectIdentifier secp160r1 = ellipticCurve.branch("8");
+ static final ASN1ObjectIdentifier secp160k1 = ellipticCurve.branch("9");
+ static final ASN1ObjectIdentifier secp256k1 = ellipticCurve.branch("10");
+ static final ASN1ObjectIdentifier sect163r2 = ellipticCurve.branch("15");
+ static final ASN1ObjectIdentifier sect283k1 = ellipticCurve.branch("16");
+ static final ASN1ObjectIdentifier sect283r1 = ellipticCurve.branch("17");
+ static final ASN1ObjectIdentifier sect131r1 = ellipticCurve.branch("22");
+ static final ASN1ObjectIdentifier sect131r2 = ellipticCurve.branch("23");
+ static final ASN1ObjectIdentifier sect193r1 = ellipticCurve.branch("24");
+ static final ASN1ObjectIdentifier sect193r2 = ellipticCurve.branch("25");
+ static final ASN1ObjectIdentifier sect233k1 = ellipticCurve.branch("26");
+ static final ASN1ObjectIdentifier sect233r1 = ellipticCurve.branch("27");
+ static final ASN1ObjectIdentifier secp128r1 = ellipticCurve.branch("28");
+ static final ASN1ObjectIdentifier secp128r2 = ellipticCurve.branch("29");
+ static final ASN1ObjectIdentifier secp160r2 = ellipticCurve.branch("30");
+ static final ASN1ObjectIdentifier secp192k1 = ellipticCurve.branch("31");
+ static final ASN1ObjectIdentifier secp224k1 = ellipticCurve.branch("32");
+ static final ASN1ObjectIdentifier secp224r1 = ellipticCurve.branch("33");
+ static final ASN1ObjectIdentifier secp384r1 = ellipticCurve.branch("34");
+ static final ASN1ObjectIdentifier secp521r1 = ellipticCurve.branch("35");
+ static final ASN1ObjectIdentifier sect409k1 = ellipticCurve.branch("36");
+ static final ASN1ObjectIdentifier sect409r1 = ellipticCurve.branch("37");
+ static final ASN1ObjectIdentifier sect571k1 = ellipticCurve.branch("38");
+ static final ASN1ObjectIdentifier sect571r1 = ellipticCurve.branch("39");
+
+ static final ASN1ObjectIdentifier secp192r1 = X9ObjectIdentifiers.prime192v1;
+ static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1;
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
new file mode 100644
index 0000000..df9a0ff
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/teletrust/TeleTrusTObjectIdentifiers.java
@@ -0,0 +1,42 @@
+package org.bouncycastle.asn1.teletrust;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface TeleTrusTObjectIdentifiers
+{
+ static final ASN1ObjectIdentifier teleTrusTAlgorithm = new ASN1ObjectIdentifier("1.3.36.3");
+
+ static final ASN1ObjectIdentifier ripemd160 = teleTrusTAlgorithm.branch("2.1");
+ static final ASN1ObjectIdentifier ripemd128 = teleTrusTAlgorithm.branch("2.2");
+ static final ASN1ObjectIdentifier ripemd256 = teleTrusTAlgorithm.branch("2.3");
+
+ static final ASN1ObjectIdentifier teleTrusTRSAsignatureAlgorithm = teleTrusTAlgorithm.branch("3.1");
+
+ static final ASN1ObjectIdentifier rsaSignatureWithripemd160 = teleTrusTRSAsignatureAlgorithm.branch("2");
+ static final ASN1ObjectIdentifier rsaSignatureWithripemd128 = teleTrusTRSAsignatureAlgorithm.branch("3");
+ static final ASN1ObjectIdentifier rsaSignatureWithripemd256 = teleTrusTRSAsignatureAlgorithm.branch("4");
+
+ static final ASN1ObjectIdentifier ecSign = teleTrusTAlgorithm.branch("3.2");
+
+ static final ASN1ObjectIdentifier ecSignWithSha1 = ecSign.branch("1");
+ static final ASN1ObjectIdentifier ecSignWithRipemd160 = ecSign.branch("2");
+
+ static final ASN1ObjectIdentifier ecc_brainpool = teleTrusTAlgorithm.branch("3.2.8");
+ static final ASN1ObjectIdentifier ellipticCurve = ecc_brainpool.branch("1");
+ static final ASN1ObjectIdentifier versionOne = ellipticCurve.branch("1");
+
+ static final ASN1ObjectIdentifier brainpoolP160r1 = versionOne.branch("1");
+ static final ASN1ObjectIdentifier brainpoolP160t1 = versionOne.branch("2");
+ static final ASN1ObjectIdentifier brainpoolP192r1 = versionOne.branch("3");
+ static final ASN1ObjectIdentifier brainpoolP192t1 = versionOne.branch("4");
+ static final ASN1ObjectIdentifier brainpoolP224r1 = versionOne.branch("5");
+ static final ASN1ObjectIdentifier brainpoolP224t1 = versionOne.branch("6");
+ static final ASN1ObjectIdentifier brainpoolP256r1 = versionOne.branch("7");
+ static final ASN1ObjectIdentifier brainpoolP256t1 = versionOne.branch("8");
+ static final ASN1ObjectIdentifier brainpoolP320r1 = versionOne.branch("9");
+ static final ASN1ObjectIdentifier brainpoolP320t1 = versionOne.branch("10");
+ static final ASN1ObjectIdentifier brainpoolP384r1 = versionOne.branch("11");
+ static final ASN1ObjectIdentifier brainpoolP384t1 = versionOne.branch("12");
+ static final ASN1ObjectIdentifier brainpoolP512r1 = versionOne.branch("13");
+ static final ASN1ObjectIdentifier brainpoolP512t1 = versionOne.branch("14");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
new file mode 100644
index 0000000..976f556
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
@@ -0,0 +1,429 @@
+package org.bouncycastle.asn1.util;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+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.ASN1Set;
+import org.bouncycastle.asn1.BERApplicationSpecific;
+import org.bouncycastle.asn1.BERConstructedOctetString;
+import org.bouncycastle.asn1.BERSequence;
+import org.bouncycastle.asn1.BERSet;
+import org.bouncycastle.asn1.BERTaggedObject;
+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.DERIA5String;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERPrintableString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.DERT61String;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DERUTCTime;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.DERVisibleString;
+import org.bouncycastle.util.encoders.Hex;
+
+public class ASN1Dump
+{
+ private static final String TAB = " ";
+ private static final int SAMPLE_SIZE = 32;
+
+ /**
+ * dump a DER object as a formatted string with indentation
+ *
+ * @param obj the ASN1Primitive to be dumped out.
+ */
+ static void _dumpAsString(
+ String indent,
+ boolean verbose,
+ ASN1Primitive obj,
+ StringBuffer buf)
+ {
+ String nl = System.getProperty("line.separator");
+ if (obj instanceof ASN1Sequence)
+ {
+ Enumeration e = ((ASN1Sequence)obj).getObjects();
+ String tab = indent + TAB;
+
+ buf.append(indent);
+ if (obj instanceof BERSequence)
+ {
+ buf.append("BER Sequence");
+ }
+ else if (obj instanceof DERSequence)
+ {
+ buf.append("DER Sequence");
+ }
+ else
+ {
+ buf.append("Sequence");
+ }
+
+ buf.append(nl);
+
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+
+ // BEGIN android-changed
+ if (o == null || o.equals(DERNull.INSTANCE))
+ // END android-changed
+ {
+ buf.append(tab);
+ buf.append("NULL");
+ buf.append(nl);
+ }
+ else if (o instanceof ASN1Primitive)
+ {
+ _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
+ }
+ else
+ {
+ _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
+ }
+ }
+ }
+ else if (obj instanceof DERTaggedObject)
+ {
+ String tab = indent + TAB;
+
+ buf.append(indent);
+ if (obj instanceof BERTaggedObject)
+ {
+ buf.append("BER Tagged [");
+ }
+ else
+ {
+ buf.append("Tagged [");
+ }
+
+ DERTaggedObject o = (DERTaggedObject)obj;
+
+ buf.append(Integer.toString(o.getTagNo()));
+ buf.append(']');
+
+ if (!o.isExplicit())
+ {
+ buf.append(" IMPLICIT ");
+ }
+
+ buf.append(nl);
+
+ if (o.isEmpty())
+ {
+ buf.append(tab);
+ buf.append("EMPTY");
+ buf.append(nl);
+ }
+ else
+ {
+ _dumpAsString(tab, verbose, o.getObject(), buf);
+ }
+ }
+ else if (obj instanceof BERSet)
+ {
+ Enumeration e = ((ASN1Set)obj).getObjects();
+ String tab = indent + TAB;
+
+ buf.append(indent);
+ buf.append("BER Set");
+ buf.append(nl);
+
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+
+ if (o == null)
+ {
+ buf.append(tab);
+ buf.append("NULL");
+ buf.append(nl);
+ }
+ else if (o instanceof ASN1Primitive)
+ {
+ _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
+ }
+ else
+ {
+ _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
+ }
+ }
+ }
+ else if (obj instanceof DERSet)
+ {
+ Enumeration e = ((ASN1Set)obj).getObjects();
+ String tab = indent + TAB;
+
+ buf.append(indent);
+ buf.append("DER Set");
+ buf.append(nl);
+
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+
+ if (o == null)
+ {
+ buf.append(tab);
+ buf.append("NULL");
+ buf.append(nl);
+ }
+ else if (o instanceof ASN1Primitive)
+ {
+ _dumpAsString(tab, verbose, (ASN1Primitive)o, buf);
+ }
+ else
+ {
+ _dumpAsString(tab, verbose, ((ASN1Encodable)o).toASN1Primitive(), buf);
+ }
+ }
+ }
+ else if (obj instanceof ASN1ObjectIdentifier)
+ {
+ buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl);
+ }
+ else if (obj instanceof DERBoolean)
+ {
+ buf.append(indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl);
+ }
+ else if (obj instanceof ASN1Integer)
+ {
+ buf.append(indent + "Integer(" + ((ASN1Integer)obj).getValue() + ")" + nl);
+ }
+ else if (obj instanceof BERConstructedOctetString)
+ {
+ ASN1OctetString oct = (ASN1OctetString)obj;
+ buf.append(indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] ");
+ if (verbose)
+ {
+ buf.append(dumpBinaryDataAsString(indent, oct.getOctets()));
+ }
+ else{
+ buf.append(nl);
+ }
+ }
+ else if (obj instanceof DEROctetString)
+ {
+ ASN1OctetString oct = (ASN1OctetString)obj;
+ buf.append(indent + "DER Octet String" + "[" + oct.getOctets().length + "] ");
+ if (verbose)
+ {
+ buf.append(dumpBinaryDataAsString(indent, oct.getOctets()));
+ }
+ else{
+ buf.append(nl);
+ }
+ }
+ else if (obj instanceof DERBitString)
+ {
+ DERBitString bt = (DERBitString)obj;
+ buf.append(indent + "DER Bit String" + "[" + bt.getBytes().length + ", " + bt.getPadBits() + "] ");
+ if (verbose)
+ {
+ buf.append(dumpBinaryDataAsString(indent, bt.getBytes()));
+ }
+ else{
+ buf.append(nl);
+ }
+ }
+ else if (obj instanceof DERIA5String)
+ {
+ buf.append(indent + "IA5String(" + ((DERIA5String)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERUTF8String)
+ {
+ buf.append(indent + "UTF8String(" + ((DERUTF8String)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERPrintableString)
+ {
+ buf.append(indent + "PrintableString(" + ((DERPrintableString)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERVisibleString)
+ {
+ buf.append(indent + "VisibleString(" + ((DERVisibleString)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERBMPString)
+ {
+ buf.append(indent + "BMPString(" + ((DERBMPString)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERT61String)
+ {
+ buf.append(indent + "T61String(" + ((DERT61String)obj).getString() + ") " + nl);
+ }
+ else if (obj instanceof DERUTCTime)
+ {
+ buf.append(indent + "UTCTime(" + ((DERUTCTime)obj).getTime() + ") " + nl);
+ }
+ else if (obj instanceof DERGeneralizedTime)
+ {
+ buf.append(indent + "GeneralizedTime(" + ((DERGeneralizedTime)obj).getTime() + ") " + nl);
+ }
+ else if (obj instanceof BERApplicationSpecific)
+ {
+ buf.append(outputApplicationSpecific("BER", indent, verbose, obj, nl));
+ }
+ else if (obj instanceof DERApplicationSpecific)
+ {
+ buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl));
+ }
+ else if (obj instanceof DEREnumerated)
+ {
+ DEREnumerated en = (DEREnumerated) obj;
+ buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl);
+ }
+ else if (obj instanceof DERExternal)
+ {
+ DERExternal ext = (DERExternal) obj;
+ buf.append(indent + "External " + nl);
+ String tab = indent + TAB;
+ if (ext.getDirectReference() != null)
+ {
+ buf.append(tab + "Direct Reference: " + ext.getDirectReference().getId() + nl);
+ }
+ if (ext.getIndirectReference() != null)
+ {
+ buf.append(tab + "Indirect Reference: " + ext.getIndirectReference().toString() + nl);
+ }
+ if (ext.getDataValueDescriptor() != null)
+ {
+ _dumpAsString(tab, verbose, ext.getDataValueDescriptor(), buf);
+ }
+ buf.append(tab + "Encoding: " + ext.getEncoding() + nl);
+ _dumpAsString(tab, verbose, ext.getExternalContent(), buf);
+ }
+ else
+ {
+ buf.append(indent + obj.toString() + nl);
+ }
+ }
+
+ private static String outputApplicationSpecific(String type, String indent, boolean verbose, ASN1Primitive obj, String nl)
+ {
+ DERApplicationSpecific app = (DERApplicationSpecific)obj;
+ StringBuffer buf = new StringBuffer();
+
+ if (app.isConstructed())
+ {
+ try
+ {
+ ASN1Sequence s = ASN1Sequence.getInstance(app.getObject(BERTags.SEQUENCE));
+ buf.append(indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "]" + nl);
+ for (Enumeration e = s.getObjects(); e.hasMoreElements();)
+ {
+ _dumpAsString(indent + TAB, verbose, (ASN1Primitive)e.nextElement(), buf);
+ }
+ }
+ catch (IOException e)
+ {
+ buf.append(e);
+ }
+ return buf.toString();
+ }
+
+ return indent + type + " ApplicationSpecific[" + app.getApplicationTag() + "] (" + new String(Hex.encode(app.getContents())) + ")" + nl;
+ }
+
+ /**
+ * dump out a DER object as a formatted string, in non-verbose mode.
+ *
+ * @param obj the ASN1Primitive to be dumped out.
+ * @return the resulting string.
+ */
+ public static String dumpAsString(
+ Object obj)
+ {
+ return dumpAsString(obj, false);
+ }
+
+ /**
+ * Dump out the object as a string.
+ *
+ * @param obj the object to be dumped
+ * @param verbose if true, dump out the contents of octet and bit strings.
+ * @return the resulting string.
+ */
+ public static String dumpAsString(
+ Object obj,
+ boolean verbose)
+ {
+ StringBuffer buf = new StringBuffer();
+
+ if (obj instanceof ASN1Primitive)
+ {
+ _dumpAsString("", verbose, (ASN1Primitive)obj, buf);
+ }
+ else if (obj instanceof ASN1Encodable)
+ {
+ _dumpAsString("", verbose, ((ASN1Encodable)obj).toASN1Primitive(), buf);
+ }
+ else
+ {
+ return "unknown object type " + obj.toString();
+ }
+
+ return buf.toString();
+ }
+
+ private static String dumpBinaryDataAsString(String indent, byte[] bytes)
+ {
+ String nl = System.getProperty("line.separator");
+ StringBuffer buf = new StringBuffer();
+
+ indent += TAB;
+
+ buf.append(nl);
+ for (int i = 0; i < bytes.length; i += SAMPLE_SIZE)
+ {
+ if (bytes.length - i > SAMPLE_SIZE)
+ {
+ buf.append(indent);
+ buf.append(new String(Hex.encode(bytes, i, SAMPLE_SIZE)));
+ buf.append(TAB);
+ buf.append(calculateAscString(bytes, i, SAMPLE_SIZE));
+ buf.append(nl);
+ }
+ else
+ {
+ buf.append(indent);
+ buf.append(new String(Hex.encode(bytes, i, bytes.length - i)));
+ for (int j = bytes.length - i; j != SAMPLE_SIZE; j++)
+ {
+ buf.append(" ");
+ }
+ buf.append(TAB);
+ buf.append(calculateAscString(bytes, i, bytes.length - i));
+ buf.append(nl);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ private static String calculateAscString(byte[] bytes, int off, int len)
+ {
+ StringBuffer buf = new StringBuffer();
+
+ for (int i = off; i != off + len; i++)
+ {
+ if (bytes[i] >= ' ' && bytes[i] <= '~')
+ {
+ buf.append((char)bytes[i]);
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java
new file mode 100644
index 0000000..7f283f9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.asn1.x500;
+
+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.DERSequence;
+
+public class AttributeTypeAndValue
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier type;
+ private ASN1Encodable value;
+
+ private AttributeTypeAndValue(ASN1Sequence seq)
+ {
+ type = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ value = (ASN1Encodable)seq.getObjectAt(1);
+ }
+
+ public static AttributeTypeAndValue getInstance(Object o)
+ {
+ if (o instanceof AttributeTypeAndValue)
+ {
+ return (AttributeTypeAndValue)o;
+ }
+ else if (o != null)
+ {
+ return new AttributeTypeAndValue(ASN1Sequence.getInstance(o));
+ }
+
+ throw new IllegalArgumentException("null value in getInstance()");
+ }
+
+ public AttributeTypeAndValue(
+ ASN1ObjectIdentifier type,
+ ASN1Encodable value)
+ {
+ this.type = type;
+ this.value = value;
+ }
+
+ public ASN1ObjectIdentifier getType()
+ {
+ return type;
+ }
+
+ public ASN1Encodable getValue()
+ {
+ return value;
+ }
+
+ /**
+ * <pre>
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * value ANY DEFINED BY type }
+ * </pre>
+ * @return a basic ASN.1 object representation.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(type);
+ v.add(value);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java
new file mode 100644
index 0000000..cf7563e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/DirectoryString.java
@@ -0,0 +1,125 @@
+package org.bouncycastle.asn1.x500;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1String;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBMPString;
+import org.bouncycastle.asn1.DERPrintableString;
+import org.bouncycastle.asn1.DERT61String;
+import org.bouncycastle.asn1.DERUTF8String;
+import org.bouncycastle.asn1.DERUniversalString;
+
+public class DirectoryString
+ extends ASN1Object
+ implements ASN1Choice, ASN1String
+{
+ private ASN1String string;
+
+ public static DirectoryString getInstance(Object o)
+ {
+ if (o == null || o instanceof DirectoryString)
+ {
+ return (DirectoryString)o;
+ }
+
+ if (o instanceof DERT61String)
+ {
+ return new DirectoryString((DERT61String)o);
+ }
+
+ if (o instanceof DERPrintableString)
+ {
+ return new DirectoryString((DERPrintableString)o);
+ }
+
+ if (o instanceof DERUniversalString)
+ {
+ return new DirectoryString((DERUniversalString)o);
+ }
+
+ if (o instanceof DERUTF8String)
+ {
+ return new DirectoryString((DERUTF8String)o);
+ }
+
+ if (o instanceof DERBMPString)
+ {
+ return new DirectoryString((DERBMPString)o);
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + o.getClass().getName());
+ }
+
+ public static DirectoryString getInstance(ASN1TaggedObject o, boolean explicit)
+ {
+ if (!explicit)
+ {
+ throw new IllegalArgumentException("choice item must be explicitly tagged");
+ }
+
+ return getInstance(o.getObject());
+ }
+
+ private DirectoryString(
+ DERT61String string)
+ {
+ this.string = string;
+ }
+
+ private DirectoryString(
+ DERPrintableString string)
+ {
+ this.string = string;
+ }
+
+ private DirectoryString(
+ DERUniversalString string)
+ {
+ this.string = string;
+ }
+
+ private DirectoryString(
+ DERUTF8String string)
+ {
+ this.string = string;
+ }
+
+ private DirectoryString(
+ DERBMPString string)
+ {
+ this.string = string;
+ }
+
+ public DirectoryString(String string)
+ {
+ this.string = new DERUTF8String(string);
+ }
+
+ public String getString()
+ {
+ return string.getString();
+ }
+
+ public String toString()
+ {
+ return string.getString();
+ }
+
+ /**
+ * <pre>
+ * DirectoryString ::= CHOICE {
+ * teletexString TeletexString (SIZE (1..MAX)),
+ * printableString PrintableString (SIZE (1..MAX)),
+ * universalString UniversalString (SIZE (1..MAX)),
+ * utf8String UTF8String (SIZE (1..MAX)),
+ * bmpString BMPString (SIZE (1..MAX)) }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return ((ASN1Encodable)string).toASN1Primitive();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java
new file mode 100644
index 0000000..f51c261
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/RDN.java
@@ -0,0 +1,119 @@
+package org.bouncycastle.asn1.x500;
+
+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.ASN1Set;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSet;
+
+public class RDN
+ extends ASN1Object
+{
+ private ASN1Set values;
+
+ private RDN(ASN1Set values)
+ {
+ this.values = values;
+ }
+
+ public static RDN getInstance(Object obj)
+ {
+ if (obj instanceof RDN)
+ {
+ return (RDN)obj;
+ }
+ else if (obj != null)
+ {
+ return new RDN(ASN1Set.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a single valued RDN.
+ *
+ * @param oid RDN type.
+ * @param value RDN value.
+ */
+ public RDN(ASN1ObjectIdentifier oid, ASN1Encodable value)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(oid);
+ v.add(value);
+
+ this.values = new DERSet(new DERSequence(v));
+ }
+
+ public RDN(AttributeTypeAndValue attrTAndV)
+ {
+ this.values = new DERSet(attrTAndV);
+ }
+
+ /**
+ * Create a multi-valued RDN.
+ *
+ * @param aAndVs attribute type/value pairs making up the RDN
+ */
+ public RDN(AttributeTypeAndValue[] aAndVs)
+ {
+ this.values = new DERSet(aAndVs);
+ }
+
+ public boolean isMultiValued()
+ {
+ return this.values.size() > 1;
+ }
+
+ /**
+ * Return the number of AttributeTypeAndValue objects in this RDN,
+ *
+ * @return size of RDN, greater than 1 if multi-valued.
+ */
+ public int size()
+ {
+ return this.values.size();
+ }
+
+ public AttributeTypeAndValue getFirst()
+ {
+ if (this.values.size() == 0)
+ {
+ return null;
+ }
+
+ return AttributeTypeAndValue.getInstance(this.values.getObjectAt(0));
+ }
+
+ public AttributeTypeAndValue[] getTypesAndValues()
+ {
+ AttributeTypeAndValue[] tmp = new AttributeTypeAndValue[values.size()];
+
+ for (int i = 0; i != tmp.length; i++)
+ {
+ tmp[i] = AttributeTypeAndValue.getInstance(values.getObjectAt(i));
+ }
+
+ return tmp;
+ }
+
+ /**
+ * <pre>
+ * RelativeDistinguishedName ::=
+ * SET OF AttributeTypeAndValue
+
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue }
+ * </pre>
+ * @return this object as an ASN1Primitive type
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return values;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java
new file mode 100644
index 0000000..50e57c5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500Name.java
@@ -0,0 +1,326 @@
+package org.bouncycastle.asn1.x500;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x500.style.BCStyle;
+
+/**
+ * <pre>
+ * Name ::= CHOICE {
+ * RDNSequence }
+ *
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * value ANY }
+ * </pre>
+ */
+public class X500Name
+ extends ASN1Object
+ implements ASN1Choice
+{
+ private static X500NameStyle defaultStyle = BCStyle.INSTANCE;
+
+ private boolean isHashCodeCalculated;
+ private int hashCodeValue;
+
+ private X500NameStyle style;
+ private RDN[] rdns;
+
+ public X500Name(X500NameStyle style, X500Name name)
+ {
+ this.rdns = name.rdns;
+ this.style = style;
+ }
+
+ /**
+ * Return a X500Name based on the passed in tagged object.
+ *
+ * @param obj tag object holding name.
+ * @param explicit true if explicitly tagged false otherwise.
+ * @return the X500Name
+ */
+ public static X500Name getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ // must be true as choice item
+ return getInstance(ASN1Sequence.getInstance(obj, true));
+ }
+
+ public static X500Name getInstance(
+ Object obj)
+ {
+ if (obj instanceof X500Name)
+ {
+ return (X500Name)obj;
+ }
+ else if (obj != null)
+ {
+ return new X500Name(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public static X500Name getInstance(
+ X500NameStyle style,
+ Object obj)
+ {
+ if (obj instanceof X500Name)
+ {
+ return getInstance(style, ((X500Name)obj).toASN1Primitive());
+ }
+ else if (obj != null)
+ {
+ return new X500Name(style, ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * Constructor from ASN1Sequence
+ *
+ * the principal will be a list of constructed sets, each containing an (OID, String) pair.
+ */
+ private X500Name(
+ ASN1Sequence seq)
+ {
+ this(defaultStyle, seq);
+ }
+
+ private X500Name(
+ X500NameStyle style,
+ ASN1Sequence seq)
+ {
+ this.style = style;
+ this.rdns = new RDN[seq.size()];
+
+ int index = 0;
+
+ for (Enumeration e = seq.getObjects(); e.hasMoreElements();)
+ {
+ rdns[index++] = RDN.getInstance(e.nextElement());
+ }
+ }
+
+ public X500Name(
+ RDN[] rDNs)
+ {
+ this(defaultStyle, rDNs);
+ }
+
+ public X500Name(
+ X500NameStyle style,
+ RDN[] rDNs)
+ {
+ this.rdns = rDNs;
+ this.style = style;
+ }
+
+ public X500Name(
+ String dirName)
+ {
+ this(defaultStyle, dirName);
+ }
+
+ public X500Name(
+ X500NameStyle style,
+ String dirName)
+ {
+ this(style.fromString(dirName));
+
+ this.style = style;
+ }
+
+ /**
+ * return an array of RDNs in structure order.
+ *
+ * @return an array of RDN objects.
+ */
+ public RDN[] getRDNs()
+ {
+ RDN[] tmp = new RDN[this.rdns.length];
+
+ System.arraycopy(rdns, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ /**
+ * return an array of OIDs contained in the attribute type of each RDN in structure order.
+ *
+ * @return an array, possibly zero length, of ASN1ObjectIdentifiers objects.
+ */
+ public ASN1ObjectIdentifier[] getAttributeTypes()
+ {
+ int count = 0;
+
+ for (int i = 0; i != rdns.length; i++)
+ {
+ RDN rdn = rdns[i];
+
+ count += rdn.size();
+ }
+
+ ASN1ObjectIdentifier[] res = new ASN1ObjectIdentifier[count];
+
+ count = 0;
+
+ for (int i = 0; i != rdns.length; i++)
+ {
+ RDN rdn = rdns[i];
+
+ if (rdn.isMultiValued())
+ {
+ AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
+ for (int j = 0; j != attr.length; j++)
+ {
+ res[count++] = attr[j].getType();
+ }
+ }
+ else if (rdn.size() != 0)
+ {
+ res[count++] = rdn.getFirst().getType();
+ }
+ }
+
+ return res;
+ }
+
+ /**
+ * return an array of RDNs containing the attribute type given by OID in structure order.
+ *
+ * @param attributeType the type OID we are looking for.
+ * @return an array, possibly zero length, of RDN objects.
+ */
+ public RDN[] getRDNs(ASN1ObjectIdentifier attributeType)
+ {
+ RDN[] res = new RDN[rdns.length];
+ int count = 0;
+
+ for (int i = 0; i != rdns.length; i++)
+ {
+ RDN rdn = rdns[i];
+
+ if (rdn.isMultiValued())
+ {
+ AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
+ for (int j = 0; j != attr.length; j++)
+ {
+ if (attr[j].getType().equals(attributeType))
+ {
+ res[count++] = rdn;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (rdn.getFirst().getType().equals(attributeType))
+ {
+ res[count++] = rdn;
+ }
+ }
+ }
+
+ RDN[] tmp = new RDN[count];
+
+ System.arraycopy(res, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return new DERSequence(rdns);
+ }
+
+ public int hashCode()
+ {
+ if (isHashCodeCalculated)
+ {
+ return hashCodeValue;
+ }
+
+ isHashCodeCalculated = true;
+
+ hashCodeValue = style.calculateHashCode(this);
+
+ return hashCodeValue;
+ }
+
+ /**
+ * test for equality - note: case is ignored.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof X500Name || obj instanceof ASN1Sequence))
+ {
+ return false;
+ }
+
+ ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
+
+ if (this.toASN1Primitive().equals(derO))
+ {
+ return true;
+ }
+
+ try
+ {
+ return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((ASN1Encodable)obj).toASN1Primitive())));
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ }
+
+ public String toString()
+ {
+ return style.toString(this);
+ }
+
+ /**
+ * Set the default style for X500Name construction.
+ *
+ * @param style an X500NameStyle
+ */
+ public static void setDefaultStyle(X500NameStyle style)
+ {
+ if (style == null)
+ {
+ throw new NullPointerException("cannot set style to null");
+ }
+
+ defaultStyle = style;
+ }
+
+ /**
+ * Return the current default style.
+ *
+ * @return default style for X500Name construction.
+ */
+ public static X500NameStyle getDefaultStyle()
+ {
+ return defaultStyle;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
new file mode 100644
index 0000000..30e871c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
@@ -0,0 +1,81 @@
+package org.bouncycastle.asn1.x500;
+
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public class X500NameBuilder
+{
+ private X500NameStyle template;
+ private Vector rdns = new Vector();
+
+ public X500NameBuilder(X500NameStyle template)
+ {
+ this.template = template;
+ }
+
+ public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, String value)
+ {
+ this.addRDN(oid, template.stringToValue(oid, value));
+
+ return this;
+ }
+
+ public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, ASN1Encodable value)
+ {
+ rdns.addElement(new RDN(oid, value));
+
+ return this;
+ }
+
+ public X500NameBuilder addRDN(AttributeTypeAndValue attrTAndV)
+ {
+ rdns.addElement(new RDN(attrTAndV));
+
+ return this;
+ }
+
+ public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, String[] values)
+ {
+ ASN1Encodable[] vals = new ASN1Encodable[values.length];
+
+ for (int i = 0; i != vals.length; i++)
+ {
+ vals[i] = template.stringToValue(oids[i], values[i]);
+ }
+
+ return addMultiValuedRDN(oids, vals);
+ }
+
+ public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, ASN1Encodable[] values)
+ {
+ AttributeTypeAndValue[] avs = new AttributeTypeAndValue[oids.length];
+
+ for (int i = 0; i != oids.length; i++)
+ {
+ avs[i] = new AttributeTypeAndValue(oids[i], values[i]);
+ }
+
+ return addMultiValuedRDN(avs);
+ }
+
+ public X500NameBuilder addMultiValuedRDN(AttributeTypeAndValue[] attrTAndVs)
+ {
+ rdns.addElement(new RDN(attrTAndVs));
+
+ return this;
+ }
+
+ public X500Name build()
+ {
+ RDN[] vals = new RDN[rdns.size()];
+
+ for (int i = 0; i != vals.length; i++)
+ {
+ vals[i] = (RDN)rdns.elementAt(i);
+ }
+
+ return new X500Name(template, vals);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java
new file mode 100644
index 0000000..7a7c837
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/X500NameStyle.java
@@ -0,0 +1,34 @@
+package org.bouncycastle.asn1.x500;
+
+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).
+ * <p>
+ */
+public interface X500NameStyle
+{
+ /**
+ * Convert the passed in String value into the appropriate ASN.1
+ * encoded object.
+ *
+ * @param oid the oid associated with the value in the DN.
+ * @param value the value of the particular DN component.
+ * @return the ASN.1 equivalent for the value.
+ */
+ ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value);
+
+ ASN1ObjectIdentifier attrNameToOID(String attrName);
+
+ boolean areEqual(X500Name name1, X500Name name2);
+
+ RDN[] fromString(String dirName);
+
+ int calculateHashCode(X500Name name);
+
+ String toString(X500Name name);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java
new file mode 100644
index 0000000..af10fef
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStrictStyle.java
@@ -0,0 +1,33 @@
+package org.bouncycastle.asn1.x500.style;
+
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * Variation of BCStyle that insists on strict ordering for equality
+ * and hashCode comparisons
+ */
+public class BCStrictStyle
+ extends BCStyle
+{
+ public boolean areEqual(X500Name name1, X500Name name2)
+ {
+ RDN[] rdns1 = name1.getRDNs();
+ RDN[] rdns2 = name2.getRDNs();
+
+ if (rdns1.length != rdns2.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != rdns1.length; i++)
+ {
+ if (rdnAreEqual(rdns1[i], rdns2[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
new file mode 100644
index 0000000..32f93ff
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
@@ -0,0 +1,544 @@
+package org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+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
+{
+ public static final X500NameStyle INSTANCE = new BCStyle();
+
+ /**
+ * country code - StringType(SIZE(2))
+ */
+ public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6");
+
+ /**
+ * organization - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10");
+
+ /**
+ * organizational unit name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11");
+
+ /**
+ * Title
+ */
+ public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12");
+
+ /**
+ * common name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3");
+
+ /**
+ * device serial number name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5");
+
+ /**
+ * street - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9");
+
+ /**
+ * device serial number name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier SERIALNUMBER = SN;
+
+ /**
+ * locality name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7");
+
+ /**
+ * state, or province name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8");
+
+ /**
+ * 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");
+
+ /**
+ * businessCategory - DirectoryString(SIZE(1..128)
+ */
+ public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier(
+ "2.5.4.15");
+
+ /**
+ * postalCode - DirectoryString(SIZE(1..40)
+ */
+ public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier(
+ "2.5.4.17");
+
+ /**
+ * dnQualifier - DirectoryString(SIZE(1..64)
+ */
+ public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier(
+ "2.5.4.46");
+
+ /**
+ * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+ */
+ public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier(
+ "2.5.4.65");
+
+
+ /**
+ * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+ */
+ public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier(
+ "1.3.6.1.5.5.7.9.1");
+
+ /**
+ * 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");
+
+ /**
+ * 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");
+
+ /**
+ * 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");
+
+ /**
+ * 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");
+
+
+ /**
+ * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+ */
+ public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14");
+
+ /**
+ * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+ * DirectoryString(SIZE(1..30))
+ */
+ public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16");
+
+ /**
+ * RFC 2256 dmdName
+ */
+ public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54");
+
+ /**
+ * id-at-telephoneNumber
+ */
+ public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;
+
+ /**
+ * id-at-name
+ */
+ public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;
+
+ /**
+ * Email address (RSA PKCS#9 extension) - IA5String.
+ * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+ */
+ public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
+
+ /**
+ * more from PKCS#9
+ */
+ public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;
+ public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;
+
+ /**
+ * email address in Verisign certificates
+ */
+ public static final ASN1ObjectIdentifier E = EmailAddress;
+
+ /*
+ * others...
+ */
+ public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+ /**
+ * LDAP User id.
+ */
+ public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+ /**
+ * default look up table translating OID values into their common symbols following
+ * the convention in RFC 2253 with a few extras
+ */
+ private static final Hashtable DefaultSymbols = new Hashtable();
+
+ /**
+ * look up table translating common symbols into their OIDS.
+ */
+ private static final Hashtable DefaultLookUp = new Hashtable();
+
+ static
+ {
+ DefaultSymbols.put(C, "C");
+ DefaultSymbols.put(O, "O");
+ DefaultSymbols.put(T, "T");
+ DefaultSymbols.put(OU, "OU");
+ DefaultSymbols.put(CN, "CN");
+ DefaultSymbols.put(L, "L");
+ DefaultSymbols.put(ST, "ST");
+ DefaultSymbols.put(SN, "SERIALNUMBER");
+ DefaultSymbols.put(EmailAddress, "E");
+ DefaultSymbols.put(DC, "DC");
+ DefaultSymbols.put(UID, "UID");
+ DefaultSymbols.put(STREET, "STREET");
+ DefaultSymbols.put(SURNAME, "SURNAME");
+ DefaultSymbols.put(GIVENNAME, "GIVENNAME");
+ DefaultSymbols.put(INITIALS, "INITIALS");
+ DefaultSymbols.put(GENERATION, "GENERATION");
+ DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress");
+ DefaultSymbols.put(UnstructuredName, "unstructuredName");
+ DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier");
+ DefaultSymbols.put(DN_QUALIFIER, "DN");
+ DefaultSymbols.put(PSEUDONYM, "Pseudonym");
+ DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress");
+ DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth");
+ DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship");
+ DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence");
+ DefaultSymbols.put(GENDER, "Gender");
+ DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth");
+ DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth");
+ DefaultSymbols.put(POSTAL_CODE, "PostalCode");
+ DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory");
+ DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber");
+ DefaultSymbols.put(NAME, "Name");
+
+ DefaultLookUp.put("c", C);
+ DefaultLookUp.put("o", O);
+ DefaultLookUp.put("t", T);
+ DefaultLookUp.put("ou", OU);
+ DefaultLookUp.put("cn", CN);
+ DefaultLookUp.put("l", L);
+ DefaultLookUp.put("st", ST);
+ DefaultLookUp.put("sn", SN);
+ DefaultLookUp.put("serialnumber", SN);
+ DefaultLookUp.put("street", STREET);
+ DefaultLookUp.put("emailaddress", E);
+ DefaultLookUp.put("dc", DC);
+ DefaultLookUp.put("e", E);
+ DefaultLookUp.put("uid", UID);
+ DefaultLookUp.put("surname", SURNAME);
+ DefaultLookUp.put("givenname", GIVENNAME);
+ DefaultLookUp.put("initials", INITIALS);
+ DefaultLookUp.put("generation", GENERATION);
+ DefaultLookUp.put("unstructuredaddress", UnstructuredAddress);
+ DefaultLookUp.put("unstructuredname", UnstructuredName);
+ DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER);
+ DefaultLookUp.put("dn", DN_QUALIFIER);
+ DefaultLookUp.put("pseudonym", PSEUDONYM);
+ DefaultLookUp.put("postaladdress", POSTAL_ADDRESS);
+ DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH);
+ DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP);
+ DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE);
+ DefaultLookUp.put("gender", GENDER);
+ DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH);
+ DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH);
+ DefaultLookUp.put("postalcode", POSTAL_CODE);
+ DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY);
+ DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER);
+ DefaultLookUp.put("name", NAME);
+ }
+
+ protected BCStyle()
+ {
+
+ }
+
+ 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 RuntimeException("can't recode value for oid " + oid.getId());
+ }
+ }
+ else
+ {
+ 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 DERGeneralizedTime(value);
+ }
+ else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER)
+ || oid.equals(TELEPHONE_NUMBER))
+ {
+ return new DERPrintableString(value);
+ }
+ }
+
+ return new DERUTF8String(value);
+ }
+
+ public ASN1ObjectIdentifier attrNameToOID(String attrName)
+ {
+ 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)
+ {
+ if (rdn1.isMultiValued())
+ {
+ if (rdn2.isMultiValued())
+ {
+ AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues();
+ AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues();
+
+ if (atvs1.length != atvs2.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != atvs1.length; i++)
+ {
+ if (!atvAreEqual(atvs1[i], atvs2[i]))
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!rdn2.isMultiValued())
+ {
+ return atvAreEqual(rdn1.getFirst(), rdn2.getFirst());
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean atvAreEqual(AttributeTypeAndValue atv1, AttributeTypeAndValue atv2)
+ {
+ if (atv1 == atv2)
+ {
+ return true;
+ }
+
+ if (atv1 == null)
+ {
+ return false;
+ }
+
+ if (atv2 == null)
+ {
+ return false;
+ }
+
+ ASN1ObjectIdentifier o1 = atv1.getType();
+ ASN1ObjectIdentifier o2 = atv2.getType();
+
+ if (!o1.equals(o2))
+ {
+ return false;
+ }
+
+ String v1 = IETFUtils.canonicalize(IETFUtils.valueToString(atv1.getValue()));
+ String v2 = IETFUtils.canonicalize(IETFUtils.valueToString(atv2.getValue()));
+
+ if (!v1.equals(v2))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ 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();
+ boolean first = true;
+
+ RDN[] rdns = name.getRDNs();
+
+ for (int i = 0; i < rdns.length; i++)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(',');
+ }
+
+ if (rdns[i].isMultiValued())
+ {
+ AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
+ boolean firstAtv = true;
+
+ for (int j = 0; j != atv.length; j++)
+ {
+ if (firstAtv)
+ {
+ firstAtv = false;
+ }
+ else
+ {
+ buf.append('+');
+ }
+
+ IETFUtils.appendTypeAndValue(buf, atv[j], DefaultSymbols);
+ }
+ }
+ else
+ {
+ IETFUtils.appendTypeAndValue(buf, rdns[i].getFirst(), DefaultSymbols);
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
new file mode 100644
index 0000000..5c60c89
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
@@ -0,0 +1,301 @@
+package org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1String;
+import org.bouncycastle.asn1.DERUniversalString;
+import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
+import org.bouncycastle.asn1.x500.RDN;
+import org.bouncycastle.asn1.x500.X500NameBuilder;
+import org.bouncycastle.asn1.x500.X500NameStyle;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+public class IETFUtils
+{
+ public static RDN[] rDNsFromString(String name, X500NameStyle x500Style)
+ {
+ X500NameTokenizer nTok = new X500NameTokenizer(name);
+ X500NameBuilder builder = new X500NameBuilder(x500Style);
+
+ while (nTok.hasMoreTokens())
+ {
+ String token = nTok.nextToken();
+ int index = token.indexOf('=');
+
+ if (index == -1)
+ {
+ throw new IllegalArgumentException("badly formated directory string");
+ }
+
+ String attr = token.substring(0, index);
+ String value = token.substring(index + 1);
+ ASN1ObjectIdentifier oid = x500Style.attrNameToOID(attr);
+
+ if (value.indexOf('+') > 0)
+ {
+ X500NameTokenizer vTok = new X500NameTokenizer(value, '+');
+ String v = vTok.nextToken();
+
+ Vector oids = new Vector();
+ Vector values = new Vector();
+
+ oids.addElement(oid);
+ values.addElement(v);
+
+ while (vTok.hasMoreTokens())
+ {
+ String sv = vTok.nextToken();
+ int ndx = sv.indexOf('=');
+
+ String nm = sv.substring(0, ndx);
+ String vl = sv.substring(ndx + 1);
+
+ oids.addElement(x500Style.attrNameToOID(nm));
+ values.addElement(vl);
+ }
+
+ builder.addMultiValuedRDN(toOIDArray(oids), toValueArray(values));
+ }
+ else
+ {
+ builder.addRDN(oid, value);
+ }
+ }
+
+ return builder.build().getRDNs();
+ }
+
+ private static String[] toValueArray(Vector values)
+ {
+ String[] tmp = new String[values.size()];
+
+ for (int i = 0; i != tmp.length; i++)
+ {
+ tmp[i] = (String)values.elementAt(i);
+ }
+
+ return tmp;
+ }
+
+ private static ASN1ObjectIdentifier[] toOIDArray(Vector oids)
+ {
+ ASN1ObjectIdentifier[] tmp = new ASN1ObjectIdentifier[oids.size()];
+
+ for (int i = 0; i != tmp.length; i++)
+ {
+ tmp[i] = (ASN1ObjectIdentifier)oids.elementAt(i);
+ }
+
+ return tmp;
+ }
+
+ public static ASN1ObjectIdentifier decodeAttrName(
+ String name,
+ Hashtable lookUp)
+ {
+ if (Strings.toUpperCase(name).startsWith("OID."))
+ {
+ return new ASN1ObjectIdentifier(name.substring(4));
+ }
+ else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
+ {
+ return new ASN1ObjectIdentifier(name);
+ }
+
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
+ if (oid == null)
+ {
+ throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+ }
+
+ return oid;
+ }
+
+ public static ASN1Encodable valueFromHexString(
+ String str,
+ int off)
+ throws IOException
+ {
+ str = Strings.toLowerCase(str);
+ byte[] data = new byte[(str.length() - off) / 2];
+ for (int index = 0; index != data.length; index++)
+ {
+ char left = str.charAt((index * 2) + off);
+ char right = str.charAt((index * 2) + off + 1);
+
+ if (left < 'a')
+ {
+ data[index] = (byte)((left - '0') << 4);
+ }
+ else
+ {
+ data[index] = (byte)((left - 'a' + 10) << 4);
+ }
+ if (right < 'a')
+ {
+ data[index] |= (byte)(right - '0');
+ }
+ else
+ {
+ data[index] |= (byte)(right - 'a' + 10);
+ }
+ }
+
+ return ASN1Primitive.fromByteArray(data);
+ }
+
+ public static void appendTypeAndValue(
+ StringBuffer buf,
+ AttributeTypeAndValue typeAndValue,
+ Hashtable oidSymbols)
+ {
+ String sym = (String)oidSymbols.get(typeAndValue.getType());
+
+ if (sym != null)
+ {
+ buf.append(sym);
+ }
+ else
+ {
+ buf.append(typeAndValue.getType().getId());
+ }
+
+ buf.append('=');
+
+ buf.append(valueToString(typeAndValue.getValue()));
+ }
+
+ public static String valueToString(ASN1Encodable value)
+ {
+ StringBuffer vBuf = new StringBuffer();
+
+ if (value instanceof ASN1String && !(value instanceof DERUniversalString))
+ {
+ String v = ((ASN1String)value).getString();
+ if (v.length() > 0 && v.charAt(0) == '#')
+ {
+ vBuf.append("\\" + v);
+ }
+ else
+ {
+ vBuf.append(v);
+ }
+ }
+ else
+ {
+ try
+ {
+ vBuf.append("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("Other value has no encoded form");
+ }
+ }
+
+ int end = vBuf.length();
+ int index = 0;
+
+ if (vBuf.length() >= 2 && vBuf.charAt(0) == '\\' && vBuf.charAt(1) == '#')
+ {
+ index += 2;
+ }
+
+ while (index != end)
+ {
+ if ((vBuf.charAt(index) == ',')
+ || (vBuf.charAt(index) == '"')
+ || (vBuf.charAt(index) == '\\')
+ || (vBuf.charAt(index) == '+')
+ || (vBuf.charAt(index) == '=')
+ || (vBuf.charAt(index) == '<')
+ || (vBuf.charAt(index) == '>')
+ || (vBuf.charAt(index) == ';'))
+ {
+ vBuf.insert(index, "\\");
+ index++;
+ end++;
+ }
+
+ index++;
+ }
+
+ return vBuf.toString();
+ }
+
+ private static String bytesToString(
+ byte[] data)
+ {
+ char[] cs = new char[data.length];
+
+ for (int i = 0; i != cs.length; i++)
+ {
+ cs[i] = (char)(data[i] & 0xff);
+ }
+
+ return new String(cs);
+ }
+
+ public static String canonicalize(String s)
+ {
+ String value = Strings.toLowerCase(s.trim());
+
+ if (value.length() > 0 && value.charAt(0) == '#')
+ {
+ ASN1Primitive obj = decodeObject(value);
+
+ if (obj instanceof ASN1String)
+ {
+ value = Strings.toLowerCase(((ASN1String)obj).getString().trim());
+ }
+ }
+
+ value = stripInternalSpaces(value);
+
+ return value;
+ }
+
+ private static ASN1Primitive decodeObject(String oValue)
+ {
+ try
+ {
+ return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("unknown encoding in name: " + e);
+ }
+ }
+
+ public static String stripInternalSpaces(
+ String str)
+ {
+ StringBuffer res = new StringBuffer();
+
+ if (str.length() != 0)
+ {
+ char c1 = str.charAt(0);
+
+ res.append(c1);
+
+ for (int k = 1; k < str.length(); k++)
+ {
+ char c2 = str.charAt(k);
+ if (!(c1 == ' ' && c2 == ' '))
+ {
+ res.append(c2);
+ }
+ c1 = c2;
+ }
+ }
+
+ return res.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
new file mode 100644
index 0000000..63f1a25
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
@@ -0,0 +1,443 @@
+package org.bouncycastle.asn1.x500.style;
+
+import java.io.IOException;
+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
+{
+ public static final X500NameStyle INSTANCE = new RFC4519Style();
+
+ 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");
+
+ /**
+ * default look up table translating OID values into their common symbols following
+ * the convention in RFC 2253 with a few extras
+ */
+ private static final Hashtable DefaultSymbols = new Hashtable();
+
+ /**
+ * look up table translating common symbols into their OIDS.
+ */
+ private static final Hashtable DefaultLookUp = new Hashtable();
+
+ static
+ {
+ DefaultSymbols.put(businessCategory, "businessCategory");
+ DefaultSymbols.put(c, "c");
+ DefaultSymbols.put(cn, "cn");
+ DefaultSymbols.put(dc, "dc");
+ DefaultSymbols.put(description, "description");
+ DefaultSymbols.put(destinationIndicator, "destinationIndicator");
+ DefaultSymbols.put(distinguishedName, "distinguishedName");
+ DefaultSymbols.put(dnQualifier, "dnQualifier");
+ DefaultSymbols.put(enhancedSearchGuide, "enhancedSearchGuide");
+ DefaultSymbols.put(facsimileTelephoneNumber, "facsimileTelephoneNumber");
+ DefaultSymbols.put(generationQualifier, "generationQualifier");
+ DefaultSymbols.put(givenName, "givenName");
+ DefaultSymbols.put(houseIdentifier, "houseIdentifier");
+ DefaultSymbols.put(initials, "initials");
+ DefaultSymbols.put(internationalISDNNumber, "internationalISDNNumber");
+ DefaultSymbols.put(l, "l");
+ DefaultSymbols.put(member, "member");
+ DefaultSymbols.put(name, "name");
+ DefaultSymbols.put(o, "o");
+ DefaultSymbols.put(ou, "ou");
+ DefaultSymbols.put(owner, "owner");
+ DefaultSymbols.put(physicalDeliveryOfficeName, "physicalDeliveryOfficeName");
+ DefaultSymbols.put(postalAddress, "postalAddress");
+ DefaultSymbols.put(postalCode, "postalCode");
+ DefaultSymbols.put(postOfficeBox, "postOfficeBox");
+ DefaultSymbols.put(preferredDeliveryMethod, "preferredDeliveryMethod");
+ DefaultSymbols.put(registeredAddress, "registeredAddress");
+ DefaultSymbols.put(roleOccupant, "roleOccupant");
+ DefaultSymbols.put(searchGuide, "searchGuide");
+ DefaultSymbols.put(seeAlso, "seeAlso");
+ DefaultSymbols.put(serialNumber, "serialNumber");
+ DefaultSymbols.put(sn, "sn");
+ DefaultSymbols.put(st, "st");
+ DefaultSymbols.put(street, "street");
+ DefaultSymbols.put(telephoneNumber, "telephoneNumber");
+ DefaultSymbols.put(teletexTerminalIdentifier, "teletexTerminalIdentifier");
+ DefaultSymbols.put(telexNumber, "telexNumber");
+ DefaultSymbols.put(title, "title");
+ DefaultSymbols.put(uid, "uid");
+ DefaultSymbols.put(uniqueMember, "uniqueMember");
+ DefaultSymbols.put(userPassword, "userPassword");
+ DefaultSymbols.put(x121Address, "x121Address");
+ DefaultSymbols.put(x500UniqueIdentifier, "x500UniqueIdentifier");
+
+ DefaultLookUp.put("businesscategory", businessCategory);
+ DefaultLookUp.put("c", c);
+ DefaultLookUp.put("cn", cn);
+ DefaultLookUp.put("dc", dc);
+ DefaultLookUp.put("description", description);
+ DefaultLookUp.put("destinationindicator", destinationIndicator);
+ DefaultLookUp.put("distinguishedname", distinguishedName);
+ DefaultLookUp.put("dnqualifier", dnQualifier);
+ DefaultLookUp.put("enhancedsearchguide", enhancedSearchGuide);
+ DefaultLookUp.put("facsimiletelephonenumber", facsimileTelephoneNumber);
+ DefaultLookUp.put("generationqualifier", generationQualifier);
+ DefaultLookUp.put("givenname", givenName);
+ DefaultLookUp.put("houseidentifier", houseIdentifier);
+ DefaultLookUp.put("initials", initials);
+ DefaultLookUp.put("internationalisdnnumber", internationalISDNNumber);
+ DefaultLookUp.put("l", l);
+ DefaultLookUp.put("member", member);
+ DefaultLookUp.put("name", name);
+ DefaultLookUp.put("o", o);
+ DefaultLookUp.put("ou", ou);
+ DefaultLookUp.put("owner", owner);
+ DefaultLookUp.put("physicaldeliveryofficename", physicalDeliveryOfficeName);
+ DefaultLookUp.put("postaladdress", postalAddress);
+ DefaultLookUp.put("postalcode", postalCode);
+ DefaultLookUp.put("postofficebox", postOfficeBox);
+ DefaultLookUp.put("preferreddeliverymethod", preferredDeliveryMethod);
+ DefaultLookUp.put("registeredaddress", registeredAddress);
+ DefaultLookUp.put("roleoccupant", roleOccupant);
+ DefaultLookUp.put("searchguide", searchGuide);
+ DefaultLookUp.put("seealso", seeAlso);
+ DefaultLookUp.put("serialnumber", serialNumber);
+ DefaultLookUp.put("sn", sn);
+ DefaultLookUp.put("st", st);
+ DefaultLookUp.put("street", street);
+ DefaultLookUp.put("telephonenumber", telephoneNumber);
+ DefaultLookUp.put("teletexterminalidentifier", teletexTerminalIdentifier);
+ DefaultLookUp.put("telexnumber", telexNumber);
+ DefaultLookUp.put("title", title);
+ DefaultLookUp.put("uid", uid);
+ DefaultLookUp.put("uniquemember", uniqueMember);
+ DefaultLookUp.put("userpassword", userPassword);
+ DefaultLookUp.put("x121address", x121Address);
+ DefaultLookUp.put("x500uniqueidentifier", x500UniqueIdentifier);
+
+ // TODO: need to add correct matching for equality comparisons.
+ }
+
+ protected RFC4519Style()
+ {
+
+ }
+
+ 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 RuntimeException("can't recode value for oid " + oid.getId());
+ }
+ }
+ else
+ {
+ 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 DERUTF8String(value);
+ }
+
+ public ASN1ObjectIdentifier attrNameToOID(String attrName)
+ {
+ 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)
+ {
+ if (rdn1.isMultiValued())
+ {
+ if (rdn2.isMultiValued())
+ {
+ AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues();
+ AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues();
+
+ if (atvs1.length != atvs2.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != atvs1.length; i++)
+ {
+ if (!atvAreEqual(atvs1[i], atvs2[i]))
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!rdn2.isMultiValued())
+ {
+ return atvAreEqual(rdn1.getFirst(), rdn2.getFirst());
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean atvAreEqual(AttributeTypeAndValue atv1, AttributeTypeAndValue atv2)
+ {
+ if (atv1 == atv2)
+ {
+ return true;
+ }
+
+ if (atv1 == null)
+ {
+ return false;
+ }
+
+ if (atv2 == null)
+ {
+ return false;
+ }
+
+ ASN1ObjectIdentifier o1 = atv1.getType();
+ ASN1ObjectIdentifier o2 = atv2.getType();
+
+ if (!o1.equals(o2))
+ {
+ return false;
+ }
+
+ String v1 = IETFUtils.canonicalize(IETFUtils.valueToString(atv1.getValue()));
+ String v2 = IETFUtils.canonicalize(IETFUtils.valueToString(atv2.getValue()));
+
+ if (!v1.equals(v2))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ // parse backwards
+ public RDN[] fromString(String dirName)
+ {
+ RDN[] tmp = IETFUtils.rDNsFromString(dirName, this);
+ RDN[] res = new RDN[tmp.length];
+
+ for (int i = 0; i != tmp.length; i++)
+ {
+ res[res.length - i - 1] = tmp[i];
+ }
+
+ 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)
+ {
+ StringBuffer buf = new StringBuffer();
+ boolean first = true;
+
+ RDN[] rdns = name.getRDNs();
+
+ for (int i = rdns.length - 1; i >= 0; i--)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(',');
+ }
+
+ if (rdns[i].isMultiValued())
+ {
+ AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
+ boolean firstAtv = true;
+
+ for (int j = 0; j != atv.length; j++)
+ {
+ if (firstAtv)
+ {
+ firstAtv = false;
+ }
+ else
+ {
+ buf.append('+');
+ }
+
+ IETFUtils.appendTypeAndValue(buf, atv[j], DefaultSymbols);
+ }
+ }
+ else
+ {
+ IETFUtils.appendTypeAndValue(buf, rdns[i].getFirst(), DefaultSymbols);
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java
new file mode 100644
index 0000000..7549a72
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java
@@ -0,0 +1,99 @@
+package org.bouncycastle.asn1.x500.style;
+
+/**
+ * class for breaking up an X500 Name 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.
+ */
+class X500NameTokenizer
+{
+ private String value;
+ private int index;
+ private char seperator;
+ private StringBuffer buf = new StringBuffer();
+
+ public X500NameTokenizer(
+ String oid)
+ {
+ this(oid, ',');
+ }
+
+ public X500NameTokenizer(
+ String oid,
+ char seperator)
+ {
+ this.value = oid;
+ this.index = -1;
+ this.seperator = seperator;
+ }
+
+ public boolean hasMoreTokens()
+ {
+ return (index != value.length());
+ }
+
+ public String nextToken()
+ {
+ if (index == value.length())
+ {
+ return null;
+ }
+
+ int end = index + 1;
+ boolean quoted = false;
+ boolean escaped = false;
+
+ buf.setLength(0);
+
+ while (end != value.length())
+ {
+ char c = value.charAt(end);
+
+ if (c == '"')
+ {
+ if (!escaped)
+ {
+ quoted = !quoted;
+ }
+ else
+ {
+ buf.append(c);
+ }
+ escaped = false;
+ }
+ else
+ {
+ if (escaped || quoted)
+ {
+ if (c == '#' && buf.charAt(buf.length() - 1) == '=')
+ {
+ buf.append('\\');
+ }
+ else if (c == '+' && seperator != '+')
+ {
+ buf.append('\\');
+ }
+ buf.append(c);
+ escaped = false;
+ }
+ else if (c == '\\')
+ {
+ escaped = true;
+ }
+ else if (c == seperator)
+ {
+ break;
+ }
+ else
+ {
+ buf.append(c);
+ }
+ }
+ end++;
+ }
+
+ index = end;
+ return buf.toString().trim();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
new file mode 100644
index 0000000..6f7c3be
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
@@ -0,0 +1,173 @@
+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.ASN1SequenceParser;
+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 ASN1Encodable parameters;
+ private boolean parametersDefined = false;
+
+ public static AlgorithmIdentifier getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static AlgorithmIdentifier getInstance(
+ Object obj)
+ {
+ if (obj== null || obj instanceof AlgorithmIdentifier)
+ {
+ return (AlgorithmIdentifier)obj;
+ }
+
+ if (obj instanceof ASN1ObjectIdentifier)
+ {
+ return new AlgorithmIdentifier((ASN1ObjectIdentifier)obj);
+ }
+
+ if (obj instanceof String)
+ {
+ return new AlgorithmIdentifier((String)obj);
+ }
+
+ if (obj instanceof ASN1Sequence || obj instanceof ASN1SequenceParser)
+ {
+ return new AlgorithmIdentifier(ASN1Sequence.getInstance(obj));
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ 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());
+ }
+
+ /**
+ * @deprecated use ASN1ObjectIdentifier
+ * @param objectId
+ * @param parameters
+ */
+ public AlgorithmIdentifier(
+ DERObjectIdentifier objectId,
+ ASN1Encodable parameters)
+ {
+ parametersDefined = true;
+ this.objectId = new ASN1ObjectIdentifier(objectId.getId());
+ this.parameters = parameters;
+ }
+
+ public AlgorithmIdentifier(
+ ASN1ObjectIdentifier objectId,
+ ASN1Encodable parameters)
+ {
+ parametersDefined = true;
+ this.objectId = objectId;
+ this.parameters = parameters;
+ }
+
+ public AlgorithmIdentifier(
+ ASN1Sequence seq)
+ {
+ if (seq.size() < 1 || seq.size() > 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ objectId = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+
+ if (seq.size() == 2)
+ {
+ parametersDefined = true;
+ parameters = seq.getObjectAt(1);
+ }
+ else
+ {
+ parameters = null;
+ }
+ }
+
+ public ASN1ObjectIdentifier getAlgorithm()
+ {
+ return new ASN1ObjectIdentifier(objectId.getId());
+ }
+
+ /**
+ * @deprecated use getAlgorithm
+ * @return
+ */
+ public ASN1ObjectIdentifier getObjectId()
+ {
+ return objectId;
+ }
+
+ public ASN1Encodable getParameters()
+ {
+ return parameters;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(objectId);
+
+ if (parametersDefined)
+ {
+ if (parameters != null)
+ {
+ v.add(parameters);
+ }
+ else
+ {
+ v.add(DERNull.INSTANCE);
+ }
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java
new file mode 100644
index 0000000..21907c6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttCertIssuer.java
@@ -0,0 +1,91 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+public class AttCertIssuer
+ extends ASN1Object
+ implements ASN1Choice
+{
+ ASN1Encodable obj;
+ ASN1Primitive choiceObj;
+
+ public static AttCertIssuer getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof AttCertIssuer)
+ {
+ return (AttCertIssuer)obj;
+ }
+ else if (obj instanceof V2Form)
+ {
+ return new AttCertIssuer(V2Form.getInstance(obj));
+ }
+ else if (obj instanceof GeneralNames)
+ {
+ return new AttCertIssuer((GeneralNames)obj);
+ }
+ else if (obj instanceof ASN1TaggedObject)
+ {
+ return new AttCertIssuer(V2Form.getInstance((ASN1TaggedObject)obj, false));
+ }
+ else if (obj instanceof ASN1Sequence)
+ {
+ return new AttCertIssuer(GeneralNames.getInstance(obj));
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ public static AttCertIssuer getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(obj.getObject()); // must be explicitly tagged
+ }
+
+ /**
+ * Don't use this one if you are trying to be RFC 3281 compliant.
+ * Use it for v1 attribute certificates only.
+ *
+ * @param names our GeneralNames structure
+ */
+ public AttCertIssuer(
+ GeneralNames names)
+ {
+ obj = names;
+ choiceObj = obj.toASN1Primitive();
+ }
+
+ public AttCertIssuer(
+ V2Form v2Form)
+ {
+ obj = v2Form;
+ choiceObj = new DERTaggedObject(false, 0, obj);
+ }
+
+ public ASN1Encodable getIssuer()
+ {
+ return obj;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * AttCertIssuer ::= CHOICE {
+ * v1Form GeneralNames, -- MUST NOT be used in this
+ * -- profile
+ * v2Form [0] V2Form -- v2 only
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return choiceObj;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
new file mode 100644
index 0000000..e157b66
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
@@ -0,0 +1,84 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERSequence;
+
+public class AttCertValidityPeriod
+ extends ASN1Object
+{
+ DERGeneralizedTime notBeforeTime;
+ DERGeneralizedTime notAfterTime;
+
+ public static AttCertValidityPeriod getInstance(
+ Object obj)
+ {
+ if (obj instanceof AttCertValidityPeriod)
+ {
+ return (AttCertValidityPeriod)obj;
+ }
+ else if (obj != null)
+ {
+ return new AttCertValidityPeriod(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private AttCertValidityPeriod(
+ ASN1Sequence seq)
+ {
+ if (seq.size() != 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ notBeforeTime = DERGeneralizedTime.getInstance(seq.getObjectAt(0));
+ notAfterTime = DERGeneralizedTime.getInstance(seq.getObjectAt(1));
+ }
+
+ /**
+ * @param notBeforeTime
+ * @param notAfterTime
+ */
+ public AttCertValidityPeriod(
+ DERGeneralizedTime notBeforeTime,
+ DERGeneralizedTime notAfterTime)
+ {
+ this.notBeforeTime = notBeforeTime;
+ this.notAfterTime = notAfterTime;
+ }
+
+ public DERGeneralizedTime getNotBeforeTime()
+ {
+ return notBeforeTime;
+ }
+
+ public DERGeneralizedTime getNotAfterTime()
+ {
+ return notAfterTime;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * AttCertValidityPeriod ::= SEQUENCE {
+ * notBeforeTime GeneralizedTime,
+ * notAfterTime GeneralizedTime
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(notBeforeTime);
+ v.add(notAfterTime);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Attribute.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
new file mode 100644
index 0000000..b8d4bde
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Attribute.java
@@ -0,0 +1,93 @@
+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.ASN1Set;
+import org.bouncycastle.asn1.DERSequence;
+
+public class Attribute
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier attrType;
+ private ASN1Set attrValues;
+
+ /**
+ * return an Attribute object from the given object.
+ *
+ * @param o the object we want converted.
+ * @exception IllegalArgumentException if the object cannot be converted.
+ */
+ public static Attribute getInstance(
+ Object o)
+ {
+ if (o instanceof Attribute)
+ {
+ return (Attribute)o;
+ }
+
+ if (o != null)
+ {
+ return new Attribute(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ private Attribute(
+ ASN1Sequence seq)
+ {
+ if (seq.size() != 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+ }
+
+ attrType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+ attrValues = ASN1Set.getInstance(seq.getObjectAt(1));
+ }
+
+ public Attribute(
+ ASN1ObjectIdentifier attrType,
+ ASN1Set attrValues)
+ {
+ this.attrType = attrType;
+ this.attrValues = attrValues;
+ }
+
+ public ASN1ObjectIdentifier getAttrType()
+ {
+ return new ASN1ObjectIdentifier(attrType.getId());
+ }
+
+ public ASN1Encodable[] getAttributeValues()
+ {
+ return attrValues.toArray();
+ }
+
+ public ASN1Set getAttrValues()
+ {
+ return attrValues;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * Attribute ::= SEQUENCE {
+ * attrType OBJECT IDENTIFIER,
+ * attrValues SET OF AttributeValue
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(attrType);
+ v.add(attrValues);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
new file mode 100644
index 0000000..92aa0f7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificate.java
@@ -0,0 +1,94 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class AttributeCertificate
+ extends ASN1Object
+{
+ AttributeCertificateInfo acinfo;
+ AlgorithmIdentifier signatureAlgorithm;
+ DERBitString signatureValue;
+
+ /**
+ * @param obj
+ * @return an AttributeCertificate object
+ */
+ public static AttributeCertificate getInstance(Object obj)
+ {
+ if (obj instanceof AttributeCertificate)
+ {
+ return (AttributeCertificate)obj;
+ }
+ else if (obj != null)
+ {
+ return new AttributeCertificate(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public AttributeCertificate(
+ AttributeCertificateInfo acinfo,
+ AlgorithmIdentifier signatureAlgorithm,
+ DERBitString signatureValue)
+ {
+ this.acinfo = acinfo;
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.signatureValue = signatureValue;
+ }
+
+ public AttributeCertificate(
+ ASN1Sequence seq)
+ {
+ if (seq.size() != 3)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ this.acinfo = AttributeCertificateInfo.getInstance(seq.getObjectAt(0));
+ this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+ this.signatureValue = DERBitString.getInstance(seq.getObjectAt(2));
+ }
+
+ public AttributeCertificateInfo getAcinfo()
+ {
+ return acinfo;
+ }
+
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return signatureAlgorithm;
+ }
+
+ public DERBitString getSignatureValue()
+ {
+ return signatureValue;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * AttributeCertificate ::= SEQUENCE {
+ * acinfo AttributeCertificateInfo,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(acinfo);
+ v.add(signatureAlgorithm);
+ v.add(signatureValue);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
new file mode 100644
index 0000000..7b9d450
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
@@ -0,0 +1,166 @@
+package org.bouncycastle.asn1.x509;
+
+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.DERBitString;
+import org.bouncycastle.asn1.DERSequence;
+
+public class AttributeCertificateInfo
+ extends ASN1Object
+{
+ private ASN1Integer version;
+ private Holder holder;
+ private AttCertIssuer issuer;
+ private AlgorithmIdentifier signature;
+ private ASN1Integer serialNumber;
+ private AttCertValidityPeriod attrCertValidityPeriod;
+ private ASN1Sequence attributes;
+ private DERBitString issuerUniqueID;
+ private Extensions extensions;
+
+ public static AttributeCertificateInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static AttributeCertificateInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof AttributeCertificateInfo)
+ {
+ return (AttributeCertificateInfo)obj;
+ }
+ else if (obj != null)
+ {
+ return new AttributeCertificateInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private AttributeCertificateInfo(
+ ASN1Sequence seq)
+ {
+ if (seq.size() < 7 || seq.size() > 9)
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+ }
+
+ this.version = ASN1Integer.getInstance(seq.getObjectAt(0));
+ this.holder = Holder.getInstance(seq.getObjectAt(1));
+ this.issuer = AttCertIssuer.getInstance(seq.getObjectAt(2));
+ this.signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(3));
+ this.serialNumber = ASN1Integer.getInstance(seq.getObjectAt(4));
+ this.attrCertValidityPeriod = AttCertValidityPeriod.getInstance(seq.getObjectAt(5));
+ this.attributes = ASN1Sequence.getInstance(seq.getObjectAt(6));
+
+ for (int i = 7; i < seq.size(); i++)
+ {
+ ASN1Encodable obj = (ASN1Encodable)seq.getObjectAt(i);
+
+ if (obj instanceof DERBitString)
+ {
+ this.issuerUniqueID = DERBitString.getInstance(seq.getObjectAt(i));
+ }
+ else if (obj instanceof ASN1Sequence || obj instanceof Extensions)
+ {
+ this.extensions = Extensions.getInstance(seq.getObjectAt(i));
+ }
+ }
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public Holder getHolder()
+ {
+ return holder;
+ }
+
+ public AttCertIssuer getIssuer()
+ {
+ return issuer;
+ }
+
+ public AlgorithmIdentifier getSignature()
+ {
+ return signature;
+ }
+
+ public ASN1Integer getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ public AttCertValidityPeriod getAttrCertValidityPeriod()
+ {
+ return attrCertValidityPeriod;
+ }
+
+ public ASN1Sequence getAttributes()
+ {
+ return attributes;
+ }
+
+ public DERBitString getIssuerUniqueID()
+ {
+ return issuerUniqueID;
+ }
+
+ public Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * AttributeCertificateInfo ::= SEQUENCE {
+ * version AttCertVersion -- version is v2,
+ * holder Holder,
+ * issuer AttCertIssuer,
+ * signature AlgorithmIdentifier,
+ * serialNumber CertificateSerialNumber,
+ * attrCertValidityPeriod AttCertValidityPeriod,
+ * attributes SEQUENCE OF Attribute,
+ * issuerUniqueID UniqueIdentifier OPTIONAL,
+ * extensions Extensions OPTIONAL
+ * }
+ *
+ * AttCertVersion ::= INTEGER { v2(1) }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(holder);
+ v.add(issuer);
+ v.add(signature);
+ v.add(serialNumber);
+ v.add(attrCertValidityPeriod);
+ v.add(attributes);
+
+ if (issuerUniqueID != null)
+ {
+ v.add(issuerUniqueID);
+ }
+
+ if (extensions != null)
+ {
+ v.add(extensions);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
new file mode 100644
index 0000000..84ef3da
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
@@ -0,0 +1,233 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.crypto.Digest;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-changed
+
+/**
+ * The AuthorityKeyIdentifier object.
+ * <pre>
+ * id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 }
+ *
+ * AuthorityKeyIdentifier ::= SEQUENCE {
+ * keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL,
+ * authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL,
+ * authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL }
+ *
+ * KeyIdentifier ::= OCTET STRING
+ * </pre>
+ *
+ */
+public class AuthorityKeyIdentifier
+ extends ASN1Object
+{
+ ASN1OctetString keyidentifier=null;
+ GeneralNames certissuer=null;
+ ASN1Integer certserno=null;
+
+ public static AuthorityKeyIdentifier getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static AuthorityKeyIdentifier getInstance(
+ Object obj)
+ {
+ if (obj instanceof AuthorityKeyIdentifier)
+ {
+ return (AuthorityKeyIdentifier)obj;
+ }
+ if (obj != null)
+ {
+ return new AuthorityKeyIdentifier(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ protected AuthorityKeyIdentifier(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ ASN1TaggedObject o = DERTaggedObject.getInstance(e.nextElement());
+
+ switch (o.getTagNo())
+ {
+ case 0:
+ this.keyidentifier = ASN1OctetString.getInstance(o, false);
+ break;
+ case 1:
+ this.certissuer = GeneralNames.getInstance(o, false);
+ break;
+ case 2:
+ this.certserno = ASN1Integer.getInstance(o, false);
+ break;
+ default:
+ throw new IllegalArgumentException("illegal tag");
+ }
+ }
+ }
+
+ /**
+ *
+ * Calulates the keyidentifier using a SHA1 hash over the BIT STRING
+ * from SubjectPublicKeyInfo as defined in RFC2459.
+ *
+ * Example of making a AuthorityKeyIdentifier:
+ * <pre>
+ * SubjectPublicKeyInfo apki = new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+ * publicKey.getEncoded()).readObject());
+ * AuthorityKeyIdentifier aki = new AuthorityKeyIdentifier(apki);
+ * </pre>
+ *
+ **/
+ public AuthorityKeyIdentifier(
+ 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);
+ this.keyidentifier = new DEROctetString(resBuf);
+ }
+
+ /**
+ * create an AuthorityKeyIdentifier with the GeneralNames tag and
+ * the serial number provided as well.
+ */
+ public AuthorityKeyIdentifier(
+ SubjectPublicKeyInfo spki,
+ GeneralNames name,
+ BigInteger serialNumber)
+ {
+ // 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);
+
+ this.keyidentifier = new DEROctetString(resBuf);
+ this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());
+ this.certserno = new ASN1Integer(serialNumber);
+ }
+
+ /**
+ * create an AuthorityKeyIdentifier with the GeneralNames tag and
+ * the serial number provided.
+ */
+ public AuthorityKeyIdentifier(
+ GeneralNames name,
+ BigInteger serialNumber)
+ {
+ this.keyidentifier = null;
+ this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());
+ this.certserno = new ASN1Integer(serialNumber);
+ }
+
+ /**
+ * create an AuthorityKeyIdentifier with a precomupted key identifier
+ */
+ public AuthorityKeyIdentifier(
+ byte[] keyIdentifier)
+ {
+ this.keyidentifier = new DEROctetString(keyIdentifier);
+ this.certissuer = null;
+ this.certserno = null;
+ }
+
+ /**
+ * create an AuthorityKeyIdentifier with a precomupted key identifier
+ * and the GeneralNames tag and the serial number provided as well.
+ */
+ public AuthorityKeyIdentifier(
+ byte[] keyIdentifier,
+ GeneralNames name,
+ BigInteger serialNumber)
+ {
+ this.keyidentifier = new DEROctetString(keyIdentifier);
+ this.certissuer = GeneralNames.getInstance(name.toASN1Primitive());
+ this.certserno = new ASN1Integer(serialNumber);
+ }
+
+ public byte[] getKeyIdentifier()
+ {
+ if (keyidentifier != null)
+ {
+ return keyidentifier.getOctets();
+ }
+
+ return null;
+ }
+
+ public GeneralNames getAuthorityCertIssuer()
+ {
+ return certissuer;
+ }
+
+ public BigInteger getAuthorityCertSerialNumber()
+ {
+ if (certserno != null)
+ {
+ return certserno.getValue();
+ }
+
+ return null;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (keyidentifier != null)
+ {
+ v.add(new DERTaggedObject(false, 0, keyidentifier));
+ }
+
+ if (certissuer != null)
+ {
+ v.add(new DERTaggedObject(false, 1, certissuer));
+ }
+
+ if (certserno != null)
+ {
+ v.add(new DERTaggedObject(false, 2, certserno));
+ }
+
+
+ return new DERSequence(v);
+ }
+
+ public String toString()
+ {
+ return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.getOctets() + ")");
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
new file mode 100644
index 0000000..19fa762
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
@@ -0,0 +1,164 @@
+package org.bouncycastle.asn1.x509;
+
+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.DERBoolean;
+import org.bouncycastle.asn1.DERSequence;
+
+public class BasicConstraints
+ extends ASN1Object
+{
+ // BEGIN android-changed
+ DERBoolean cA = DERBoolean.FALSE;
+ // END android-changed
+ ASN1Integer pathLenConstraint = null;
+
+ public static BasicConstraints getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static BasicConstraints getInstance(
+ Object obj)
+ {
+ if (obj instanceof BasicConstraints)
+ {
+ return (BasicConstraints)obj;
+ }
+ if (obj instanceof X509Extension)
+ {
+ return getInstance(X509Extension.convertValueToObject((X509Extension)obj));
+ }
+ if (obj != null)
+ {
+ return new BasicConstraints(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private BasicConstraints(
+ ASN1Sequence seq)
+ {
+ if (seq.size() == 0)
+ {
+ this.cA = null;
+ this.pathLenConstraint = null;
+ }
+ else
+ {
+ if (seq.getObjectAt(0) instanceof DERBoolean)
+ {
+ this.cA = DERBoolean.getInstance(seq.getObjectAt(0));
+ }
+ else
+ {
+ this.cA = null;
+ this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(0));
+ }
+ if (seq.size() > 1)
+ {
+ if (this.cA != null)
+ {
+ this.pathLenConstraint = ASN1Integer.getInstance(seq.getObjectAt(1));
+ }
+ else
+ {
+ throw new IllegalArgumentException("wrong sequence in constructor");
+ }
+ }
+ }
+ }
+
+ public BasicConstraints(
+ boolean cA)
+ {
+ if (cA)
+ {
+ // BEGIN android-changed
+ this.cA = DERBoolean.TRUE;
+ // END android-changed
+ }
+ else
+ {
+ this.cA = null;
+ }
+ this.pathLenConstraint = null;
+ }
+
+ /**
+ * create a cA=true object for the given path length constraint.
+ *
+ * @param pathLenConstraint
+ */
+ public BasicConstraints(
+ int pathLenConstraint)
+ {
+ // BEGIN android-changed
+ this.cA = DERBoolean.TRUE;
+ // END android-changed
+ this.pathLenConstraint = new ASN1Integer(pathLenConstraint);
+ }
+
+ public boolean isCA()
+ {
+ return (cA != null) && cA.isTrue();
+ }
+
+ public BigInteger getPathLenConstraint()
+ {
+ if (pathLenConstraint != null)
+ {
+ return pathLenConstraint.getValue();
+ }
+
+ return null;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * BasicConstraints := SEQUENCE {
+ * cA BOOLEAN DEFAULT FALSE,
+ * pathLenConstraint INTEGER (0..MAX) OPTIONAL
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (cA != null)
+ {
+ v.add(cA);
+ }
+
+ if (pathLenConstraint != null) // yes some people actually do this when cA is false...
+ {
+ v.add(pathLenConstraint);
+ }
+
+ return new DERSequence(v);
+ }
+
+ public String toString()
+ {
+ if (pathLenConstraint == null)
+ {
+ if (cA == null)
+ {
+ return "BasicConstraints: isCa(false)";
+ }
+ return "BasicConstraints: isCa(" + this.isCA() + ")";
+ }
+ return "BasicConstraints: isCa(" + this.isCA() + "), pathLenConstraint = " + pathLenConstraint.getValue();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
new file mode 100644
index 0000000..1ee6aa5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
@@ -0,0 +1,100 @@
+package org.bouncycastle.asn1.x509;
+
+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;
+
+public class CRLDistPoint
+ extends ASN1Object
+{
+ ASN1Sequence seq = null;
+
+ public static CRLDistPoint getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static CRLDistPoint getInstance(
+ Object obj)
+ {
+ if (obj instanceof CRLDistPoint)
+ {
+ return (CRLDistPoint)obj;
+ }
+ else if (obj != null)
+ {
+ return new CRLDistPoint(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private CRLDistPoint(
+ ASN1Sequence seq)
+ {
+ this.seq = seq;
+ }
+
+ public CRLDistPoint(
+ DistributionPoint[] points)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (int i = 0; i != points.length; i++)
+ {
+ v.add(points[i]);
+ }
+
+ seq = new DERSequence(v);
+ }
+
+ /**
+ * Return the distribution points making up the sequence.
+ *
+ * @return DistributionPoint[]
+ */
+ public DistributionPoint[] getDistributionPoints()
+ {
+ DistributionPoint[] dp = new DistributionPoint[seq.size()];
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ dp[i] = DistributionPoint.getInstance(seq.getObjectAt(i));
+ }
+
+ return dp;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * CRLDistPoint ::= SEQUENCE SIZE {1..MAX} OF DistributionPoint
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String sep = System.getProperty("line.separator");
+
+ buf.append("CRLDistPoint:");
+ buf.append(sep);
+ DistributionPoint dp[] = getDistributionPoints();
+ for (int i = 0; i != dp.length; i++)
+ {
+ buf.append(" ");
+ buf.append(dp[i]);
+ buf.append(sep);
+ }
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java
new file mode 100644
index 0000000..95425ba
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLNumber.java
@@ -0,0 +1,54 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+
+/**
+ * The CRLNumber object.
+ * <pre>
+ * CRLNumber::= INTEGER(0..MAX)
+ * </pre>
+ */
+public class CRLNumber
+ extends ASN1Object
+{
+ private BigInteger number;
+
+ public CRLNumber(
+ BigInteger number)
+ {
+ this.number = number;
+ }
+
+ public BigInteger getCRLNumber()
+ {
+ return number;
+ }
+
+ public String toString()
+ {
+ return "CRLNumber: " + getCRLNumber();
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return new ASN1Integer(number);
+ }
+
+ public static CRLNumber getInstance(Object o)
+ {
+ if (o instanceof CRLNumber)
+ {
+ return (CRLNumber)o;
+ }
+ else if (o != null)
+ {
+ return new CRLNumber(ASN1Integer.getInstance(o).getValue());
+ }
+
+ return null;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java
new file mode 100644
index 0000000..621b5c8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CRLReason.java
@@ -0,0 +1,152 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Enumerated;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+
+/**
+ * The CRLReason enumeration.
+ * <pre>
+ * CRLReason ::= ENUMERATED {
+ * unspecified (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6),
+ * removeFromCRL (8),
+ * privilegeWithdrawn (9),
+ * aACompromise (10)
+ * }
+ * </pre>
+ */
+public class CRLReason
+ extends ASN1Object
+{
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int UNSPECIFIED = 0;
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int KEY_COMPROMISE = 1;
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int CA_COMPROMISE = 2;
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int AFFILIATION_CHANGED = 3;
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int SUPERSEDED = 4;
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int CESSATION_OF_OPERATION = 5;
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int CERTIFICATE_HOLD = 6;
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int REMOVE_FROM_CRL = 8;
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int PRIVILEGE_WITHDRAWN = 9;
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int AA_COMPROMISE = 10;
+
+ public static final int unspecified = 0;
+ public static final int keyCompromise = 1;
+ public static final int cACompromise = 2;
+ public static final int affiliationChanged = 3;
+ public static final int superseded = 4;
+ public static final int cessationOfOperation = 5;
+ public static final int certificateHold = 6;
+ // 7 -> unknown
+ public static final int removeFromCRL = 8;
+ public static final int privilegeWithdrawn = 9;
+ public static final int aACompromise = 10;
+
+ private static final String[] reasonString =
+ {
+ "unspecified", "keyCompromise", "cACompromise", "affiliationChanged",
+ "superseded", "cessationOfOperation", "certificateHold", "unknown",
+ "removeFromCRL", "privilegeWithdrawn", "aACompromise"
+ };
+
+ private static final Hashtable table = new Hashtable();
+
+ private ASN1Enumerated value;
+
+ public static CRLReason getInstance(Object o)
+ {
+ if (o instanceof CRLReason)
+ {
+ return (CRLReason)o;
+ }
+ else if (o != null)
+ {
+ return lookup(ASN1Enumerated.getInstance(o).getValue().intValue());
+ }
+
+ return null;
+ }
+
+ private CRLReason(
+ int reason)
+ {
+ value = new ASN1Enumerated(reason);
+ }
+
+ public String toString()
+ {
+ String str;
+ int reason = getValue().intValue();
+ if (reason < 0 || reason > 10)
+ {
+ str = "invalid";
+ }
+ else
+ {
+ str = reasonString[reason];
+ }
+ return "CRLReason: " + str;
+ }
+
+ public BigInteger getValue()
+ {
+ return value.getValue();
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return value;
+ }
+
+ public static CRLReason lookup(int value)
+ {
+ // BEGIN android-changed
+ Integer idx = Integer.valueOf(value);
+ // END android-changed
+
+ if (!table.containsKey(idx))
+ {
+ table.put(idx, new CRLReason(value));
+ }
+
+ return (CRLReason)table.get(idx);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Certificate.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Certificate.java
new file mode 100644
index 0000000..4ca14d4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Certificate.java
@@ -0,0 +1,131 @@
+package org.bouncycastle.asn1.x509;
+
+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.x500.X500Name;
+
+/**
+ * an X509Certificate structure.
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * </pre>
+ */
+public class Certificate
+ extends ASN1Object
+{
+ ASN1Sequence seq;
+ TBSCertificate tbsCert;
+ AlgorithmIdentifier sigAlgId;
+ DERBitString sig;
+
+ public static Certificate getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static Certificate getInstance(
+ Object obj)
+ {
+ if (obj instanceof Certificate)
+ {
+ return (Certificate)obj;
+ }
+ else if (obj != null)
+ {
+ return new Certificate(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private Certificate(
+ ASN1Sequence seq)
+ {
+ this.seq = seq;
+
+ //
+ // correct x509 certficate
+ //
+ if (seq.size() == 3)
+ {
+ tbsCert = TBSCertificate.getInstance(seq.getObjectAt(0));
+ sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+
+ sig = DERBitString.getInstance(seq.getObjectAt(2));
+ }
+ else
+ {
+ throw new IllegalArgumentException("sequence wrong size for a certificate");
+ }
+ }
+
+ public TBSCertificate getTBSCertificate()
+ {
+ return tbsCert;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return tbsCert.getVersion();
+ }
+
+ public int getVersionNumber()
+ {
+ return tbsCert.getVersionNumber();
+ }
+
+ public ASN1Integer getSerialNumber()
+ {
+ return tbsCert.getSerialNumber();
+ }
+
+ public X500Name getIssuer()
+ {
+ return tbsCert.getIssuer();
+ }
+
+ public Time getStartDate()
+ {
+ return tbsCert.getStartDate();
+ }
+
+ public Time getEndDate()
+ {
+ return tbsCert.getEndDate();
+ }
+
+ public X500Name getSubject()
+ {
+ return tbsCert.getSubject();
+ }
+
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return tbsCert.getSubjectPublicKeyInfo();
+ }
+
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return sigAlgId;
+ }
+
+ public DERBitString getSignature()
+ {
+ return sig;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
new file mode 100644
index 0000000..91a37ad
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
@@ -0,0 +1,127 @@
+
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+
+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.x500.X500Name;
+
+/**
+ * PKIX RFC-2459
+ *
+ * The X.509 v2 CRL syntax is as follows. For signature calculation,
+ * the data that is to be signed is ASN.1 DER encoded.
+ *
+ * <pre>
+ * CertificateList ::= SEQUENCE {
+ * tbsCertList TBSCertList,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signatureValue BIT STRING }
+ * </pre>
+ */
+public class CertificateList
+ extends ASN1Object
+{
+ TBSCertList tbsCertList;
+ AlgorithmIdentifier sigAlgId;
+ DERBitString sig;
+
+ public static CertificateList getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static CertificateList getInstance(
+ Object obj)
+ {
+ if (obj instanceof CertificateList)
+ {
+ return (CertificateList)obj;
+ }
+ else if (obj != null)
+ {
+ return new CertificateList(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public CertificateList(
+ ASN1Sequence seq)
+ {
+ if (seq.size() == 3)
+ {
+ tbsCertList = TBSCertList.getInstance(seq.getObjectAt(0));
+ sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+ sig = DERBitString.getInstance(seq.getObjectAt(2));
+ }
+ else
+ {
+ throw new IllegalArgumentException("sequence wrong size for CertificateList");
+ }
+ }
+
+ public TBSCertList getTBSCertList()
+ {
+ return tbsCertList;
+ }
+
+ public TBSCertList.CRLEntry[] getRevokedCertificates()
+ {
+ return tbsCertList.getRevokedCertificates();
+ }
+
+ public Enumeration getRevokedCertificateEnumeration()
+ {
+ return tbsCertList.getRevokedCertificateEnumeration();
+ }
+
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return sigAlgId;
+ }
+
+ public DERBitString getSignature()
+ {
+ return sig;
+ }
+
+ public int getVersionNumber()
+ {
+ return tbsCertList.getVersionNumber();
+ }
+
+ public X500Name getIssuer()
+ {
+ return tbsCertList.getIssuer();
+ }
+
+ public Time getThisUpdate()
+ {
+ return tbsCertList.getThisUpdate();
+ }
+
+ public Time getNextUpdate()
+ {
+ return tbsCertList.getNextUpdate();
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCertList);
+ v.add(sigAlgId);
+ v.add(sig);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java
new file mode 100644
index 0000000..853bd35
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DSAParameter.java
@@ -0,0 +1,92 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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;
+
+public class DSAParameter
+ extends ASN1Object
+{
+ ASN1Integer p, q, g;
+
+ public static DSAParameter getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static DSAParameter getInstance(
+ Object obj)
+ {
+ if(obj == null || obj instanceof DSAParameter)
+ {
+ return (DSAParameter)obj;
+ }
+
+ if(obj instanceof ASN1Sequence)
+ {
+ return new DSAParameter((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid DSAParameter: " + obj.getClass().getName());
+ }
+
+ public DSAParameter(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g)
+ {
+ this.p = new ASN1Integer(p);
+ this.q = new ASN1Integer(q);
+ this.g = new ASN1Integer(g);
+ }
+
+ public DSAParameter(
+ ASN1Sequence seq)
+ {
+ if (seq.size() != 3)
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+ }
+
+ Enumeration e = seq.getObjects();
+
+ p = ASN1Integer.getInstance(e.nextElement());
+ q = ASN1Integer.getInstance(e.nextElement());
+ g = ASN1Integer.getInstance(e.nextElement());
+ }
+
+ public BigInteger getP()
+ {
+ return p.getPositiveValue();
+ }
+
+ public BigInteger getQ()
+ {
+ return q.getPositiveValue();
+ }
+
+ public BigInteger getG()
+ {
+ return g.getPositiveValue();
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(p);
+ v.add(q);
+ v.add(g);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java
new file mode 100644
index 0000000..fd17f1b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DigestInfo.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+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.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The DigestInfo object.
+ * <pre>
+ * DigestInfo::=SEQUENCE{
+ * digestAlgorithm AlgorithmIdentifier,
+ * digest OCTET STRING }
+ * </pre>
+ */
+public class DigestInfo
+ extends ASN1Object
+{
+ private byte[] digest;
+ private AlgorithmIdentifier algId;
+
+ public static DigestInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static DigestInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof DigestInfo)
+ {
+ return (DigestInfo)obj;
+ }
+ else if (obj != null)
+ {
+ return new DigestInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public DigestInfo(
+ AlgorithmIdentifier algId,
+ byte[] digest)
+ {
+ this.digest = digest;
+ this.algId = algId;
+ }
+
+ public DigestInfo(
+ ASN1Sequence obj)
+ {
+ Enumeration e = obj.getObjects();
+
+ algId = AlgorithmIdentifier.getInstance(e.nextElement());
+ digest = ASN1OctetString.getInstance(e.nextElement()).getOctets();
+ }
+
+ public AlgorithmIdentifier getAlgorithmId()
+ {
+ return algId;
+ }
+
+ public byte[] getDigest()
+ {
+ return digest;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(algId);
+ v.add(new DEROctetString(digest));
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
new file mode 100644
index 0000000..ab73dfb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
@@ -0,0 +1,158 @@
+package org.bouncycastle.asn1.x509;
+
+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;
+
+/**
+ * The DistributionPoint object.
+ * <pre>
+ * DistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * reasons [1] ReasonFlags OPTIONAL,
+ * cRLIssuer [2] GeneralNames OPTIONAL
+ * }
+ * </pre>
+ */
+public class DistributionPoint
+ extends ASN1Object
+{
+ DistributionPointName distributionPoint;
+ ReasonFlags reasons;
+ GeneralNames cRLIssuer;
+
+ public static DistributionPoint getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static DistributionPoint getInstance(
+ Object obj)
+ {
+ if(obj == null || obj instanceof DistributionPoint)
+ {
+ return (DistributionPoint)obj;
+ }
+
+ if(obj instanceof ASN1Sequence)
+ {
+ return new DistributionPoint((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid DistributionPoint: " + obj.getClass().getName());
+ }
+
+ public DistributionPoint(
+ ASN1Sequence seq)
+ {
+ for (int i = 0; i != seq.size(); i++)
+ {
+ ASN1TaggedObject t = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+ switch (t.getTagNo())
+ {
+ case 0:
+ distributionPoint = DistributionPointName.getInstance(t, true);
+ break;
+ case 1:
+ reasons = new ReasonFlags(DERBitString.getInstance(t, false));
+ break;
+ case 2:
+ cRLIssuer = GeneralNames.getInstance(t, false);
+ }
+ }
+ }
+
+ public DistributionPoint(
+ DistributionPointName distributionPoint,
+ ReasonFlags reasons,
+ GeneralNames cRLIssuer)
+ {
+ this.distributionPoint = distributionPoint;
+ this.reasons = reasons;
+ this.cRLIssuer = cRLIssuer;
+ }
+
+ public DistributionPointName getDistributionPoint()
+ {
+ return distributionPoint;
+ }
+
+ public ReasonFlags getReasons()
+ {
+ return reasons;
+ }
+
+ public GeneralNames getCRLIssuer()
+ {
+ return cRLIssuer;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (distributionPoint != null)
+ {
+ //
+ // as this is a CHOICE it must be explicitly tagged
+ //
+ v.add(new DERTaggedObject(0, distributionPoint));
+ }
+
+ if (reasons != null)
+ {
+ v.add(new DERTaggedObject(false, 1, reasons));
+ }
+
+ if (cRLIssuer != null)
+ {
+ v.add(new DERTaggedObject(false, 2, cRLIssuer));
+ }
+
+ return new DERSequence(v);
+ }
+
+ public String toString()
+ {
+ String sep = System.getProperty("line.separator");
+ StringBuffer buf = new StringBuffer();
+ buf.append("DistributionPoint: [");
+ buf.append(sep);
+ if (distributionPoint != null)
+ {
+ appendObject(buf, sep, "distributionPoint", distributionPoint.toString());
+ }
+ if (reasons != null)
+ {
+ appendObject(buf, sep, "reasons", reasons.toString());
+ }
+ if (cRLIssuer != null)
+ {
+ appendObject(buf, sep, "cRLIssuer", cRLIssuer.toString());
+ }
+ buf.append("]");
+ buf.append(sep);
+ return buf.toString();
+ }
+
+ private void appendObject(StringBuffer buf, String sep, String name, String value)
+ {
+ String indent = " ";
+
+ buf.append(indent);
+ buf.append(name);
+ buf.append(":");
+ buf.append(sep);
+ buf.append(indent);
+ buf.append(indent);
+ buf.append(value);
+ buf.append(sep);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
new file mode 100644
index 0000000..ee06efd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
@@ -0,0 +1,138 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * The DistributionPointName object.
+ * <pre>
+ * DistributionPointName ::= CHOICE {
+ * fullName [0] GeneralNames,
+ * nameRelativeToCRLIssuer [1] RDN
+ * }
+ * </pre>
+ */
+public class DistributionPointName
+ extends ASN1Object
+ implements ASN1Choice
+{
+ ASN1Encodable name;
+ int type;
+
+ public static final int FULL_NAME = 0;
+ public static final int NAME_RELATIVE_TO_CRL_ISSUER = 1;
+
+ public static DistributionPointName getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1TaggedObject.getInstance(obj, true));
+ }
+
+ public static DistributionPointName getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof DistributionPointName)
+ {
+ return (DistributionPointName)obj;
+ }
+ else if (obj instanceof ASN1TaggedObject)
+ {
+ return new DistributionPointName((ASN1TaggedObject)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ public DistributionPointName(
+ int type,
+ ASN1Encodable name)
+ {
+ this.type = type;
+ this.name = name;
+ }
+
+ public DistributionPointName(
+ GeneralNames name)
+ {
+ this(FULL_NAME, name);
+ }
+
+ /**
+ * Return the tag number applying to the underlying choice.
+ *
+ * @return the tag number for this point name.
+ */
+ public int getType()
+ {
+ return this.type;
+ }
+
+ /**
+ * Return the tagged object inside the distribution point name.
+ *
+ * @return the underlying choice item.
+ */
+ public ASN1Encodable getName()
+ {
+ return (ASN1Encodable)name;
+ }
+
+ public DistributionPointName(
+ ASN1TaggedObject obj)
+ {
+ this.type = obj.getTagNo();
+
+ if (type == 0)
+ {
+ this.name = GeneralNames.getInstance(obj, false);
+ }
+ else
+ {
+ this.name = ASN1Set.getInstance(obj, false);
+ }
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return new DERTaggedObject(false, type, name);
+ }
+
+ public String toString()
+ {
+ String sep = System.getProperty("line.separator");
+ StringBuffer buf = new StringBuffer();
+ buf.append("DistributionPointName: [");
+ buf.append(sep);
+ if (type == FULL_NAME)
+ {
+ appendObject(buf, sep, "fullName", name.toString());
+ }
+ else
+ {
+ appendObject(buf, sep, "nameRelativeToCRLIssuer", name.toString());
+ }
+ buf.append("]");
+ buf.append(sep);
+ return buf.toString();
+ }
+
+ private void appendObject(StringBuffer buf, String sep, String name, String value)
+ {
+ String indent = " ";
+
+ buf.append(indent);
+ buf.append(name);
+ buf.append(":");
+ buf.append(sep);
+ buf.append(indent);
+ buf.append(indent);
+ buf.append(value);
+ buf.append(sep);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
new file mode 100644
index 0000000..97f1c54
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
@@ -0,0 +1,123 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+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.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * The extendedKeyUsage object.
+ * <pre>
+ * extendedKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+ * </pre>
+ */
+public class ExtendedKeyUsage
+ extends ASN1Object
+{
+ Hashtable usageTable = new Hashtable();
+ ASN1Sequence seq;
+
+ public static ExtendedKeyUsage getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static ExtendedKeyUsage getInstance(
+ Object obj)
+ {
+ if (obj instanceof ExtendedKeyUsage)
+ {
+ return (ExtendedKeyUsage)obj;
+ }
+
+ if (obj != null)
+ {
+ return new ExtendedKeyUsage(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public ExtendedKeyUsage(
+ KeyPurposeId usage)
+ {
+ this.seq = new DERSequence(usage);
+
+ this.usageTable.put(usage, usage);
+ }
+
+ public ExtendedKeyUsage(
+ ASN1Sequence seq)
+ {
+ this.seq = seq;
+
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+ if (!(o instanceof ASN1ObjectIdentifier))
+ {
+ throw new IllegalArgumentException("Only ASN1ObjectIdentifiers allowed in ExtendedKeyUsage.");
+ }
+ this.usageTable.put(o, o);
+ }
+ }
+
+ public ExtendedKeyUsage(
+ Vector usages)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ Enumeration e = usages.elements();
+
+ while (e.hasMoreElements())
+ {
+ ASN1Primitive o = (ASN1Primitive)e.nextElement();
+
+ v.add(o);
+ this.usageTable.put(o, o);
+ }
+
+ this.seq = new DERSequence(v);
+ }
+
+ public boolean hasKeyPurposeId(
+ KeyPurposeId keyPurposeId)
+ {
+ return (usageTable.get(keyPurposeId) != null);
+ }
+
+ /**
+ * Returns all extended key usages.
+ * The returned vector contains ASN1ObjectIdentifiers.
+ * @return A vector with all key purposes.
+ */
+ public Vector getUsages()
+ {
+ Vector temp = new Vector();
+ for (Enumeration it = usageTable.elements(); it.hasMoreElements();)
+ {
+ temp.addElement(it.nextElement());
+ }
+ return temp;
+ }
+
+ public int size()
+ {
+ return usageTable.size();
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java
new file mode 100644
index 0000000..e6a06d8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extension.java
@@ -0,0 +1,266 @@
+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.DEROctetString;
+
+/**
+ * an object for the elements in the X.509 V3 extension block.
+ */
+public class Extension
+{
+ /**
+ * Subject Directory Attributes
+ */
+ public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9");
+
+ /**
+ * Subject Key Identifier
+ */
+ public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14");
+
+ /**
+ * Key Usage
+ */
+ public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15");
+
+ /**
+ * Private Key Usage Period
+ */
+ public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16");
+
+ /**
+ * Subject Alternative Name
+ */
+ public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17");
+
+ /**
+ * Issuer Alternative Name
+ */
+ public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18");
+
+ /**
+ * Basic Constraints
+ */
+ public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19");
+
+ /**
+ * CRL Number
+ */
+ public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20");
+
+ /**
+ * Reason code
+ */
+ public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21");
+
+ /**
+ * Hold Instruction Code
+ */
+ public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23");
+
+ /**
+ * Invalidity Date
+ */
+ public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24");
+
+ /**
+ * Delta CRL indicator
+ */
+ public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27");
+
+ /**
+ * Issuing Distribution Point
+ */
+ public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28");
+
+ /**
+ * Certificate Issuer
+ */
+ public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29");
+
+ /**
+ * Name Constraints
+ */
+ public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30");
+
+ /**
+ * CRL Distribution Points
+ */
+ public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31");
+
+ /**
+ * Certificate Policies
+ */
+ public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32");
+
+ /**
+ * Policy Mappings
+ */
+ public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33");
+
+ /**
+ * Authority Key Identifier
+ */
+ public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35");
+
+ /**
+ * Policy Constraints
+ */
+ public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36");
+
+ /**
+ * Extended Key Usage
+ */
+ public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37");
+
+ /**
+ * Freshest CRL
+ */
+ public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46");
+
+ /**
+ * Inhibit Any Policy
+ */
+ public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54");
+
+ /**
+ * Authority Info Access
+ */
+ public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+ /**
+ * Subject Info Access
+ */
+ public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11");
+
+ /**
+ * Logo Type
+ */
+ public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+ /**
+ * BiometricInfo
+ */
+ public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2");
+
+ /**
+ * QCStatements
+ */
+ public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+ /**
+ * Audit identity extension in attribute certificates.
+ */
+ public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4");
+
+ /**
+ * NoRevAvail extension in attribute certificates.
+ */
+ public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56");
+
+ /**
+ * TargetInformation extension in attribute certificates.
+ */
+ public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55");
+
+ private ASN1ObjectIdentifier extnId;
+
+ boolean critical;
+ ASN1OctetString value;
+
+ public Extension(
+ ASN1ObjectIdentifier extnId,
+ ASN1Boolean critical,
+ ASN1OctetString value)
+ {
+ this(extnId, critical.isTrue(), value);
+ }
+
+ public Extension(
+ ASN1ObjectIdentifier extnId,
+ boolean critical,
+ byte[] value)
+ {
+ this(extnId, critical, new DEROctetString(value));
+ }
+
+ public Extension(
+ ASN1ObjectIdentifier extnId,
+ boolean critical,
+ ASN1OctetString value)
+ {
+ this.extnId = extnId;
+ this.critical = critical;
+ this.value = value;
+ }
+
+ public ASN1ObjectIdentifier getExtnId()
+ {
+ return extnId;
+ }
+
+ public boolean isCritical()
+ {
+ return critical;
+ }
+
+ public ASN1OctetString getExtnValue()
+ {
+ return value;
+ }
+
+ public ASN1Encodable getParsedValue()
+ {
+ return convertValueToObject(this);
+ }
+
+ public int hashCode()
+ {
+ if (this.isCritical())
+ {
+ return this.getExtnValue().hashCode();
+ }
+
+ return ~this.getExtnValue().hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof Extension))
+ {
+ return false;
+ }
+
+ Extension other = (Extension)o;
+
+ return other.getExtnValue().equals(this.getExtnValue())
+ && (other.isCritical() == this.isCritical());
+ }
+
+ /**
+ * Convert the value of the passed in extension to an object
+ * @param ext the extension to parse
+ * @return the object the value string contains
+ * @exception IllegalArgumentException if conversion is not possible
+ */
+ private static ASN1Primitive convertValueToObject(
+ Extension ext)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ return ASN1Primitive.fromByteArray(ext.getExtnValue().getOctets());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't convert extension: " + e);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java
new file mode 100644
index 0000000..1b93305
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Extensions.java
@@ -0,0 +1,214 @@
+package org.bouncycastle.asn1.x509;
+
+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;
+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 Extensions
+ extends ASN1Object
+{
+ private Hashtable extensions = new Hashtable();
+ private Vector ordering = new Vector();
+
+ public static Extensions getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static Extensions getInstance(
+ Object obj)
+ {
+ if (obj instanceof Extensions)
+ {
+ return (Extensions)obj;
+ }
+ else if (obj != null)
+ {
+ return new Extensions(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * Constructor from ASN1Sequence.
+ *
+ * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
+ */
+ private Extensions(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence s = ASN1Sequence.getInstance(e.nextElement());
+
+ if (s.size() == 3)
+ {
+ extensions.put(s.getObjectAt(0), new Extension(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)), ASN1Boolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2))));
+ }
+ else if (s.size() == 2)
+ {
+ extensions.put(s.getObjectAt(0), new Extension(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)), false, ASN1OctetString.getInstance(s.getObjectAt(1))));
+ }
+ else
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + s.size());
+ }
+
+ ordering.addElement(s.getObjectAt(0));
+ }
+ }
+
+ /**
+ * Base Constructor
+ *
+ * @param extensions an array of extensions.
+ */
+ public Extensions(
+ Extension[] extensions)
+ {
+ for (int i = 0; i != extensions.length; i++)
+ {
+ Extension ext = extensions[i];
+
+ this.ordering.addElement(ext.getExtnId());
+ this.extensions.put(ext.getExtnId(), ext);
+ }
+ }
+
+ /**
+ * return an Enumeration of the extension field's object ids.
+ */
+ public Enumeration oids()
+ {
+ return ordering.elements();
+ }
+
+ /**
+ * return the extension represented by the object identifier
+ * passed in.
+ *
+ * @return the extension if it's present, null otherwise.
+ */
+ public Extension getExtension(
+ ASN1ObjectIdentifier oid)
+ {
+ return (Extension)extensions.get(oid);
+ }
+
+ /**
+ * <pre>
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Extension ::= SEQUENCE {
+ * extnId EXTENSION.&amp;id ({ExtensionSet}),
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ Enumeration e = ordering.elements();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = (Extension)extensions.get(oid);
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(oid);
+
+ if (ext.isCritical())
+ {
+ v.add(ASN1Boolean.getInstance(true));
+ }
+
+ v.add(ext.getExtnValue());
+
+ vec.add(new DERSequence(v));
+ }
+
+ return new DERSequence(vec);
+ }
+
+ public boolean equivalent(
+ Extensions other)
+ {
+ if (extensions.size() != other.extensions.size())
+ {
+ return false;
+ }
+
+ Enumeration e1 = extensions.keys();
+
+ while (e1.hasMoreElements())
+ {
+ Object key = e1.nextElement();
+
+ if (!extensions.get(key).equals(other.extensions.get(key)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public ASN1ObjectIdentifier[] getExtensionOIDs()
+ {
+ return toOidArray(ordering);
+ }
+
+ public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)
+ {
+ Vector oidVec = new Vector();
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ Object oid = ordering.elementAt(i);
+
+ if (((Extension)extensions.get(oid)).isCritical() == isCritical)
+ {
+ oidVec.addElement(oid);
+ }
+ }
+
+ return toOidArray(oidVec);
+ }
+
+ private ASN1ObjectIdentifier[] toOidArray(Vector oidVec)
+ {
+ ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()];
+
+ for (int i = 0; i != oids.length; i++)
+ {
+ oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i);
+ }
+ return oids;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java
new file mode 100644
index 0000000..270ef1c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ExtensionsGenerator.java
@@ -0,0 +1,94 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+
+/**
+ * Generator for X.509 extensions
+ */
+public class ExtensionsGenerator
+{
+ private Hashtable extensions = new Hashtable();
+ private Vector extOrdering = new Vector();
+
+ /**
+ * Reset the generator
+ */
+ public void reset()
+ {
+ extensions = new Hashtable();
+ extOrdering = new Vector();
+ }
+
+ /**
+ * Add an extension with the given oid and the passed in value to be included
+ * in the OCTET STRING associated with the extension.
+ *
+ * @param oid OID for the extension.
+ * @param critical true if critical, false otherwise.
+ * @param value the ASN.1 object to be included in the extension.
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ throws IOException
+ {
+ this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+
+ /**
+ * Add an extension with the given oid and the passed in byte array to be wrapped in the
+ * OCTET STRING associated with the extension.
+ *
+ * @param oid OID for the extension.
+ * @param critical true if critical, false otherwise.
+ * @param value the byte array to be wrapped.
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ if (extensions.containsKey(oid))
+ {
+ throw new IllegalArgumentException("extension " + oid + " already added");
+ }
+
+ extOrdering.addElement(oid);
+ extensions.put(oid, new Extension(oid, critical, new DEROctetString(value)));
+ }
+
+ /**
+ * Return true if there are no extension present in this generator.
+ *
+ * @return true if empty, false otherwise
+ */
+ public boolean isEmpty()
+ {
+ return extOrdering.isEmpty();
+ }
+
+ /**
+ * Generate an Extensions object based on the current state of the generator.
+ *
+ * @return an X09Extensions object.
+ */
+ public Extensions generate()
+ {
+ Extension[] exts = new Extension[extOrdering.size()];
+
+ for (int i = 0; i != extOrdering.size(); i++)
+ {
+ exts[i] = (Extension)extensions.get(extOrdering.elementAt(i));
+ }
+
+ return new Extensions(exts);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
new file mode 100644
index 0000000..1829ecd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
@@ -0,0 +1,439 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Encodable;
+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.DERIA5String;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.util.IPAddress;
+
+/**
+ * The GeneralName object.
+ * <pre>
+ * GeneralName ::= CHOICE {
+ * otherName [0] OtherName,
+ * rfc822Name [1] IA5String,
+ * dNSName [2] IA5String,
+ * x400Address [3] ORAddress,
+ * directoryName [4] Name,
+ * ediPartyName [5] EDIPartyName,
+ * uniformResourceIdentifier [6] IA5String,
+ * iPAddress [7] OCTET STRING,
+ * registeredID [8] OBJECT IDENTIFIER}
+ *
+ * OtherName ::= SEQUENCE {
+ * type-id OBJECT IDENTIFIER,
+ * value [0] EXPLICIT ANY DEFINED BY type-id }
+ *
+ * EDIPartyName ::= SEQUENCE {
+ * nameAssigner [0] DirectoryString OPTIONAL,
+ * partyName [1] DirectoryString }
+ *
+ * Name ::= CHOICE { RDNSequence }
+ * </pre>
+ */
+public class GeneralName
+ extends ASN1Object
+ implements ASN1Choice
+{
+ public static final int otherName = 0;
+ public static final int rfc822Name = 1;
+ public static final int dNSName = 2;
+ public static final int x400Address = 3;
+ public static final int directoryName = 4;
+ public static final int ediPartyName = 5;
+ public static final int uniformResourceIdentifier = 6;
+ public static final int iPAddress = 7;
+ public static final int registeredID = 8;
+
+ private ASN1Encodable obj;
+ private int tag;
+
+ /**
+ * @deprecated use X500Name constructor.
+ * @param dirName
+ */
+ public GeneralName(
+ X509Name dirName)
+ {
+ this.obj = X500Name.getInstance(dirName);
+ this.tag = 4;
+ }
+
+ public GeneralName(
+ X500Name dirName)
+ {
+ this.obj = dirName;
+ this.tag = 4;
+ }
+
+ /**
+ * When the subjectAltName extension contains an Internet mail address,
+ * the address MUST be included as an rfc822Name. The format of an
+ * rfc822Name is an "addr-spec" as defined in RFC 822 [RFC 822].
+ *
+ * When the subjectAltName extension contains a domain name service
+ * label, the domain name MUST be stored in the dNSName (an IA5String).
+ * The name MUST be in the "preferred name syntax," as specified by RFC
+ * 1034 [RFC 1034].
+ *
+ * When the subjectAltName extension contains a URI, the name MUST be
+ * stored in the uniformResourceIdentifier (an IA5String). The name MUST
+ * be a non-relative URL, and MUST follow the URL syntax and encoding
+ * rules specified in [RFC 1738]. The name must include both a scheme
+ * (e.g., "http" or "ftp") and a scheme-specific-part. The scheme-
+ * specific-part must include a fully qualified domain name or IP
+ * address as the host.
+ *
+ * When the subjectAltName extension contains a iPAddress, the address
+ * MUST be stored in the octet string in "network byte order," as
+ * specified in RFC 791 [RFC 791]. The least significant bit (LSB) of
+ * each octet is the LSB of the corresponding byte in the network
+ * address. For IP Version 4, as specified in RFC 791, the octet string
+ * MUST contain exactly four octets. For IP Version 6, as specified in
+ * RFC 1883, the octet string MUST contain exactly sixteen octets [RFC
+ * 1883].
+ */
+ public GeneralName(
+ int tag,
+ ASN1Encodable name)
+ {
+ this.obj = name;
+ this.tag = tag;
+ }
+
+ /**
+ * Create a GeneralName for the given tag from the passed in String.
+ * <p>
+ * This constructor can handle:
+ * <ul>
+ * <li>rfc822Name
+ * <li>iPAddress
+ * <li>directoryName
+ * <li>dNSName
+ * <li>uniformResourceIdentifier
+ * <li>registeredID
+ * </ul>
+ * For x400Address, otherName and ediPartyName there is no common string
+ * format defined.
+ * <p>
+ * Note: A directory name can be encoded in different ways into a byte
+ * representation. Be aware of this if the byte representation is used for
+ * comparing results.
+ *
+ * @param tag tag number
+ * @param name string representation of name
+ * @throws IllegalArgumentException if the string encoding is not correct or * not supported.
+ */
+ public GeneralName(
+ int tag,
+ String name)
+ {
+ this.tag = tag;
+
+ if (tag == rfc822Name || tag == dNSName || tag == uniformResourceIdentifier)
+ {
+ this.obj = new DERIA5String(name);
+ }
+ else if (tag == registeredID)
+ {
+ this.obj = new ASN1ObjectIdentifier(name);
+ }
+ else if (tag == directoryName)
+ {
+ this.obj = new X500Name(name);
+ }
+ else if (tag == iPAddress)
+ {
+ byte[] enc = toGeneralNameEncoding(name);
+ if (enc != null)
+ {
+ this.obj = new DEROctetString(enc);
+ }
+ else
+ {
+ throw new IllegalArgumentException("IP Address is invalid");
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("can't process String for tag: " + tag);
+ }
+ }
+
+ public static GeneralName getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof GeneralName)
+ {
+ return (GeneralName)obj;
+ }
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ ASN1TaggedObject tagObj = (ASN1TaggedObject)obj;
+ int tag = tagObj.getTagNo();
+
+ switch (tag)
+ {
+ case otherName:
+ return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false));
+ case rfc822Name:
+ return new GeneralName(tag, DERIA5String.getInstance(tagObj, false));
+ case dNSName:
+ return new GeneralName(tag, DERIA5String.getInstance(tagObj, false));
+ case x400Address:
+ throw new IllegalArgumentException("unknown tag: " + tag);
+ case directoryName:
+ return new GeneralName(tag, X500Name.getInstance(tagObj, true));
+ case ediPartyName:
+ return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false));
+ case uniformResourceIdentifier:
+ return new GeneralName(tag, DERIA5String.getInstance(tagObj, false));
+ case iPAddress:
+ return new GeneralName(tag, ASN1OctetString.getInstance(tagObj, false));
+ case registeredID:
+ return new GeneralName(tag, ASN1ObjectIdentifier.getInstance(tagObj, false));
+ }
+ }
+
+ if (obj instanceof byte[])
+ {
+ try
+ {
+ return getInstance(ASN1Primitive.fromByteArray((byte[])obj));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("unable to parse encoded general name");
+ }
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
+ }
+
+ public static GeneralName getInstance(
+ ASN1TaggedObject tagObj,
+ boolean explicit)
+ {
+ return GeneralName.getInstance(ASN1TaggedObject.getInstance(tagObj, true));
+ }
+
+ public int getTagNo()
+ {
+ return tag;
+ }
+
+ public ASN1Encodable getName()
+ {
+ return obj;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+
+ buf.append(tag);
+ buf.append(": ");
+ switch (tag)
+ {
+ case rfc822Name:
+ case dNSName:
+ case uniformResourceIdentifier:
+ buf.append(DERIA5String.getInstance(obj).getString());
+ break;
+ case directoryName:
+ buf.append(X500Name.getInstance(obj).toString());
+ break;
+ default:
+ buf.append(obj.toString());
+ }
+ return buf.toString();
+ }
+
+ private byte[] toGeneralNameEncoding(String ip)
+ {
+ if (IPAddress.isValidIPv6WithNetmask(ip) || IPAddress.isValidIPv6(ip))
+ {
+ int slashIndex = ip.indexOf('/');
+
+ if (slashIndex < 0)
+ {
+ byte[] addr = new byte[16];
+ int[] parsedIp = parseIPv6(ip);
+ copyInts(parsedIp, addr, 0);
+
+ return addr;
+ }
+ else
+ {
+ byte[] addr = new byte[32];
+ int[] parsedIp = parseIPv6(ip.substring(0, slashIndex));
+ copyInts(parsedIp, addr, 0);
+ String mask = ip.substring(slashIndex + 1);
+ if (mask.indexOf(':') > 0)
+ {
+ parsedIp = parseIPv6(mask);
+ }
+ else
+ {
+ parsedIp = parseMask(mask);
+ }
+ copyInts(parsedIp, addr, 16);
+
+ return addr;
+ }
+ }
+ else if (IPAddress.isValidIPv4WithNetmask(ip) || IPAddress.isValidIPv4(ip))
+ {
+ int slashIndex = ip.indexOf('/');
+
+ if (slashIndex < 0)
+ {
+ byte[] addr = new byte[4];
+
+ parseIPv4(ip, addr, 0);
+
+ return addr;
+ }
+ else
+ {
+ byte[] addr = new byte[8];
+
+ parseIPv4(ip.substring(0, slashIndex), addr, 0);
+
+ String mask = ip.substring(slashIndex + 1);
+ if (mask.indexOf('.') > 0)
+ {
+ parseIPv4(mask, addr, 4);
+ }
+ else
+ {
+ parseIPv4Mask(mask, addr, 4);
+ }
+
+ return addr;
+ }
+ }
+
+ return null;
+ }
+
+ private void parseIPv4Mask(String mask, byte[] addr, int offset)
+ {
+ int maskVal = Integer.parseInt(mask);
+
+ for (int i = 0; i != maskVal; i++)
+ {
+ addr[(i / 8) + offset] |= 1 << (7 - (i % 8));
+ }
+ }
+
+ private void parseIPv4(String ip, byte[] addr, int offset)
+ {
+ StringTokenizer sTok = new StringTokenizer(ip, "./");
+ int index = 0;
+
+ while (sTok.hasMoreTokens())
+ {
+ addr[offset + index++] = (byte)Integer.parseInt(sTok.nextToken());
+ }
+ }
+
+ private int[] parseMask(String mask)
+ {
+ int[] res = new int[8];
+ int maskVal = Integer.parseInt(mask);
+
+ for (int i = 0; i != maskVal; i++)
+ {
+ res[i / 16] |= 1 << (15 - (i % 16));
+ }
+ return res;
+ }
+
+ private void copyInts(int[] parsedIp, byte[] addr, int offSet)
+ {
+ for (int i = 0; i != parsedIp.length; i++)
+ {
+ addr[(i * 2) + offSet] = (byte)(parsedIp[i] >> 8);
+ addr[(i * 2 + 1) + offSet] = (byte)parsedIp[i];
+ }
+ }
+
+ private int[] parseIPv6(String ip)
+ {
+ StringTokenizer sTok = new StringTokenizer(ip, ":", true);
+ int index = 0;
+ int[] val = new int[8];
+
+ if (ip.charAt(0) == ':' && ip.charAt(1) == ':')
+ {
+ sTok.nextToken(); // skip the first one
+ }
+
+ int doubleColon = -1;
+
+ while (sTok.hasMoreTokens())
+ {
+ String e = sTok.nextToken();
+
+ if (e.equals(":"))
+ {
+ doubleColon = index;
+ val[index++] = 0;
+ }
+ else
+ {
+ if (e.indexOf('.') < 0)
+ {
+ val[index++] = Integer.parseInt(e, 16);
+ if (sTok.hasMoreTokens())
+ {
+ sTok.nextToken();
+ }
+ }
+ else
+ {
+ StringTokenizer eTok = new StringTokenizer(e, ".");
+
+ val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken());
+ val[index++] = (Integer.parseInt(eTok.nextToken()) << 8) | Integer.parseInt(eTok.nextToken());
+ }
+ }
+ }
+
+ if (index != val.length)
+ {
+ System.arraycopy(val, doubleColon, val, val.length - (index - doubleColon), index - doubleColon);
+ for (int i = doubleColon; i != val.length - (index - doubleColon); i++)
+ {
+ val[i] = 0;
+ }
+ }
+
+ return val;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ if (tag == directoryName) // directoryName is explicitly tagged as it is a CHOICE
+ {
+ return new DERTaggedObject(true, tag, obj);
+ }
+ else
+ {
+ return new DERTaggedObject(false, tag, obj);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
new file mode 100644
index 0000000..bd45407
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
@@ -0,0 +1,102 @@
+package org.bouncycastle.asn1.x509;
+
+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;
+
+public class GeneralNames
+ extends ASN1Object
+{
+ private final GeneralName[] names;
+
+ public static GeneralNames getInstance(
+ Object obj)
+ {
+ if (obj instanceof GeneralNames)
+ {
+ return (GeneralNames)obj;
+ }
+
+ if (obj != null)
+ {
+ return new GeneralNames(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public static GeneralNames getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Construct a GeneralNames object containing one GeneralName.
+ *
+ * @param name the name to be contained.
+ */
+ public GeneralNames(
+ GeneralName name)
+ {
+ this.names = new GeneralName[] { name };
+ }
+
+
+ public GeneralNames(
+ GeneralName[] names)
+ {
+ this.names = names;
+ }
+
+ private GeneralNames(
+ ASN1Sequence seq)
+ {
+ this.names = new GeneralName[seq.size()];
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ names[i] = GeneralName.getInstance(seq.getObjectAt(i));
+ }
+ }
+
+ public GeneralName[] getNames()
+ {
+ GeneralName[] tmp = new GeneralName[names.length];
+
+ System.arraycopy(names, 0, tmp, 0, names.length);
+
+ return tmp;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * GeneralNames ::= SEQUENCE SIZE {1..MAX} OF GeneralName
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return new DERSequence(names);
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String sep = System.getProperty("line.separator");
+
+ buf.append("GeneralNames:");
+ buf.append(sep);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ buf.append(" ");
+ buf.append(names[i]);
+ buf.append(sep);
+ }
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
new file mode 100644
index 0000000..bf72ce6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/GeneralSubtree.java
@@ -0,0 +1,218 @@
+package org.bouncycastle.asn1.x509;
+
+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.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * Class for containing a restriction object subtrees in NameConstraints. See
+ * RFC 3280.
+ *
+ * <pre>
+ *
+ * GeneralSubtree ::= SEQUENCE
+ * {
+ * base GeneralName,
+ * minimum [0] BaseDistance DEFAULT 0,
+ * maximum [1] BaseDistance OPTIONAL
+ * }
+ * </pre>
+ *
+ * @see org.bouncycastle.asn1.x509.NameConstraints
+ *
+ */
+public class GeneralSubtree
+ extends ASN1Object
+{
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+ private GeneralName base;
+
+ private ASN1Integer minimum;
+
+ private ASN1Integer maximum;
+
+ private GeneralSubtree(
+ ASN1Sequence seq)
+ {
+ base = GeneralName.getInstance(seq.getObjectAt(0));
+
+ switch (seq.size())
+ {
+ case 1:
+ break;
+ case 2:
+ ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(1));
+ switch (o.getTagNo())
+ {
+ case 0:
+ minimum = ASN1Integer.getInstance(o, false);
+ break;
+ case 1:
+ maximum = ASN1Integer.getInstance(o, false);
+ break;
+ default:
+ throw new IllegalArgumentException("Bad tag number: "
+ + o.getTagNo());
+ }
+ break;
+ case 3:
+ {
+ {
+ ASN1TaggedObject oMin = ASN1TaggedObject.getInstance(seq.getObjectAt(1));
+ if (oMin.getTagNo() != 0)
+ {
+ throw new IllegalArgumentException("Bad tag number for 'minimum': " + oMin.getTagNo());
+ }
+ minimum = ASN1Integer.getInstance(oMin, false);
+ }
+
+ {
+ ASN1TaggedObject oMax = ASN1TaggedObject.getInstance(seq.getObjectAt(2));
+ if (oMax.getTagNo() != 1)
+ {
+ throw new IllegalArgumentException("Bad tag number for 'maximum': " + oMax.getTagNo());
+ }
+ maximum = ASN1Integer.getInstance(oMax, false);
+ }
+
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * According RFC 3280, the minimum and maximum fields are not used with any
+ * name forms, thus minimum MUST be zero, and maximum MUST be absent.
+ * <p>
+ * If minimum is <code>null</code>, zero is assumed, if
+ * maximum is <code>null</code>, maximum is absent.
+ *
+ * @param base
+ * A restriction.
+ * @param minimum
+ * Minimum
+ *
+ * @param maximum
+ * Maximum
+ */
+ public GeneralSubtree(
+ GeneralName base,
+ BigInteger minimum,
+ BigInteger maximum)
+ {
+ this.base = base;
+ if (maximum != null)
+ {
+ this.maximum = new ASN1Integer(maximum);
+ }
+ if (minimum == null)
+ {
+ this.minimum = null;
+ }
+ else
+ {
+ this.minimum = new ASN1Integer(minimum);
+ }
+ }
+
+ public GeneralSubtree(GeneralName base)
+ {
+ this(base, null, null);
+ }
+
+ public static GeneralSubtree getInstance(
+ ASN1TaggedObject o,
+ boolean explicit)
+ {
+ return new GeneralSubtree(ASN1Sequence.getInstance(o, explicit));
+ }
+
+ public static GeneralSubtree getInstance(
+ Object obj)
+ {
+ if (obj == null)
+ {
+ return null;
+ }
+
+ if (obj instanceof GeneralSubtree)
+ {
+ return (GeneralSubtree) obj;
+ }
+
+ return new GeneralSubtree(ASN1Sequence.getInstance(obj));
+ }
+
+ public GeneralName getBase()
+ {
+ return base;
+ }
+
+ public BigInteger getMinimum()
+ {
+ if (minimum == null)
+ {
+ return ZERO;
+ }
+
+ return minimum.getValue();
+ }
+
+ public BigInteger getMaximum()
+ {
+ if (maximum == null)
+ {
+ return null;
+ }
+
+ return maximum.getValue();
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * Returns:
+ *
+ * <pre>
+ * GeneralSubtree ::= SEQUENCE
+ * {
+ * base GeneralName,
+ * minimum [0] BaseDistance DEFAULT 0,
+ * maximum [1] BaseDistance OPTIONAL
+ * }
+ * </pre>
+ *
+ * @return a ASN1Primitive
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(base);
+
+ if (minimum != null && !minimum.getValue().equals(ZERO))
+ {
+ v.add(new DERTaggedObject(false, 0, minimum));
+ }
+
+ if (maximum != null)
+ {
+ v.add(new DERTaggedObject(false, 1, maximum));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java
new file mode 100644
index 0000000..6ae6e35
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Holder.java
@@ -0,0 +1,245 @@
+package org.bouncycastle.asn1.x509;
+
+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;
+
+/**
+ * The Holder object.
+ * <p>
+ * For an v2 attribute certificate this is:
+ *
+ * <pre>
+ * Holder ::= SEQUENCE {
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * -- the issuer and serial number of
+ * -- the holder's Public Key Certificate
+ * entityName [1] GeneralNames OPTIONAL,
+ * -- the name of the claimant or role
+ * objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ * -- used to directly authenticate the holder,
+ * -- for example, an executable
+ * }
+ * </pre>
+ *
+ * <p>
+ * For an v1 attribute certificate this is:
+ *
+ * <pre>
+ * subject CHOICE {
+ * baseCertificateID [0] IssuerSerial,
+ * -- associated with a Public Key Certificate
+ * subjectName [1] GeneralNames },
+ * -- associated with a name
+ * </pre>
+ */
+public class Holder
+ extends ASN1Object
+{
+ public static final int V1_CERTIFICATE_HOLDER = 0;
+ public static final int V2_CERTIFICATE_HOLDER = 1;
+
+ IssuerSerial baseCertificateID;
+
+ GeneralNames entityName;
+
+ ObjectDigestInfo objectDigestInfo;
+
+ private int version = V2_CERTIFICATE_HOLDER;
+
+ public static Holder getInstance(Object obj)
+ {
+ if (obj instanceof Holder)
+ {
+ return (Holder)obj;
+ }
+ else if (obj instanceof ASN1TaggedObject)
+ {
+ return new Holder(ASN1TaggedObject.getInstance(obj));
+ }
+ else if (obj != null)
+ {
+ return new Holder(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * Constructor for a holder for an V1 attribute certificate.
+ *
+ * @param tagObj The ASN.1 tagged holder object.
+ */
+ private Holder(ASN1TaggedObject tagObj)
+ {
+ switch (tagObj.getTagNo())
+ {
+ case 0:
+ baseCertificateID = IssuerSerial.getInstance(tagObj, false);
+ break;
+ case 1:
+ entityName = GeneralNames.getInstance(tagObj, false);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown tag in Holder");
+ }
+ version = 0;
+ }
+
+ /**
+ * Constructor for a holder for an V2 attribute certificate.
+ *
+ * @param seq The ASN.1 sequence.
+ */
+ private Holder(ASN1Sequence seq)
+ {
+ if (seq.size() > 3)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(seq
+ .getObjectAt(i));
+
+ switch (tObj.getTagNo())
+ {
+ case 0:
+ baseCertificateID = IssuerSerial.getInstance(tObj, false);
+ break;
+ case 1:
+ entityName = GeneralNames.getInstance(tObj, false);
+ break;
+ case 2:
+ objectDigestInfo = ObjectDigestInfo.getInstance(tObj, false);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown tag in Holder");
+ }
+ }
+ version = 1;
+ }
+
+ public Holder(IssuerSerial baseCertificateID)
+ {
+ this(baseCertificateID, V2_CERTIFICATE_HOLDER);
+ }
+
+ /**
+ * Constructs a holder from a IssuerSerial for a V1 or V2 certificate.
+ * .
+ * @param baseCertificateID The IssuerSerial.
+ * @param version The version of the attribute certificate.
+ */
+ public Holder(IssuerSerial baseCertificateID, int version)
+ {
+ this.baseCertificateID = baseCertificateID;
+ this.version = version;
+ }
+
+ /**
+ * Returns 1 for V2 attribute certificates or 0 for V1 attribute
+ * certificates.
+ * @return The version of the attribute certificate.
+ */
+ public int getVersion()
+ {
+ return version;
+ }
+
+ /**
+ * Constructs a holder with an entityName for V2 attribute certificates.
+ *
+ * @param entityName The entity or subject name.
+ */
+ public Holder(GeneralNames entityName)
+ {
+ this(entityName, V2_CERTIFICATE_HOLDER);
+ }
+
+ /**
+ * Constructs a holder with an entityName for V2 attribute certificates or
+ * with a subjectName for V1 attribute certificates.
+ *
+ * @param entityName The entity or subject name.
+ * @param version The version of the attribute certificate.
+ */
+ public Holder(GeneralNames entityName, int version)
+ {
+ this.entityName = entityName;
+ this.version = version;
+ }
+
+ /**
+ * Constructs a holder from an object digest info.
+ *
+ * @param objectDigestInfo The object digest info object.
+ */
+ public Holder(ObjectDigestInfo objectDigestInfo)
+ {
+ this.objectDigestInfo = objectDigestInfo;
+ }
+
+ public IssuerSerial getBaseCertificateID()
+ {
+ return baseCertificateID;
+ }
+
+ /**
+ * Returns the entityName for an V2 attribute certificate or the subjectName
+ * for an V1 attribute certificate.
+ *
+ * @return The entityname or subjectname.
+ */
+ public GeneralNames getEntityName()
+ {
+ return entityName;
+ }
+
+ public ObjectDigestInfo getObjectDigestInfo()
+ {
+ return objectDigestInfo;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ if (version == 1)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (baseCertificateID != null)
+ {
+ v.add(new DERTaggedObject(false, 0, baseCertificateID));
+ }
+
+ if (entityName != null)
+ {
+ v.add(new DERTaggedObject(false, 1, entityName));
+ }
+
+ if (objectDigestInfo != null)
+ {
+ v.add(new DERTaggedObject(false, 2, objectDigestInfo));
+ }
+
+ return new DERSequence(v);
+ }
+ else
+ {
+ if (entityName != null)
+ {
+ return new DERTaggedObject(false, 1, entityName);
+ }
+ else
+ {
+ return new DERTaggedObject(false, 0, baseCertificateID);
+ }
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
new file mode 100644
index 0000000..d082a9d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuerSerial.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.asn1.x509;
+
+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;
+
+public class IssuerSerial
+ extends ASN1Object
+{
+ GeneralNames issuer;
+ ASN1Integer serial;
+ DERBitString issuerUID;
+
+ public static IssuerSerial getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof IssuerSerial)
+ {
+ return (IssuerSerial)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new IssuerSerial((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ public static IssuerSerial getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public IssuerSerial(
+ ASN1Sequence seq)
+ {
+ if (seq.size() != 2 && seq.size() != 3)
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+ }
+
+ issuer = GeneralNames.getInstance(seq.getObjectAt(0));
+ serial = ASN1Integer.getInstance(seq.getObjectAt(1));
+
+ if (seq.size() == 3)
+ {
+ issuerUID = DERBitString.getInstance(seq.getObjectAt(2));
+ }
+ }
+
+ public IssuerSerial(
+ GeneralNames issuer,
+ ASN1Integer serial)
+ {
+ this.issuer = issuer;
+ this.serial = serial;
+ }
+
+ public GeneralNames getIssuer()
+ {
+ return issuer;
+ }
+
+ public ASN1Integer getSerial()
+ {
+ return serial;
+ }
+
+ public DERBitString getIssuerUID()
+ {
+ return issuerUID;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * IssuerSerial ::= SEQUENCE {
+ * issuer GeneralNames,
+ * serial CertificateSerialNumber,
+ * issuerUID UniqueIdentifier OPTIONAL
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(issuer);
+ v.add(serial);
+
+ if (issuerUID != null)
+ {
+ v.add(issuerUID);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
new file mode 100644
index 0000000..e31471c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
@@ -0,0 +1,282 @@
+package org.bouncycastle.asn1.x509;
+
+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.DERBoolean;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+
+/**
+ * <pre>
+ * IssuingDistributionPoint ::= SEQUENCE {
+ * distributionPoint [0] DistributionPointName OPTIONAL,
+ * onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
+ * onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
+ * onlySomeReasons [3] ReasonFlags OPTIONAL,
+ * indirectCRL [4] BOOLEAN DEFAULT FALSE,
+ * onlyContainsAttributeCerts [5] BOOLEAN DEFAULT FALSE }
+ * </pre>
+ */
+public class IssuingDistributionPoint
+ extends ASN1Object
+{
+ private DistributionPointName distributionPoint;
+
+ private boolean onlyContainsUserCerts;
+
+ private boolean onlyContainsCACerts;
+
+ private ReasonFlags onlySomeReasons;
+
+ private boolean indirectCRL;
+
+ private boolean onlyContainsAttributeCerts;
+
+ private ASN1Sequence seq;
+
+ public static IssuingDistributionPoint getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static IssuingDistributionPoint getInstance(
+ Object obj)
+ {
+ if (obj instanceof IssuingDistributionPoint)
+ {
+ return (IssuingDistributionPoint)obj;
+ }
+ else if (obj != null)
+ {
+ return new IssuingDistributionPoint(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ /**
+ * Constructor from given details.
+ *
+ * @param distributionPoint
+ * May contain an URI as pointer to most current CRL.
+ * @param onlyContainsUserCerts Covers revocation information for end certificates.
+ * @param onlyContainsCACerts Covers revocation information for CA certificates.
+ *
+ * @param onlySomeReasons
+ * Which revocation reasons does this point cover.
+ * @param indirectCRL
+ * If <code>true</code> then the CRL contains revocation
+ * information about certificates ssued by other CAs.
+ * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
+ */
+ public IssuingDistributionPoint(
+ DistributionPointName distributionPoint,
+ boolean onlyContainsUserCerts,
+ boolean onlyContainsCACerts,
+ ReasonFlags onlySomeReasons,
+ boolean indirectCRL,
+ boolean onlyContainsAttributeCerts)
+ {
+ this.distributionPoint = distributionPoint;
+ this.indirectCRL = indirectCRL;
+ this.onlyContainsAttributeCerts = onlyContainsAttributeCerts;
+ this.onlyContainsCACerts = onlyContainsCACerts;
+ this.onlyContainsUserCerts = onlyContainsUserCerts;
+ this.onlySomeReasons = onlySomeReasons;
+
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ if (distributionPoint != null)
+ { // CHOICE item so explicitly tagged
+ vec.add(new DERTaggedObject(true, 0, distributionPoint));
+ }
+ if (onlyContainsUserCerts)
+ {
+ // BEGIN android-changed
+ vec.add(new DERTaggedObject(false, 1, DERBoolean.TRUE));
+ // END android-changed
+ }
+ if (onlyContainsCACerts)
+ {
+ // BEGIN android-changed
+ vec.add(new DERTaggedObject(false, 2, DERBoolean.TRUE));
+ // END android-changed
+ }
+ if (onlySomeReasons != null)
+ {
+ vec.add(new DERTaggedObject(false, 3, onlySomeReasons));
+ }
+ if (indirectCRL)
+ {
+ // BEGIN android-changed
+ vec.add(new DERTaggedObject(false, 4, DERBoolean.TRUE));
+ // END android-changed
+ }
+ if (onlyContainsAttributeCerts)
+ {
+ // BEGIN android-changed
+ vec.add(new DERTaggedObject(false, 5, DERBoolean.TRUE));
+ // END android-changed
+ }
+
+ seq = new DERSequence(vec);
+ }
+
+ /**
+ * Shorthand Constructor from given details.
+ *
+ * @param distributionPoint
+ * May contain an URI as pointer to most current CRL.
+ * @param indirectCRL
+ * If <code>true</code> then the CRL contains revocation
+ * information about certificates ssued by other CAs.
+ * @param onlyContainsAttributeCerts Covers revocation information for attribute certificates.
+ */
+ public IssuingDistributionPoint(
+ DistributionPointName distributionPoint,
+ boolean indirectCRL,
+ boolean onlyContainsAttributeCerts)
+ {
+ this(distributionPoint, false, false, null, indirectCRL, onlyContainsAttributeCerts);
+ }
+
+ /**
+ * Constructor from ASN1Sequence
+ */
+ private IssuingDistributionPoint(
+ ASN1Sequence seq)
+ {
+ this.seq = seq;
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+
+ switch (o.getTagNo())
+ {
+ case 0:
+ // CHOICE so explicit
+ distributionPoint = DistributionPointName.getInstance(o, true);
+ break;
+ case 1:
+ onlyContainsUserCerts = DERBoolean.getInstance(o, false).isTrue();
+ break;
+ case 2:
+ onlyContainsCACerts = DERBoolean.getInstance(o, false).isTrue();
+ break;
+ case 3:
+ onlySomeReasons = new ReasonFlags(ReasonFlags.getInstance(o, false));
+ break;
+ case 4:
+ indirectCRL = DERBoolean.getInstance(o, false).isTrue();
+ break;
+ case 5:
+ onlyContainsAttributeCerts = DERBoolean.getInstance(o, false).isTrue();
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "unknown tag in IssuingDistributionPoint");
+ }
+ }
+ }
+
+ public boolean onlyContainsUserCerts()
+ {
+ return onlyContainsUserCerts;
+ }
+
+ public boolean onlyContainsCACerts()
+ {
+ return onlyContainsCACerts;
+ }
+
+ public boolean isIndirectCRL()
+ {
+ return indirectCRL;
+ }
+
+ public boolean onlyContainsAttributeCerts()
+ {
+ return onlyContainsAttributeCerts;
+ }
+
+ /**
+ * @return Returns the distributionPoint.
+ */
+ public DistributionPointName getDistributionPoint()
+ {
+ return distributionPoint;
+ }
+
+ /**
+ * @return Returns the onlySomeReasons.
+ */
+ public ReasonFlags getOnlySomeReasons()
+ {
+ return onlySomeReasons;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+
+ public String toString()
+ {
+ String sep = System.getProperty("line.separator");
+ StringBuffer buf = new StringBuffer();
+
+ buf.append("IssuingDistributionPoint: [");
+ buf.append(sep);
+ if (distributionPoint != null)
+ {
+ appendObject(buf, sep, "distributionPoint", distributionPoint.toString());
+ }
+ if (onlyContainsUserCerts)
+ {
+ appendObject(buf, sep, "onlyContainsUserCerts", booleanToString(onlyContainsUserCerts));
+ }
+ if (onlyContainsCACerts)
+ {
+ appendObject(buf, sep, "onlyContainsCACerts", booleanToString(onlyContainsCACerts));
+ }
+ if (onlySomeReasons != null)
+ {
+ appendObject(buf, sep, "onlySomeReasons", onlySomeReasons.toString());
+ }
+ if (onlyContainsAttributeCerts)
+ {
+ appendObject(buf, sep, "onlyContainsAttributeCerts", booleanToString(onlyContainsAttributeCerts));
+ }
+ if (indirectCRL)
+ {
+ appendObject(buf, sep, "indirectCRL", booleanToString(indirectCRL));
+ }
+ buf.append("]");
+ buf.append(sep);
+ return buf.toString();
+ }
+
+ private void appendObject(StringBuffer buf, String sep, String name, String value)
+ {
+ String indent = " ";
+
+ buf.append(indent);
+ buf.append(name);
+ buf.append(":");
+ buf.append(sep);
+ buf.append(indent);
+ buf.append(indent);
+ buf.append(value);
+ buf.append(sep);
+ }
+
+ private String booleanToString(boolean value)
+ {
+ return value ? "true" : "false";
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
new file mode 100644
index 0000000..542a26b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyPurposeId.java
@@ -0,0 +1,119 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * The KeyPurposeId object.
+ * <pre>
+ * KeyPurposeId ::= OBJECT IDENTIFIER
+ *
+ * id-kp ::= OBJECT IDENTIFIER { iso(1) identified-organization(3)
+ * dod(6) internet(1) security(5) mechanisms(5) pkix(7) 3}
+ *
+ * </pre>
+ */
+public class KeyPurposeId
+ extends ASN1ObjectIdentifier
+{
+ private static final String id_kp = "1.3.6.1.5.5.7.3";
+
+ /**
+ * Create a KeyPurposeId from an OID string
+ *
+ * @param id OID String. E.g. "1.3.6.1.5.5.7.3.1"
+ */
+ public KeyPurposeId(
+ String id)
+ {
+ super(id);
+ }
+
+ /**
+ * { 2 5 29 37 0 }
+ */
+ public static final KeyPurposeId anyExtendedKeyUsage = new KeyPurposeId(X509Extensions.ExtendedKeyUsage.getId() + ".0");
+ /**
+ * { id-kp 1 }
+ */
+ public static final KeyPurposeId id_kp_serverAuth = new KeyPurposeId(id_kp + ".1");
+ /**
+ * { id-kp 2 }
+ */
+ public static final KeyPurposeId id_kp_clientAuth = new KeyPurposeId(id_kp + ".2");
+ /**
+ * { id-kp 3 }
+ */
+ public static final KeyPurposeId id_kp_codeSigning = new KeyPurposeId(id_kp + ".3");
+ /**
+ * { id-kp 4 }
+ */
+ public static final KeyPurposeId id_kp_emailProtection = new KeyPurposeId(id_kp + ".4");
+ /**
+ * Usage deprecated by RFC4945 - was { id-kp 5 }
+ */
+ public static final KeyPurposeId id_kp_ipsecEndSystem = new KeyPurposeId(id_kp + ".5");
+ /**
+ * Usage deprecated by RFC4945 - was { id-kp 6 }
+ */
+ public static final KeyPurposeId id_kp_ipsecTunnel = new KeyPurposeId(id_kp + ".6");
+ /**
+ * Usage deprecated by RFC4945 - was { idkp 7 }
+ */
+ public static final KeyPurposeId id_kp_ipsecUser = new KeyPurposeId(id_kp + ".7");
+ /**
+ * { id-kp 8 }
+ */
+ public static final KeyPurposeId id_kp_timeStamping = new KeyPurposeId(id_kp + ".8");
+ /**
+ * { id-kp 9 }
+ */
+ public static final KeyPurposeId id_kp_OCSPSigning = new KeyPurposeId(id_kp + ".9");
+ /**
+ * { id-kp 10 }
+ */
+ public static final KeyPurposeId id_kp_dvcs = new KeyPurposeId(id_kp + ".10");
+ /**
+ * { id-kp 11 }
+ */
+ public static final KeyPurposeId id_kp_sbgpCertAAServerAuth = new KeyPurposeId(id_kp + ".11");
+ /**
+ * { id-kp 12 }
+ */
+ public static final KeyPurposeId id_kp_scvp_responder = new KeyPurposeId(id_kp + ".12");
+ /**
+ * { id-kp 13 }
+ */
+ public static final KeyPurposeId id_kp_eapOverPPP = new KeyPurposeId(id_kp + ".13");
+ /**
+ * { id-kp 14 }
+ */
+ public static final KeyPurposeId id_kp_eapOverLAN = new KeyPurposeId(id_kp + ".14");
+ /**
+ * { id-kp 15 }
+ */
+ public static final KeyPurposeId id_kp_scvpServer = new KeyPurposeId(id_kp + ".15");
+ /**
+ * { id-kp 16 }
+ */
+ public static final KeyPurposeId id_kp_scvpClient = new KeyPurposeId(id_kp + ".16");
+ /**
+ * { id-kp 17 }
+ */
+ public static final KeyPurposeId id_kp_ipsecIKE = new KeyPurposeId(id_kp + ".17");
+ /**
+ * { id-kp 18 }
+ */
+ public static final KeyPurposeId id_kp_capwapAC = new KeyPurposeId(id_kp + ".18");
+ /**
+ * { id-kp 19 }
+ */
+ public static final KeyPurposeId id_kp_capwapWTP = new KeyPurposeId(id_kp + ".19");
+
+ //
+ // microsoft key purpose ids
+ //
+ /**
+ * { 1 3 6 1 4 1 311 20 2 2 }
+ */
+ public static final KeyPurposeId id_kp_smartcardlogon = new KeyPurposeId("1.3.6.1.4.1.311.20.2.2");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java
new file mode 100644
index 0000000..3ffd94b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/KeyUsage.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERBitString;
+
+/**
+ * The KeyUsage object.
+ * <pre>
+ * id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
+ *
+ * KeyUsage ::= BIT STRING {
+ * digitalSignature (0),
+ * nonRepudiation (1),
+ * keyEncipherment (2),
+ * dataEncipherment (3),
+ * keyAgreement (4),
+ * keyCertSign (5),
+ * cRLSign (6),
+ * encipherOnly (7),
+ * decipherOnly (8) }
+ * </pre>
+ */
+public class KeyUsage
+ extends DERBitString
+{
+ public static final int digitalSignature = (1 << 7);
+ public static final int nonRepudiation = (1 << 6);
+ public static final int keyEncipherment = (1 << 5);
+ public static final int dataEncipherment = (1 << 4);
+ public static final int keyAgreement = (1 << 3);
+ public static final int keyCertSign = (1 << 2);
+ public static final int cRLSign = (1 << 1);
+ public static final int encipherOnly = (1 << 0);
+ public static final int decipherOnly = (1 << 15);
+
+ public static DERBitString getInstance(Object obj) // needs to be DERBitString for other VMs
+ {
+ if (obj instanceof KeyUsage)
+ {
+ return (KeyUsage)obj;
+ }
+
+ if (obj instanceof X509Extension)
+ {
+ return new KeyUsage(DERBitString.getInstance(X509Extension.convertValueToObject((X509Extension)obj)));
+ }
+
+ return new KeyUsage(DERBitString.getInstance(obj));
+ }
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (KeyUsage.keyEncipherment | KeyUsage.dataEncipherment)
+ */
+ public KeyUsage(
+ int usage)
+ {
+ super(getBytes(usage), getPadBits(usage));
+ }
+
+ public KeyUsage(
+ DERBitString usage)
+ {
+ super(usage.getBytes(), usage.getPadBits());
+ }
+
+ public String toString()
+ {
+ if (data.length == 1)
+ {
+ return "KeyUsage: 0x" + Integer.toHexString(data[0] & 0xff);
+ }
+ return "KeyUsage: 0x" + Integer.toHexString((data[1] & 0xff) << 8 | (data[0] & 0xff));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
new file mode 100644
index 0000000..02096f2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/NameConstraints.java
@@ -0,0 +1,118 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+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 NameConstraints
+ extends ASN1Object
+{
+ private ASN1Sequence permitted, excluded;
+
+ public static NameConstraints getInstance(Object obj)
+ {
+ if (obj instanceof NameConstraints)
+ {
+ return (NameConstraints)obj;
+ }
+ if (obj != null)
+ {
+ return new NameConstraints(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private NameConstraints(ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+ while (e.hasMoreElements())
+ {
+ ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement());
+ switch (o.getTagNo())
+ {
+ case 0:
+ permitted = ASN1Sequence.getInstance(o, false);
+ break;
+ case 1:
+ excluded = ASN1Sequence.getInstance(o, false);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Constructor from a given details.
+ *
+ * <p>
+ * permitted and excluded are Vectors of GeneralSubtree objects.
+ *
+ * @param permitted
+ * Permitted subtrees
+ * @param excluded
+ * Excludes subtrees
+ */
+ public NameConstraints(
+ Vector permitted,
+ Vector excluded)
+ {
+ if (permitted != null)
+ {
+ this.permitted = createSequence(permitted);
+ }
+ if (excluded != null)
+ {
+ this.excluded = createSequence(excluded);
+ }
+ }
+
+ private DERSequence createSequence(Vector subtree)
+ {
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ Enumeration e = subtree.elements();
+ while (e.hasMoreElements())
+ {
+ vec.add((GeneralSubtree)e.nextElement());
+ }
+
+ return new DERSequence(vec);
+ }
+
+ public ASN1Sequence getPermittedSubtrees()
+ {
+ return permitted;
+ }
+
+ public ASN1Sequence getExcludedSubtrees()
+ {
+ return excluded;
+ }
+
+ /*
+ * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
+ * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (permitted != null)
+ {
+ v.add(new DERTaggedObject(false, 0, permitted));
+ }
+
+ if (excluded != null)
+ {
+ v.add(new DERTaggedObject(false, 1, excluded));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java
new file mode 100644
index 0000000..7a2d77e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ObjectDigestInfo.java
@@ -0,0 +1,191 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Enumerated;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DEREnumerated;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * ObjectDigestInfo ASN.1 structure used in v2 attribute certificates.
+ *
+ * <pre>
+ *
+ * ObjectDigestInfo ::= SEQUENCE {
+ * digestedObjectType ENUMERATED {
+ * publicKey (0),
+ * publicKeyCert (1),
+ * otherObjectTypes (2) },
+ * -- otherObjectTypes MUST NOT
+ * -- be used in this profile
+ * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
+ * digestAlgorithm AlgorithmIdentifier,
+ * objectDigest BIT STRING
+ * }
+ *
+ * </pre>
+ *
+ */
+public class ObjectDigestInfo
+ extends ASN1Object
+{
+ /**
+ * The public key is hashed.
+ */
+ public final static int publicKey = 0;
+
+ /**
+ * The public key certificate is hashed.
+ */
+ public final static int publicKeyCert = 1;
+
+ /**
+ * An other object is hashed.
+ */
+ public final static int otherObjectDigest = 2;
+
+ ASN1Enumerated digestedObjectType;
+
+ ASN1ObjectIdentifier otherObjectTypeID;
+
+ AlgorithmIdentifier digestAlgorithm;
+
+ DERBitString objectDigest;
+
+ public static ObjectDigestInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof ObjectDigestInfo)
+ {
+ return (ObjectDigestInfo)obj;
+ }
+
+ if (obj != null)
+ {
+ return new ObjectDigestInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public static ObjectDigestInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ /**
+ * Constructor from given details.
+ * <p>
+ * If <code>digestedObjectType</code> is not {@link #publicKeyCert} or
+ * {@link #publicKey} <code>otherObjectTypeID</code> must be given,
+ * otherwise it is ignored.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param otherObjectTypeID The object type ID for
+ * <code>otherObjectDigest</code>.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param objectDigest The hash value.
+ */
+ public ObjectDigestInfo(
+ int digestedObjectType,
+ ASN1ObjectIdentifier otherObjectTypeID,
+ AlgorithmIdentifier digestAlgorithm,
+ byte[] objectDigest)
+ {
+ this.digestedObjectType = new ASN1Enumerated(digestedObjectType);
+ if (digestedObjectType == otherObjectDigest)
+ {
+ this.otherObjectTypeID = otherObjectTypeID;
+ }
+
+ this.digestAlgorithm = digestAlgorithm;
+ this.objectDigest = new DERBitString(objectDigest);
+ }
+
+ private ObjectDigestInfo(
+ ASN1Sequence seq)
+ {
+ if (seq.size() > 4 || seq.size() < 3)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ digestedObjectType = DEREnumerated.getInstance(seq.getObjectAt(0));
+
+ int offset = 0;
+
+ if (seq.size() == 4)
+ {
+ otherObjectTypeID = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1));
+ offset++;
+ }
+
+ digestAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1 + offset));
+
+ objectDigest = DERBitString.getInstance(seq.getObjectAt(2 + offset));
+ }
+
+ public DEREnumerated getDigestedObjectType()
+ {
+ return digestedObjectType;
+ }
+
+ public ASN1ObjectIdentifier getOtherObjectTypeID()
+ {
+ return otherObjectTypeID;
+ }
+
+ public AlgorithmIdentifier getDigestAlgorithm()
+ {
+ return digestAlgorithm;
+ }
+
+ public DERBitString getObjectDigest()
+ {
+ return objectDigest;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * <pre>
+ *
+ * ObjectDigestInfo ::= SEQUENCE {
+ * digestedObjectType ENUMERATED {
+ * publicKey (0),
+ * publicKeyCert (1),
+ * otherObjectTypes (2) },
+ * -- otherObjectTypes MUST NOT
+ * -- be used in this profile
+ * otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
+ * digestAlgorithm AlgorithmIdentifier,
+ * objectDigest BIT STRING
+ * }
+ *
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(digestedObjectType);
+
+ if (otherObjectTypeID != null)
+ {
+ v.add(otherObjectTypeID);
+ }
+
+ v.add(digestAlgorithm);
+ v.add(objectDigest);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
new file mode 100644
index 0000000..d1de26f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
@@ -0,0 +1,87 @@
+package org.bouncycastle.asn1.x509;
+
+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.DERSequence;
+
+public class PolicyInformation
+ extends ASN1Object
+{
+ private ASN1ObjectIdentifier policyIdentifier;
+ private ASN1Sequence policyQualifiers;
+
+ private PolicyInformation(
+ ASN1Sequence seq)
+ {
+ if (seq.size() < 1 || seq.size() > 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ policyIdentifier = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+
+ if (seq.size() > 1)
+ {
+ policyQualifiers = ASN1Sequence.getInstance(seq.getObjectAt(1));
+ }
+ }
+
+ public PolicyInformation(
+ ASN1ObjectIdentifier policyIdentifier)
+ {
+ this.policyIdentifier = policyIdentifier;
+ }
+
+ public PolicyInformation(
+ ASN1ObjectIdentifier policyIdentifier,
+ ASN1Sequence policyQualifiers)
+ {
+ this.policyIdentifier = policyIdentifier;
+ this.policyQualifiers = policyQualifiers;
+ }
+
+ public static PolicyInformation getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof PolicyInformation)
+ {
+ return (PolicyInformation)obj;
+ }
+
+ return new PolicyInformation(ASN1Sequence.getInstance(obj));
+ }
+
+ public ASN1ObjectIdentifier getPolicyIdentifier()
+ {
+ return policyIdentifier;
+ }
+
+ public ASN1Sequence getPolicyQualifiers()
+ {
+ return policyQualifiers;
+ }
+
+ /*
+ * PolicyInformation ::= SEQUENCE {
+ * policyIdentifier CertPolicyId,
+ * policyQualifiers SEQUENCE SIZE (1..MAX) OF
+ * PolicyQualifierInfo OPTIONAL }
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(policyIdentifier);
+
+ if (policyQualifiers != null)
+ {
+ v.add(policyQualifiers);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
new file mode 100644
index 0000000..91c8725
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java
@@ -0,0 +1,98 @@
+package org.bouncycastle.asn1.x509;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+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;
+
+/**
+ * @deprecated use org.bouncycastle.asn1.pkcs.RSAPublicKey
+ */
+public class RSAPublicKeyStructure
+ extends ASN1Object
+{
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+
+ public static RSAPublicKeyStructure getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static RSAPublicKeyStructure getInstance(
+ Object obj)
+ {
+ if(obj == null || obj instanceof RSAPublicKeyStructure)
+ {
+ return (RSAPublicKeyStructure)obj;
+ }
+
+ if(obj instanceof ASN1Sequence)
+ {
+ return new RSAPublicKeyStructure((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid RSAPublicKeyStructure: " + obj.getClass().getName());
+ }
+
+ public RSAPublicKeyStructure(
+ BigInteger modulus,
+ BigInteger publicExponent)
+ {
+ this.modulus = modulus;
+ this.publicExponent = publicExponent;
+ }
+
+ public RSAPublicKeyStructure(
+ ASN1Sequence seq)
+ {
+ if (seq.size() != 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ Enumeration e = seq.getObjects();
+
+ modulus = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+ publicExponent = ASN1Integer.getInstance(e.nextElement()).getPositiveValue();
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ /**
+ * This outputs the key in PKCS1v2 format.
+ * <pre>
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * }
+ * </pre>
+ * <p>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(getModulus()));
+ v.add(new ASN1Integer(getPublicExponent()));
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java
new file mode 100644
index 0000000..612e2c5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/ReasonFlags.java
@@ -0,0 +1,85 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.DERBitString;
+
+/**
+ * The ReasonFlags object.
+ * <pre>
+ * ReasonFlags ::= BIT STRING {
+ * unused (0),
+ * keyCompromise (1),
+ * cACompromise (2),
+ * affiliationChanged (3),
+ * superseded (4),
+ * cessationOfOperation (5),
+ * certificateHold (6),
+ * privilegeWithdrawn (7),
+ * aACompromise (8) }
+ * </pre>
+ */
+public class ReasonFlags
+ extends DERBitString
+{
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int UNUSED = (1 << 7);
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int KEY_COMPROMISE = (1 << 6);
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int CA_COMPROMISE = (1 << 5);
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int AFFILIATION_CHANGED = (1 << 4);
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int SUPERSEDED = (1 << 3);
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int CESSATION_OF_OPERATION = (1 << 2);
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int CERTIFICATE_HOLD = (1 << 1);
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int PRIVILEGE_WITHDRAWN = (1 << 0);
+ /**
+ * @deprecated use lower case version
+ */
+ public static final int AA_COMPROMISE = (1 << 15);
+
+ public static final int unused = (1 << 7);
+ public static final int keyCompromise = (1 << 6);
+ public static final int cACompromise = (1 << 5);
+ public static final int affiliationChanged = (1 << 4);
+ public static final int superseded = (1 << 3);
+ public static final int cessationOfOperation = (1 << 2);
+ public static final int certificateHold = (1 << 1);
+ public static final int privilegeWithdrawn = (1 << 0);
+ public static final int aACompromise = (1 << 15);
+
+ /**
+ * @param reasons - the bitwise OR of the Key Reason flags giving the
+ * allowed uses for the key.
+ */
+ public ReasonFlags(
+ int reasons)
+ {
+ super(getBytes(reasons), getPadBits(reasons));
+ }
+
+ public ReasonFlags(
+ DERBitString reasons)
+ {
+ super(reasons.getBytes(), reasons.getPadBits());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
new file mode 100644
index 0000000..e56d89f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectKeyIdentifier.java
@@ -0,0 +1,134 @@
+package org.bouncycastle.asn1.x509;
+
+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.crypto.Digest;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-changed
+
+/**
+ * The SubjectKeyIdentifier object.
+ * <pre>
+ * SubjectKeyIdentifier::= OCTET STRING
+ * </pre>
+ */
+public class SubjectKeyIdentifier
+ extends ASN1Object
+{
+ private byte[] keyidentifier;
+
+ public static SubjectKeyIdentifier getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1OctetString.getInstance(obj, explicit));
+ }
+
+ public static SubjectKeyIdentifier getInstance(
+ Object obj)
+ {
+ if (obj instanceof SubjectKeyIdentifier)
+ {
+ return (SubjectKeyIdentifier)obj;
+ }
+ else if (obj != null)
+ {
+ return new SubjectKeyIdentifier(ASN1OctetString.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public SubjectKeyIdentifier(
+ byte[] keyid)
+ {
+ this.keyidentifier = keyid;
+ }
+
+ protected SubjectKeyIdentifier(
+ ASN1OctetString keyid)
+ {
+ this.keyidentifier = keyid.getOctets();
+ }
+
+ public byte[] getKeyIdentifier()
+ {
+ return keyidentifier;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ 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:
+ * <pre>
+ * (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).
+ * </pre>
+ * @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:
+ * <pre>
+ * (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.
+ * </pre>
+ * @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/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
new file mode 100644
index 0000000..660ca05
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java
@@ -0,0 +1,155 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+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;
+
+/**
+ * The object that contains the public key stored in a certficate.
+ * <p>
+ * The getEncoded() method in the public keys in the JCE produces a DER
+ * encoded one of these.
+ */
+public class SubjectPublicKeyInfo
+ extends ASN1Object
+{
+ private AlgorithmIdentifier algId;
+ private DERBitString keyData;
+
+ public static SubjectPublicKeyInfo getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static SubjectPublicKeyInfo getInstance(
+ Object obj)
+ {
+ if (obj instanceof SubjectPublicKeyInfo)
+ {
+ return (SubjectPublicKeyInfo)obj;
+ }
+ else if (obj != null)
+ {
+ return new SubjectPublicKeyInfo(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public SubjectPublicKeyInfo(
+ AlgorithmIdentifier algId,
+ ASN1Encodable publicKey)
+ {
+ this.keyData = new DERBitString(publicKey);
+ this.algId = algId;
+ }
+
+ public SubjectPublicKeyInfo(
+ AlgorithmIdentifier algId,
+ byte[] publicKey)
+ {
+ this.keyData = new DERBitString(publicKey);
+ this.algId = algId;
+ }
+
+ public SubjectPublicKeyInfo(
+ ASN1Sequence seq)
+ {
+ if (seq.size() != 2)
+ {
+ throw new IllegalArgumentException("Bad sequence size: "
+ + seq.size());
+ }
+
+ Enumeration e = seq.getObjects();
+
+ this.algId = AlgorithmIdentifier.getInstance(e.nextElement());
+ this.keyData = DERBitString.getInstance(e.nextElement());
+ }
+
+ public AlgorithmIdentifier getAlgorithm()
+ {
+ return algId;
+ }
+
+ /**
+ * @deprecated use getAlgorithm()
+ * @return alg ID.
+ */
+ public AlgorithmIdentifier getAlgorithmId()
+ {
+ return algId;
+ }
+
+ /**
+ * for when the public key is an encoded object - if the bitstring
+ * can't be decoded this routine throws an IOException.
+ *
+ * @exception IOException - if the bit string doesn't represent a DER
+ * encoded object.
+ * @return the public key as an ASN.1 primitive.
+ */
+ public ASN1Primitive parsePublicKey()
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes());
+
+ return aIn.readObject();
+ }
+
+ /**
+ * for when the public key is an encoded object - if the bitstring
+ * can't be decoded this routine throws an IOException.
+ *
+ * @exception IOException - if the bit string doesn't represent a DER
+ * encoded object.
+ * @deprecated use parsePublicKey
+ * @return the public key as an ASN.1 primitive.
+ */
+ public ASN1Primitive getPublicKey()
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(keyData.getBytes());
+
+ return aIn.readObject();
+ }
+
+ /**
+ * for when the public key is raw bits.
+ *
+ * @return the public key as the raw bit string...
+ */
+ public DERBitString getPublicKeyData()
+ {
+ return keyData;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * publicKey BIT STRING }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(algId);
+ v.add(keyData);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
new file mode 100644
index 0000000..ce657a7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertList.java
@@ -0,0 +1,309 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+
+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.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DERUTCTime;
+import org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * PKIX RFC-2459 - TBSCertList object.
+ * <pre>
+ * TBSCertList ::= SEQUENCE {
+ * version Version OPTIONAL,
+ * -- if present, shall be v2
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * thisUpdate Time,
+ * nextUpdate Time OPTIONAL,
+ * revokedCertificates SEQUENCE OF SEQUENCE {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate Time,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, shall be v2
+ * } OPTIONAL,
+ * crlExtensions [0] EXPLICIT Extensions OPTIONAL
+ * -- if present, shall be v2
+ * }
+ * </pre>
+ */
+public class TBSCertList
+ extends ASN1Object
+{
+ public static class CRLEntry
+ extends ASN1Object
+ {
+ ASN1Sequence seq;
+
+ Extensions crlEntryExtensions;
+
+ private CRLEntry(
+ ASN1Sequence seq)
+ {
+ if (seq.size() < 2 || seq.size() > 3)
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+ }
+
+ this.seq = seq;
+ }
+
+ public static CRLEntry getInstance(Object o)
+ {
+ if (o instanceof CRLEntry)
+ {
+ return ((CRLEntry)o);
+ }
+ else if (o != null)
+ {
+ return new CRLEntry(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public ASN1Integer getUserCertificate()
+ {
+ return ASN1Integer.getInstance(seq.getObjectAt(0));
+ }
+
+ public Time getRevocationDate()
+ {
+ return Time.getInstance(seq.getObjectAt(1));
+ }
+
+ public Extensions getExtensions()
+ {
+ if (crlEntryExtensions == null && seq.size() == 3)
+ {
+ crlEntryExtensions = Extensions.getInstance(seq.getObjectAt(2));
+ }
+
+ return crlEntryExtensions;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+
+ public boolean hasExtensions()
+ {
+ return seq.size() == 3;
+ }
+ }
+
+ private class RevokedCertificatesEnumeration
+ implements Enumeration
+ {
+ private final Enumeration en;
+
+ RevokedCertificatesEnumeration(Enumeration en)
+ {
+ this.en = en;
+ }
+
+ public boolean hasMoreElements()
+ {
+ return en.hasMoreElements();
+ }
+
+ public Object nextElement()
+ {
+ return CRLEntry.getInstance(en.nextElement());
+ }
+ }
+
+ private class EmptyEnumeration
+ implements Enumeration
+ {
+ public boolean hasMoreElements()
+ {
+ return false;
+ }
+
+ public Object nextElement()
+ {
+ return null; // TODO: check exception handling
+ }
+ }
+
+ ASN1Integer version;
+ AlgorithmIdentifier signature;
+ X500Name issuer;
+ Time thisUpdate;
+ Time nextUpdate;
+ ASN1Sequence revokedCertificates;
+ Extensions crlExtensions;
+
+ public static TBSCertList getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static TBSCertList getInstance(
+ Object obj)
+ {
+ if (obj instanceof TBSCertList)
+ {
+ return (TBSCertList)obj;
+ }
+ else if (obj != null)
+ {
+ return new TBSCertList(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public TBSCertList(
+ ASN1Sequence seq)
+ {
+ if (seq.size() < 3 || seq.size() > 7)
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+ }
+
+ int seqPos = 0;
+
+ if (seq.getObjectAt(seqPos) instanceof ASN1Integer)
+ {
+ version = ASN1Integer.getInstance(seq.getObjectAt(seqPos++));
+ }
+ else
+ {
+ version = null; // version is optional
+ }
+
+ signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqPos++));
+ issuer = X500Name.getInstance(seq.getObjectAt(seqPos++));
+ thisUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
+
+ if (seqPos < seq.size()
+ && (seq.getObjectAt(seqPos) instanceof DERUTCTime
+ || seq.getObjectAt(seqPos) instanceof DERGeneralizedTime
+ || seq.getObjectAt(seqPos) instanceof Time))
+ {
+ nextUpdate = Time.getInstance(seq.getObjectAt(seqPos++));
+ }
+
+ if (seqPos < seq.size()
+ && !(seq.getObjectAt(seqPos) instanceof DERTaggedObject))
+ {
+ revokedCertificates = ASN1Sequence.getInstance(seq.getObjectAt(seqPos++));
+ }
+
+ if (seqPos < seq.size()
+ && seq.getObjectAt(seqPos) instanceof DERTaggedObject)
+ {
+ crlExtensions = Extensions.getInstance(ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(seqPos), true));
+ }
+ }
+
+ public int getVersionNumber()
+ {
+ if (version == null)
+ {
+ return 1;
+ }
+ return version.getValue().intValue() + 1;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public AlgorithmIdentifier getSignature()
+ {
+ return signature;
+ }
+
+ public X500Name getIssuer()
+ {
+ return issuer;
+ }
+
+ public Time getThisUpdate()
+ {
+ return thisUpdate;
+ }
+
+ public Time getNextUpdate()
+ {
+ return nextUpdate;
+ }
+
+ public CRLEntry[] getRevokedCertificates()
+ {
+ if (revokedCertificates == null)
+ {
+ return new CRLEntry[0];
+ }
+
+ CRLEntry[] entries = new CRLEntry[revokedCertificates.size()];
+
+ for (int i = 0; i < entries.length; i++)
+ {
+ entries[i] = CRLEntry.getInstance(revokedCertificates.getObjectAt(i));
+ }
+
+ return entries;
+ }
+
+ public Enumeration getRevokedCertificateEnumeration()
+ {
+ if (revokedCertificates == null)
+ {
+ return new EmptyEnumeration();
+ }
+
+ return new RevokedCertificatesEnumeration(revokedCertificates.getObjects());
+ }
+
+ public Extensions getExtensions()
+ {
+ return crlExtensions;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (version != null)
+ {
+ v.add(version);
+ }
+ v.add(signature);
+ v.add(issuer);
+
+ v.add(thisUpdate);
+ if (nextUpdate != null)
+ {
+ v.add(nextUpdate);
+ }
+
+ // Add CRLEntries if they exist
+ if (revokedCertificates != null)
+ {
+ v.add(revokedCertificates);
+ }
+
+ if (crlExtensions != null)
+ {
+ v.add(new DERTaggedObject(0, crlExtensions));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java
new file mode 100644
index 0000000..dc41964
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java
@@ -0,0 +1,192 @@
+package org.bouncycastle.asn1.x509;
+
+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.DERTaggedObject;
+import org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * The TBSCertificate object.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * extensions [ 3 ] Extensions OPTIONAL
+ * }
+ * </pre>
+ * <p>
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+ * will parse them, but you really shouldn't be creating new ones.
+ */
+public class TBSCertificate
+ extends ASN1Object
+{
+ ASN1Sequence seq;
+
+ ASN1Integer version;
+ ASN1Integer serialNumber;
+ AlgorithmIdentifier signature;
+ X500Name issuer;
+ Time startDate, endDate;
+ X500Name subject;
+ SubjectPublicKeyInfo subjectPublicKeyInfo;
+ DERBitString issuerUniqueId;
+ DERBitString subjectUniqueId;
+ Extensions extensions;
+
+ public static TBSCertificate getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static TBSCertificate getInstance(
+ Object obj)
+ {
+ if (obj instanceof TBSCertificate)
+ {
+ return (TBSCertificate)obj;
+ }
+ else if (obj != null)
+ {
+ return new TBSCertificate(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ private TBSCertificate(
+ ASN1Sequence seq)
+ {
+ int seqStart = 0;
+
+ this.seq = seq;
+
+ //
+ // some certficates don't include a version number - we assume v1
+ //
+ if (seq.getObjectAt(0) instanceof DERTaggedObject)
+ {
+ version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
+ }
+ else
+ {
+ seqStart = -1; // field 0 is missing!
+ version = new ASN1Integer(0);
+ }
+
+ serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1));
+
+ signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2));
+ issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3));
+
+ //
+ // before and after dates
+ //
+ ASN1Sequence dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4);
+
+ startDate = Time.getInstance(dates.getObjectAt(0));
+ endDate = Time.getInstance(dates.getObjectAt(1));
+
+ subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5));
+
+ //
+ // public key info.
+ //
+ subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6));
+
+ for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--)
+ {
+ DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras);
+
+ switch (extra.getTagNo())
+ {
+ case 1:
+ issuerUniqueId = DERBitString.getInstance(extra, false);
+ break;
+ case 2:
+ subjectUniqueId = DERBitString.getInstance(extra, false);
+ break;
+ case 3:
+ extensions = Extensions.getInstance(ASN1Sequence.getInstance(extra, true));
+ }
+ }
+ }
+
+ public int getVersionNumber()
+ {
+ return version.getValue().intValue() + 1;
+ }
+
+ public ASN1Integer getVersion()
+ {
+ return version;
+ }
+
+ public ASN1Integer getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ public AlgorithmIdentifier getSignature()
+ {
+ return signature;
+ }
+
+ public X500Name getIssuer()
+ {
+ return issuer;
+ }
+
+ public Time getStartDate()
+ {
+ return startDate;
+ }
+
+ public Time getEndDate()
+ {
+ return endDate;
+ }
+
+ public X500Name getSubject()
+ {
+ return subject;
+ }
+
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return subjectPublicKeyInfo;
+ }
+
+ public DERBitString getIssuerUniqueId()
+ {
+ return issuerUniqueId;
+ }
+
+ public DERBitString getSubjectUniqueId()
+ {
+ return subjectUniqueId;
+ }
+
+ public Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
new file mode 100644
index 0000000..2c5d920
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java
@@ -0,0 +1,194 @@
+package org.bouncycastle.asn1.x509;
+
+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.DERTaggedObject;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * The TBSCertificate object.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * extensions [ 3 ] Extensions OPTIONAL
+ * }
+ * </pre>
+ * <p>
+ * Note: issuerUniqueID and subjectUniqueID are both deprecated by the IETF. This class
+ * will parse them, but you really shouldn't be creating new ones.
+ */
+public class TBSCertificateStructure
+ extends ASN1Object
+ implements X509ObjectIdentifiers, PKCSObjectIdentifiers
+{
+ ASN1Sequence seq;
+
+ ASN1Integer version;
+ ASN1Integer serialNumber;
+ AlgorithmIdentifier signature;
+ X500Name issuer;
+ Time startDate, endDate;
+ X500Name subject;
+ SubjectPublicKeyInfo subjectPublicKeyInfo;
+ DERBitString issuerUniqueId;
+ DERBitString subjectUniqueId;
+ X509Extensions extensions;
+
+ public static TBSCertificateStructure getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static TBSCertificateStructure getInstance(
+ Object obj)
+ {
+ if (obj instanceof TBSCertificateStructure)
+ {
+ return (TBSCertificateStructure)obj;
+ }
+ else if (obj != null)
+ {
+ return new TBSCertificateStructure(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public TBSCertificateStructure(
+ ASN1Sequence seq)
+ {
+ int seqStart = 0;
+
+ this.seq = seq;
+
+ //
+ // some certficates don't include a version number - we assume v1
+ //
+ if (seq.getObjectAt(0) instanceof DERTaggedObject)
+ {
+ version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true);
+ }
+ else
+ {
+ seqStart = -1; // field 0 is missing!
+ version = new ASN1Integer(0);
+ }
+
+ serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1));
+
+ signature = AlgorithmIdentifier.getInstance(seq.getObjectAt(seqStart + 2));
+ issuer = X500Name.getInstance(seq.getObjectAt(seqStart + 3));
+
+ //
+ // before and after dates
+ //
+ ASN1Sequence dates = (ASN1Sequence)seq.getObjectAt(seqStart + 4);
+
+ startDate = Time.getInstance(dates.getObjectAt(0));
+ endDate = Time.getInstance(dates.getObjectAt(1));
+
+ subject = X500Name.getInstance(seq.getObjectAt(seqStart + 5));
+
+ //
+ // public key info.
+ //
+ subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(seq.getObjectAt(seqStart + 6));
+
+ for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--)
+ {
+ DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras);
+
+ switch (extra.getTagNo())
+ {
+ case 1:
+ issuerUniqueId = DERBitString.getInstance(extra, false);
+ break;
+ case 2:
+ subjectUniqueId = DERBitString.getInstance(extra, false);
+ break;
+ case 3:
+ extensions = X509Extensions.getInstance(extra);
+ }
+ }
+ }
+
+ public int getVersion()
+ {
+ return version.getValue().intValue() + 1;
+ }
+
+ public ASN1Integer getVersionNumber()
+ {
+ return version;
+ }
+
+ public ASN1Integer getSerialNumber()
+ {
+ return serialNumber;
+ }
+
+ public AlgorithmIdentifier getSignature()
+ {
+ return signature;
+ }
+
+ public X500Name getIssuer()
+ {
+ return issuer;
+ }
+
+ public Time getStartDate()
+ {
+ return startDate;
+ }
+
+ public Time getEndDate()
+ {
+ return endDate;
+ }
+
+ public X500Name getSubject()
+ {
+ return subject;
+ }
+
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return subjectPublicKeyInfo;
+ }
+
+ public DERBitString getIssuerUniqueId()
+ {
+ return issuerUniqueId;
+ }
+
+ public DERBitString getSubjectUniqueId()
+ {
+ return subjectUniqueId;
+ }
+
+ public X509Extensions getExtensions()
+ {
+ return extensions;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/Time.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Time.java
new file mode 100644
index 0000000..5bffedc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/Time.java
@@ -0,0 +1,133 @@
+package org.bouncycastle.asn1.x509;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.SimpleTimeZone;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERUTCTime;
+
+public class Time
+ extends ASN1Object
+ implements ASN1Choice
+{
+ ASN1Primitive time;
+
+ public static Time getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(obj.getObject()); // must be explicitly tagged
+ }
+
+ public Time(
+ ASN1Primitive time)
+ {
+ if (!(time instanceof DERUTCTime)
+ && !(time instanceof DERGeneralizedTime))
+ {
+ throw new IllegalArgumentException("unknown object passed to Time");
+ }
+
+ this.time = time;
+ }
+
+ /**
+ * 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.
+ */
+ public Time(
+ Date date)
+ {
+ SimpleTimeZone tz = new SimpleTimeZone(0, "Z");
+ SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss");
+
+ dateF.setTimeZone(tz);
+
+ String d = dateF.format(date) + "Z";
+ int year = Integer.parseInt(d.substring(0, 4));
+
+ if (year < 1950 || year > 2049)
+ {
+ time = new DERGeneralizedTime(d);
+ }
+ else
+ {
+ time = new DERUTCTime(d.substring(2));
+ }
+ }
+
+ public static Time getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof Time)
+ {
+ return (Time)obj;
+ }
+ else if (obj instanceof DERUTCTime)
+ {
+ return new Time((DERUTCTime)obj);
+ }
+ else if (obj instanceof DERGeneralizedTime)
+ {
+ return new Time((DERGeneralizedTime)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ public String getTime()
+ {
+ if (time instanceof DERUTCTime)
+ {
+ return ((DERUTCTime)time).getAdjustedTime();
+ }
+ else
+ {
+ return ((DERGeneralizedTime)time).getTime();
+ }
+ }
+
+ public Date getDate()
+ {
+ try
+ {
+ if (time instanceof DERUTCTime)
+ {
+ return ((DERUTCTime)time).getAdjustedDate();
+ }
+ else
+ {
+ return ((DERGeneralizedTime)time).getDate();
+ }
+ }
+ catch (ParseException e)
+ { // this should never happen
+ throw new IllegalStateException("invalid date string: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return time;
+ }
+
+ public String toString()
+ {
+ return getTime();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
new file mode 100644
index 0000000..437d6c0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java
@@ -0,0 +1,144 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.DERUTCTime;
+import org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * Generator for Version 1 TBSCertificateStructures.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * }
+ * </pre>
+ *
+ */
+public class V1TBSCertificateGenerator
+{
+ DERTaggedObject version = new DERTaggedObject(true, 0, new ASN1Integer(0));
+
+ ASN1Integer serialNumber;
+ AlgorithmIdentifier signature;
+ X500Name issuer;
+ Time startDate, endDate;
+ X500Name subject;
+ SubjectPublicKeyInfo subjectPublicKeyInfo;
+
+ public V1TBSCertificateGenerator()
+ {
+ }
+
+ public void setSerialNumber(
+ ASN1Integer serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ public void setSignature(
+ AlgorithmIdentifier signature)
+ {
+ this.signature = signature;
+ }
+
+ /**
+ * @deprecated use X500Name method
+ */
+ public void setIssuer(
+ X509Name issuer)
+ {
+ this.issuer = X500Name.getInstance(issuer.toASN1Primitive());
+ }
+
+ public void setIssuer(
+ X500Name issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ public void setStartDate(
+ Time startDate)
+ {
+ this.startDate = startDate;
+ }
+
+ public void setStartDate(
+ DERUTCTime startDate)
+ {
+ this.startDate = new Time(startDate);
+ }
+
+ public void setEndDate(
+ Time endDate)
+ {
+ this.endDate = endDate;
+ }
+
+ public void setEndDate(
+ DERUTCTime endDate)
+ {
+ this.endDate = new Time(endDate);
+ }
+
+ /**
+ * @deprecated use X500Name method
+ */
+ public void setSubject(
+ X509Name subject)
+ {
+ this.subject = X500Name.getInstance(subject.toASN1Primitive());
+ }
+
+ public void setSubject(
+ X500Name subject)
+ {
+ this.subject = subject;
+ }
+
+ public void setSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo pubKeyInfo)
+ {
+ this.subjectPublicKeyInfo = pubKeyInfo;
+ }
+
+ public TBSCertificate generateTBSCertificate()
+ {
+ if ((serialNumber == null) || (signature == null)
+ || (issuer == null) || (startDate == null) || (endDate == null)
+ || (subject == null) || (subjectPublicKeyInfo == null))
+ {
+ throw new IllegalStateException("not all mandatory fields set in V1 TBScertificate generator");
+ }
+
+ ASN1EncodableVector seq = new ASN1EncodableVector();
+
+ // seq.add(version); - not required as default value.
+ seq.add(serialNumber);
+ seq.add(signature);
+ seq.add(issuer);
+
+ //
+ // before and after dates
+ //
+ ASN1EncodableVector validity = new ASN1EncodableVector();
+
+ validity.add(startDate);
+ validity.add(endDate);
+
+ seq.add(new DERSequence(validity));
+
+ seq.add(subject);
+
+ seq.add(subjectPublicKeyInfo);
+
+ return TBSCertificate.getInstance(new DERSequence(seq));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/V2Form.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/V2Form.java
new file mode 100644
index 0000000..ed5c6ab
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/V2Form.java
@@ -0,0 +1,130 @@
+package org.bouncycastle.asn1.x509;
+
+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 V2Form
+ extends ASN1Object
+{
+ GeneralNames issuerName;
+ IssuerSerial baseCertificateID;
+ ObjectDigestInfo objectDigestInfo;
+
+ public static V2Form getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static V2Form getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof V2Form)
+ {
+ return (V2Form)obj;
+ }
+ else if (obj instanceof ASN1Sequence)
+ {
+ return new V2Form((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
+ }
+
+ public V2Form(
+ GeneralNames issuerName)
+ {
+ this.issuerName = issuerName;
+ }
+
+ public V2Form(
+ ASN1Sequence seq)
+ {
+ if (seq.size() > 3)
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + seq.size());
+ }
+
+ int index = 0;
+
+ if (!(seq.getObjectAt(0) instanceof ASN1TaggedObject))
+ {
+ index++;
+ this.issuerName = GeneralNames.getInstance(seq.getObjectAt(0));
+ }
+
+ for (int i = index; i != seq.size(); i++)
+ {
+ ASN1TaggedObject o = ASN1TaggedObject.getInstance(seq.getObjectAt(i));
+ if (o.getTagNo() == 0)
+ {
+ baseCertificateID = IssuerSerial.getInstance(o, false);
+ }
+ else if (o.getTagNo() == 1)
+ {
+ objectDigestInfo = ObjectDigestInfo.getInstance(o, false);
+ }
+ else
+ {
+ throw new IllegalArgumentException("Bad tag number: "
+ + o.getTagNo());
+ }
+ }
+ }
+
+ public GeneralNames getIssuerName()
+ {
+ return issuerName;
+ }
+
+ public IssuerSerial getBaseCertificateID()
+ {
+ return baseCertificateID;
+ }
+
+ public ObjectDigestInfo getObjectDigestInfo()
+ {
+ return objectDigestInfo;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * V2Form ::= SEQUENCE {
+ * issuerName GeneralNames OPTIONAL,
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * objectDigestInfo [1] ObjectDigestInfo OPTIONAL
+ * -- issuerName MUST be present in this profile
+ * -- baseCertificateID and objectDigestInfo MUST NOT
+ * -- be present in this profile
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (issuerName != null)
+ {
+ v.add(issuerName);
+ }
+
+ if (baseCertificateID != null)
+ {
+ v.add(new DERTaggedObject(false, 0, baseCertificateID));
+ }
+
+ if (objectDigestInfo != null)
+ {
+ v.add(new DERTaggedObject(false, 1, objectDigestInfo));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
new file mode 100644
index 0000000..3d923b6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java
@@ -0,0 +1,212 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+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;
+
+/**
+ * Generator for Version 3 TBSCertificateStructures.
+ * <pre>
+ * TBSCertificate ::= SEQUENCE {
+ * version [ 0 ] Version DEFAULT v1(0),
+ * serialNumber CertificateSerialNumber,
+ * signature AlgorithmIdentifier,
+ * issuer Name,
+ * validity Validity,
+ * subject Name,
+ * subjectPublicKeyInfo SubjectPublicKeyInfo,
+ * issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
+ * extensions [ 3 ] Extensions OPTIONAL
+ * }
+ * </pre>
+ *
+ */
+public class V3TBSCertificateGenerator
+{
+ DERTaggedObject version = new DERTaggedObject(true, 0, new ASN1Integer(2));
+
+ ASN1Integer serialNumber;
+ AlgorithmIdentifier signature;
+ X500Name issuer;
+ Time startDate, endDate;
+ X500Name subject;
+ SubjectPublicKeyInfo subjectPublicKeyInfo;
+ Extensions extensions;
+
+ private boolean altNamePresentAndCritical;
+ private DERBitString issuerUniqueID;
+ private DERBitString subjectUniqueID;
+
+ public V3TBSCertificateGenerator()
+ {
+ }
+
+ public void setSerialNumber(
+ ASN1Integer serialNumber)
+ {
+ this.serialNumber = serialNumber;
+ }
+
+ public void setSignature(
+ AlgorithmIdentifier signature)
+ {
+ this.signature = signature;
+ }
+
+ /**
+ * @deprecated use X500Name method
+ */
+ public void setIssuer(
+ X509Name issuer)
+ {
+ this.issuer = X500Name.getInstance(issuer);
+ }
+
+ public void setIssuer(
+ X500Name issuer)
+ {
+ this.issuer = issuer;
+ }
+
+ public void setStartDate(
+ DERUTCTime startDate)
+ {
+ this.startDate = new Time(startDate);
+ }
+
+ public void setStartDate(
+ Time startDate)
+ {
+ this.startDate = startDate;
+ }
+
+ public void setEndDate(
+ DERUTCTime endDate)
+ {
+ this.endDate = new Time(endDate);
+ }
+
+ public void setEndDate(
+ Time endDate)
+ {
+ this.endDate = endDate;
+ }
+
+ /**
+ * @deprecated use X500Name method
+ */
+ public void setSubject(
+ X509Name subject)
+ {
+ this.subject = X500Name.getInstance(subject.toASN1Primitive());
+ }
+
+ public void setSubject(
+ X500Name subject)
+ {
+ this.subject = subject;
+ }
+
+ public void setIssuerUniqueID(
+ DERBitString uniqueID)
+ {
+ this.issuerUniqueID = uniqueID;
+ }
+
+ public void setSubjectUniqueID(
+ DERBitString uniqueID)
+ {
+ this.subjectUniqueID = uniqueID;
+ }
+
+ public void setSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo pubKeyInfo)
+ {
+ this.subjectPublicKeyInfo = pubKeyInfo;
+ }
+
+ /**
+ * @deprecated use method taking Extensions
+ * @param extensions
+ */
+ public void setExtensions(
+ X509Extensions extensions)
+ {
+ setExtensions(Extensions.getInstance(extensions));
+ }
+
+ public void setExtensions(
+ Extensions extensions)
+ {
+ this.extensions = extensions;
+ if (extensions != null)
+ {
+ Extension altName = extensions.getExtension(Extension.subjectAlternativeName);
+
+ if (altName != null && altName.isCritical())
+ {
+ altNamePresentAndCritical = true;
+ }
+ }
+ }
+
+ public TBSCertificate generateTBSCertificate()
+ {
+ if ((serialNumber == null) || (signature == null)
+ || (issuer == null) || (startDate == null) || (endDate == null)
+ || (subject == null && !altNamePresentAndCritical) || (subjectPublicKeyInfo == null))
+ {
+ throw new IllegalStateException("not all mandatory fields set in V3 TBScertificate generator");
+ }
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(version);
+ v.add(serialNumber);
+ v.add(signature);
+ v.add(issuer);
+
+ //
+ // before and after dates
+ //
+ ASN1EncodableVector validity = new ASN1EncodableVector();
+
+ validity.add(startDate);
+ validity.add(endDate);
+
+ v.add(new DERSequence(validity));
+
+ if (subject != null)
+ {
+ v.add(subject);
+ }
+ else
+ {
+ v.add(new DERSequence());
+ }
+
+ v.add(subjectPublicKeyInfo);
+
+ if (issuerUniqueID != null)
+ {
+ v.add(new DERTaggedObject(false, 1, issuerUniqueID));
+ }
+
+ if (subjectUniqueID != null)
+ {
+ v.add(new DERTaggedObject(false, 2, subjectUniqueID));
+ }
+
+ if (extensions != null)
+ {
+ v.add(new DERTaggedObject(true, 3, extensions));
+ }
+
+ return TBSCertificate.getInstance(new DERSequence(v));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
new file mode 100644
index 0000000..6830030
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509CertificateStructure.java
@@ -0,0 +1,129 @@
+package org.bouncycastle.asn1.x509;
+
+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.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.X500Name;
+
+/**
+ * an X509Certificate structure.
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * </pre>
+ * @deprecated use org.bouncycastle.asn1.x509.Certificate
+ */
+public class X509CertificateStructure
+ extends ASN1Object
+ implements X509ObjectIdentifiers, PKCSObjectIdentifiers
+{
+ ASN1Sequence seq;
+ TBSCertificateStructure tbsCert;
+ AlgorithmIdentifier sigAlgId;
+ DERBitString sig;
+
+ public static X509CertificateStructure getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static X509CertificateStructure getInstance(
+ Object obj)
+ {
+ if (obj instanceof X509CertificateStructure)
+ {
+ return (X509CertificateStructure)obj;
+ }
+ else if (obj != null)
+ {
+ return new X509CertificateStructure(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public X509CertificateStructure(
+ ASN1Sequence seq)
+ {
+ this.seq = seq;
+
+ //
+ // correct x509 certficate
+ //
+ if (seq.size() == 3)
+ {
+ tbsCert = TBSCertificateStructure.getInstance(seq.getObjectAt(0));
+ sigAlgId = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
+
+ sig = DERBitString.getInstance(seq.getObjectAt(2));
+ }
+ else
+ {
+ throw new IllegalArgumentException("sequence wrong size for a certificate");
+ }
+ }
+
+ public TBSCertificateStructure getTBSCertificate()
+ {
+ return tbsCert;
+ }
+
+ public int getVersion()
+ {
+ return tbsCert.getVersion();
+ }
+
+ public ASN1Integer getSerialNumber()
+ {
+ return tbsCert.getSerialNumber();
+ }
+
+ public X500Name getIssuer()
+ {
+ return tbsCert.getIssuer();
+ }
+
+ public Time getStartDate()
+ {
+ return tbsCert.getStartDate();
+ }
+
+ public Time getEndDate()
+ {
+ return tbsCert.getEndDate();
+ }
+
+ public X500Name getSubject()
+ {
+ return tbsCert.getSubject();
+ }
+
+ public SubjectPublicKeyInfo getSubjectPublicKeyInfo()
+ {
+ return tbsCert.getSubjectPublicKeyInfo();
+ }
+
+ public AlgorithmIdentifier getSignatureAlgorithm()
+ {
+ return sigAlgId;
+ }
+
+ public DERBitString getSignature()
+ {
+ return sig;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return seq;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java
new file mode 100644
index 0000000..0ae0f80
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509DefaultEntryConverter.java
@@ -0,0 +1,65 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DERGeneralizedTime;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERPrintableString;
+import org.bouncycastle.asn1.DERUTF8String;
+
+/**
+ * The default converter for X509 DN entries when going from their
+ * string value to ASN.1 strings.
+ */
+public class X509DefaultEntryConverter
+ extends X509NameEntryConverter
+{
+ /**
+ * Apply default coversion for the given value depending on the oid
+ * and the character range of the value.
+ *
+ * @param oid the object identifier for the DN entry
+ * @param value the value associated with it
+ * @return the ASN.1 equivalent for the string value.
+ */
+ public ASN1Primitive getConvertedValue(
+ ASN1ObjectIdentifier oid,
+ String value)
+ {
+ if (value.length() != 0 && value.charAt(0) == '#')
+ {
+ try
+ {
+ return convertHexEncoded(value, 1);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("can't recode value for oid " + oid.getId());
+ }
+ }
+ else
+ {
+ if (value.length() != 0 && value.charAt(0) == '\\')
+ {
+ value = value.substring(1);
+ }
+ if (oid.equals(X509Name.EmailAddress) || oid.equals(X509Name.DC))
+ {
+ return new DERIA5String(value);
+ }
+ else if (oid.equals(X509Name.DATE_OF_BIRTH)) // accept time string as well as # (for compatibility)
+ {
+ return new DERGeneralizedTime(value);
+ }
+ else if (oid.equals(X509Name.C) || oid.equals(X509Name.SN) || oid.equals(X509Name.DN_QUALIFIER)
+ || oid.equals(X509Name.TELEPHONE_NUMBER))
+ {
+ return new DERPrintableString(value);
+ }
+ }
+
+ return new DERUTF8String(value);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
new file mode 100644
index 0000000..f020bcb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java
@@ -0,0 +1,248 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+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.
+ */
+public class X509Extension
+{
+ /**
+ * Subject Directory Attributes
+ */
+ public static final ASN1ObjectIdentifier subjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9");
+
+ /**
+ * Subject Key Identifier
+ */
+ public static final ASN1ObjectIdentifier subjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14");
+
+ /**
+ * Key Usage
+ */
+ public static final ASN1ObjectIdentifier keyUsage = new ASN1ObjectIdentifier("2.5.29.15");
+
+ /**
+ * Private Key Usage Period
+ */
+ public static final ASN1ObjectIdentifier privateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16");
+
+ /**
+ * Subject Alternative Name
+ */
+ public static final ASN1ObjectIdentifier subjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17");
+
+ /**
+ * Issuer Alternative Name
+ */
+ public static final ASN1ObjectIdentifier issuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18");
+
+ /**
+ * Basic Constraints
+ */
+ public static final ASN1ObjectIdentifier basicConstraints = new ASN1ObjectIdentifier("2.5.29.19");
+
+ /**
+ * CRL Number
+ */
+ public static final ASN1ObjectIdentifier cRLNumber = new ASN1ObjectIdentifier("2.5.29.20");
+
+ /**
+ * Reason code
+ */
+ public static final ASN1ObjectIdentifier reasonCode = new ASN1ObjectIdentifier("2.5.29.21");
+
+ /**
+ * Hold Instruction Code
+ */
+ public static final ASN1ObjectIdentifier instructionCode = new ASN1ObjectIdentifier("2.5.29.23");
+
+ /**
+ * Invalidity Date
+ */
+ public static final ASN1ObjectIdentifier invalidityDate = new ASN1ObjectIdentifier("2.5.29.24");
+
+ /**
+ * Delta CRL indicator
+ */
+ public static final ASN1ObjectIdentifier deltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27");
+
+ /**
+ * Issuing Distribution Point
+ */
+ public static final ASN1ObjectIdentifier issuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28");
+
+ /**
+ * Certificate Issuer
+ */
+ public static final ASN1ObjectIdentifier certificateIssuer = new ASN1ObjectIdentifier("2.5.29.29");
+
+ /**
+ * Name Constraints
+ */
+ public static final ASN1ObjectIdentifier nameConstraints = new ASN1ObjectIdentifier("2.5.29.30");
+
+ /**
+ * CRL Distribution Points
+ */
+ public static final ASN1ObjectIdentifier cRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31");
+
+ /**
+ * Certificate Policies
+ */
+ public static final ASN1ObjectIdentifier certificatePolicies = new ASN1ObjectIdentifier("2.5.29.32");
+
+ /**
+ * Policy Mappings
+ */
+ public static final ASN1ObjectIdentifier policyMappings = new ASN1ObjectIdentifier("2.5.29.33");
+
+ /**
+ * Authority Key Identifier
+ */
+ public static final ASN1ObjectIdentifier authorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35");
+
+ /**
+ * Policy Constraints
+ */
+ public static final ASN1ObjectIdentifier policyConstraints = new ASN1ObjectIdentifier("2.5.29.36");
+
+ /**
+ * Extended Key Usage
+ */
+ public static final ASN1ObjectIdentifier extendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37");
+
+ /**
+ * Freshest CRL
+ */
+ public static final ASN1ObjectIdentifier freshestCRL = new ASN1ObjectIdentifier("2.5.29.46");
+
+ /**
+ * Inhibit Any Policy
+ */
+ public static final ASN1ObjectIdentifier inhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54");
+
+ /**
+ * Authority Info Access
+ */
+ public static final ASN1ObjectIdentifier authorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+ /**
+ * Subject Info Access
+ */
+ public static final ASN1ObjectIdentifier subjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11");
+
+ /**
+ * Logo Type
+ */
+ public static final ASN1ObjectIdentifier logoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+ /**
+ * BiometricInfo
+ */
+ public static final ASN1ObjectIdentifier biometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2");
+
+ /**
+ * QCStatements
+ */
+ public static final ASN1ObjectIdentifier qCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+ /**
+ * Audit identity extension in attribute certificates.
+ */
+ public static final ASN1ObjectIdentifier auditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4");
+
+ /**
+ * NoRevAvail extension in attribute certificates.
+ */
+ public static final ASN1ObjectIdentifier noRevAvail = new ASN1ObjectIdentifier("2.5.29.56");
+
+ /**
+ * TargetInformation extension in attribute certificates.
+ */
+ public static final ASN1ObjectIdentifier targetInformation = new ASN1ObjectIdentifier("2.5.29.55");
+
+ boolean critical;
+ ASN1OctetString value;
+
+ public X509Extension(
+ DERBoolean critical,
+ ASN1OctetString value)
+ {
+ this.critical = critical.isTrue();
+ this.value = value;
+ }
+
+ public X509Extension(
+ boolean critical,
+ ASN1OctetString value)
+ {
+ this.critical = critical;
+ this.value = value;
+ }
+
+ public boolean isCritical()
+ {
+ return critical;
+ }
+
+ public ASN1OctetString getValue()
+ {
+ return value;
+ }
+
+ public ASN1Encodable getParsedValue()
+ {
+ return convertValueToObject(this);
+ }
+
+ public int hashCode()
+ {
+ if (this.isCritical())
+ {
+ return this.getValue().hashCode();
+ }
+
+ return ~this.getValue().hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof X509Extension))
+ {
+ return false;
+ }
+
+ X509Extension other = (X509Extension)o;
+
+ return other.getValue().equals(this.getValue())
+ && (other.isCritical() == this.isCritical());
+ }
+
+ /**
+ * Convert the value of the passed in extension to an object
+ * @param ext the extension to parse
+ * @return the object the value string contains
+ * @exception IllegalArgumentException if conversion is not possible
+ */
+ public static ASN1Primitive convertValueToObject(
+ X509Extension ext)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ return ASN1Primitive.fromByteArray(ext.getValue().getOctets());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't convert extension: " + e);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
new file mode 100644
index 0000000..5e9bb46
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java
@@ -0,0 +1,489 @@
+package org.bouncycastle.asn1.x509;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+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.DERBoolean;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * @deprecated use Extensions
+ */
+public class X509Extensions
+ extends ASN1Object
+{
+ /**
+ * Subject Directory Attributes
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier SubjectDirectoryAttributes = new ASN1ObjectIdentifier("2.5.29.9");
+
+ /**
+ * Subject Key Identifier
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier SubjectKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.14");
+
+ /**
+ * Key Usage
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier KeyUsage = new ASN1ObjectIdentifier("2.5.29.15");
+
+ /**
+ * Private Key Usage Period
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier PrivateKeyUsagePeriod = new ASN1ObjectIdentifier("2.5.29.16");
+
+ /**
+ * Subject Alternative Name
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier SubjectAlternativeName = new ASN1ObjectIdentifier("2.5.29.17");
+
+ /**
+ * Issuer Alternative Name
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier IssuerAlternativeName = new ASN1ObjectIdentifier("2.5.29.18");
+
+ /**
+ * Basic Constraints
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier BasicConstraints = new ASN1ObjectIdentifier("2.5.29.19");
+
+ /**
+ * CRL Number
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier CRLNumber = new ASN1ObjectIdentifier("2.5.29.20");
+
+ /**
+ * Reason code
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier ReasonCode = new ASN1ObjectIdentifier("2.5.29.21");
+
+ /**
+ * Hold Instruction Code
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier InstructionCode = new ASN1ObjectIdentifier("2.5.29.23");
+
+ /**
+ * Invalidity Date
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier InvalidityDate = new ASN1ObjectIdentifier("2.5.29.24");
+
+ /**
+ * Delta CRL indicator
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier DeltaCRLIndicator = new ASN1ObjectIdentifier("2.5.29.27");
+
+ /**
+ * Issuing Distribution Point
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier IssuingDistributionPoint = new ASN1ObjectIdentifier("2.5.29.28");
+
+ /**
+ * Certificate Issuer
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier CertificateIssuer = new ASN1ObjectIdentifier("2.5.29.29");
+
+ /**
+ * Name Constraints
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier NameConstraints = new ASN1ObjectIdentifier("2.5.29.30");
+
+ /**
+ * CRL Distribution Points
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier CRLDistributionPoints = new ASN1ObjectIdentifier("2.5.29.31");
+
+ /**
+ * Certificate Policies
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier CertificatePolicies = new ASN1ObjectIdentifier("2.5.29.32");
+
+ /**
+ * Policy Mappings
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier PolicyMappings = new ASN1ObjectIdentifier("2.5.29.33");
+
+ /**
+ * Authority Key Identifier
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier AuthorityKeyIdentifier = new ASN1ObjectIdentifier("2.5.29.35");
+
+ /**
+ * Policy Constraints
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier PolicyConstraints = new ASN1ObjectIdentifier("2.5.29.36");
+
+ /**
+ * Extended Key Usage
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier ExtendedKeyUsage = new ASN1ObjectIdentifier("2.5.29.37");
+
+ /**
+ * Freshest CRL
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier FreshestCRL = new ASN1ObjectIdentifier("2.5.29.46");
+
+ /**
+ * Inhibit Any Policy
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier InhibitAnyPolicy = new ASN1ObjectIdentifier("2.5.29.54");
+
+ /**
+ * Authority Info Access
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier AuthorityInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+ /**
+ * Subject Info Access
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier SubjectInfoAccess = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.11");
+
+ /**
+ * Logo Type
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier LogoType = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+ /**
+ * BiometricInfo
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier BiometricInfo = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.2");
+
+ /**
+ * QCStatements
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier QCStatements = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+ /**
+ * Audit identity extension in attribute certificates.
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier AuditIdentity = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.4");
+
+ /**
+ * NoRevAvail extension in attribute certificates.
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier NoRevAvail = new ASN1ObjectIdentifier("2.5.29.56");
+
+ /**
+ * TargetInformation extension in attribute certificates.
+ * @deprecated use X509Extension value.
+ */
+ public static final ASN1ObjectIdentifier TargetInformation = new ASN1ObjectIdentifier("2.5.29.55");
+
+ private Hashtable extensions = new Hashtable();
+ private Vector ordering = new Vector();
+
+ public static X509Extensions getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static X509Extensions getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof X509Extensions)
+ {
+ return (X509Extensions)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new X509Extensions((ASN1Sequence)obj);
+ }
+
+ if (obj instanceof Extensions)
+ {
+ return new X509Extensions((ASN1Sequence)((Extensions)obj).toASN1Primitive());
+ }
+
+ if (obj instanceof ASN1TaggedObject)
+ {
+ return getInstance(((ASN1TaggedObject)obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * Constructor from ASN1Sequence.
+ *
+ * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
+ */
+ public X509Extensions(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ ASN1Sequence s = ASN1Sequence.getInstance(e.nextElement());
+
+ if (s.size() == 3)
+ {
+ extensions.put(s.getObjectAt(0), new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2))));
+ }
+ else if (s.size() == 2)
+ {
+ extensions.put(s.getObjectAt(0), new X509Extension(false, ASN1OctetString.getInstance(s.getObjectAt(1))));
+ }
+ else
+ {
+ throw new IllegalArgumentException("Bad sequence size: " + s.size());
+ }
+
+ ordering.addElement(s.getObjectAt(0));
+ }
+ }
+
+ /**
+ * constructor from a table of extensions.
+ * <p>
+ * it's is assumed the table contains OID/String pairs.
+ */
+ public X509Extensions(
+ Hashtable extensions)
+ {
+ this(null, extensions);
+ }
+
+ /**
+ * Constructor from a table of extensions with ordering.
+ * <p>
+ * It's is assumed the table contains OID/String pairs.
+ */
+ public X509Extensions(
+ Vector ordering,
+ Hashtable extensions)
+ {
+ Enumeration e;
+
+ if (ordering == null)
+ {
+ e = extensions.keys();
+ }
+ else
+ {
+ e = ordering.elements();
+ }
+
+ while (e.hasMoreElements())
+ {
+ this.ordering.addElement(ASN1ObjectIdentifier.getInstance(e.nextElement()));
+ }
+
+ e = this.ordering.elements();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(e.nextElement());
+ X509Extension ext = (X509Extension)extensions.get(oid);
+
+ this.extensions.put(oid, ext);
+ }
+ }
+
+ /**
+ * Constructor from two vectors
+ *
+ * @param objectIDs a vector of the object identifiers.
+ * @param values a vector of the extension values.
+ */
+ public X509Extensions(
+ Vector objectIDs,
+ Vector values)
+ {
+ Enumeration e = objectIDs.elements();
+
+ while (e.hasMoreElements())
+ {
+ this.ordering.addElement(e.nextElement());
+ }
+
+ int count = 0;
+
+ e = this.ordering.elements();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ X509Extension ext = (X509Extension)values.elementAt(count);
+
+ this.extensions.put(oid, ext);
+ count++;
+ }
+ }
+
+ /**
+ * return an Enumeration of the extension field's object ids.
+ */
+ public Enumeration oids()
+ {
+ return ordering.elements();
+ }
+
+ /**
+ * return the extension represented by the object identifier
+ * passed in.
+ *
+ * @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)
+ {
+ return (X509Extension)extensions.get(oid);
+ }
+
+ /**
+ * <pre>
+ * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ * Extension ::= SEQUENCE {
+ * extnId EXTENSION.&amp;id ({ExtensionSet}),
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ Enumeration e = ordering.elements();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ X509Extension ext = (X509Extension)extensions.get(oid);
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(oid);
+
+ if (ext.isCritical())
+ {
+ // BEGIN android-changed
+ v.add(DERBoolean.TRUE);
+ // END android-changed
+ }
+
+ v.add(ext.getValue());
+
+ vec.add(new DERSequence(v));
+ }
+
+ return new DERSequence(vec);
+ }
+
+ public boolean equivalent(
+ X509Extensions other)
+ {
+ if (extensions.size() != other.extensions.size())
+ {
+ return false;
+ }
+
+ Enumeration e1 = extensions.keys();
+
+ while (e1.hasMoreElements())
+ {
+ Object key = e1.nextElement();
+
+ if (!extensions.get(key).equals(other.extensions.get(key)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public ASN1ObjectIdentifier[] getExtensionOIDs()
+ {
+ return toOidArray(ordering);
+ }
+
+ public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)
+ {
+ Vector oidVec = new Vector();
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ Object oid = ordering.elementAt(i);
+
+ if (((X509Extension)extensions.get(oid)).isCritical() == isCritical)
+ {
+ oidVec.addElement(oid);
+ }
+ }
+
+ return toOidArray(oidVec);
+ }
+
+ private ASN1ObjectIdentifier[] toOidArray(Vector oidVec)
+ {
+ ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()];
+
+ for (int i = 0; i != oids.length; i++)
+ {
+ oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i);
+ }
+ return oids;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
new file mode 100644
index 0000000..468d1b9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java
@@ -0,0 +1,117 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Hashtable;
+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;
+
+/**
+ * Generator for X.509 extensions
+ * @deprecated use org.bouncycastle.asn1.x509.ExtensionsGenerator
+ */
+public class X509ExtensionsGenerator
+{
+ private Hashtable extensions = new Hashtable();
+ private Vector extOrdering = new Vector();
+
+ /**
+ * Reset the generator
+ */
+ public void reset()
+ {
+ extensions = new Hashtable();
+ 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.
+ *
+ * @param oid OID for the extension.
+ * @param critical true if critical, false otherwise.
+ * @param value the ASN.1 object to be included in the extension.
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ try
+ {
+ this.addExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error encoding value: " + e);
+ }
+ }
+
+ /**
+ * Add an extension with the given oid and the passed in byte array to be wrapped in the
+ * OCTET STRING associated with the extension.
+ *
+ * @param oid OID for the extension.
+ * @param critical true if critical, false otherwise.
+ * @param value the byte array to be wrapped.
+ */
+ public void addExtension(
+ ASN1ObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ if (extensions.containsKey(oid))
+ {
+ throw new IllegalArgumentException("extension " + oid + " already added");
+ }
+
+ extOrdering.addElement(oid);
+ extensions.put(oid, new X509Extension(critical, new DEROctetString(value)));
+ }
+
+ /**
+ * Return true if there are no extension present in this generator.
+ *
+ * @return true if empty, false otherwise
+ */
+ public boolean isEmpty()
+ {
+ return extOrdering.isEmpty();
+ }
+
+ /**
+ * Generate an X509Extensions object based on the current state of the generator.
+ *
+ * @return an X09Extensions object.
+ */
+ public X509Extensions generate()
+ {
+ return new X509Extensions(extOrdering, extensions);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
new file mode 100644
index 0000000..2dc630f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
@@ -0,0 +1,1286 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1String;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.DERUniversalString;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+/**
+ * <pre>
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ *
+ * RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+ *
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type OBJECT IDENTIFIER,
+ * value ANY }
+ * </pre>
+ * @deprecated use org.bouncycastle.asn1.x500.X500Name.
+ */
+public class X509Name
+ extends ASN1Object
+{
+ /**
+ * country code - StringType(SIZE(2))
+ * @deprecated use a X500NameStyle
+ */
+ public static final ASN1ObjectIdentifier C = new ASN1ObjectIdentifier("2.5.4.6");
+
+ /**
+ * organization - StringType(SIZE(1..64))
+ * @deprecated use a X500NameStyle
+ */
+ public static final ASN1ObjectIdentifier O = new ASN1ObjectIdentifier("2.5.4.10");
+
+ /**
+ * organizational unit name - StringType(SIZE(1..64))
+ * @deprecated use a X500NameStyle
+ */
+ public static final ASN1ObjectIdentifier OU = new ASN1ObjectIdentifier("2.5.4.11");
+
+ /**
+ * Title
+ * @deprecated use a X500NameStyle
+ */
+ public static final ASN1ObjectIdentifier T = new ASN1ObjectIdentifier("2.5.4.12");
+
+ /**
+ * common name - StringType(SIZE(1..64))
+ * @deprecated use a X500NameStyle
+ */
+ public static final ASN1ObjectIdentifier CN = new ASN1ObjectIdentifier("2.5.4.3");
+
+ /**
+ * device serial number name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5");
+
+ /**
+ * street - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier STREET = new ASN1ObjectIdentifier("2.5.4.9");
+
+ /**
+ * device serial number name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier SERIALNUMBER = SN;
+
+ /**
+ * locality name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier L = new ASN1ObjectIdentifier("2.5.4.7");
+
+ /**
+ * state, or province name - StringType(SIZE(1..64))
+ */
+ public static final ASN1ObjectIdentifier ST = new ASN1ObjectIdentifier("2.5.4.8");
+
+ /**
+ * 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");
+
+ /**
+ * businessCategory - DirectoryString(SIZE(1..128)
+ */
+ public static final ASN1ObjectIdentifier BUSINESS_CATEGORY = new ASN1ObjectIdentifier(
+ "2.5.4.15");
+
+ /**
+ * postalCode - DirectoryString(SIZE(1..40)
+ */
+ public static final ASN1ObjectIdentifier POSTAL_CODE = new ASN1ObjectIdentifier(
+ "2.5.4.17");
+
+ /**
+ * dnQualifier - DirectoryString(SIZE(1..64)
+ */
+ public static final ASN1ObjectIdentifier DN_QUALIFIER = new ASN1ObjectIdentifier(
+ "2.5.4.46");
+
+ /**
+ * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+ */
+ public static final ASN1ObjectIdentifier PSEUDONYM = new ASN1ObjectIdentifier(
+ "2.5.4.65");
+
+
+ /**
+ * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+ */
+ public static final ASN1ObjectIdentifier DATE_OF_BIRTH = new ASN1ObjectIdentifier(
+ "1.3.6.1.5.5.7.9.1");
+
+ /**
+ * 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");
+
+ /**
+ * 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");
+
+ /**
+ * 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");
+
+ /**
+ * 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");
+
+
+ /**
+ * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+ */
+ public static final ASN1ObjectIdentifier NAME_AT_BIRTH = new ASN1ObjectIdentifier("1.3.36.8.3.14");
+
+ /**
+ * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+ * DirectoryString(SIZE(1..30))
+ */
+ public static final ASN1ObjectIdentifier POSTAL_ADDRESS = new ASN1ObjectIdentifier("2.5.4.16");
+
+ /**
+ * RFC 2256 dmdName
+ */
+ public static final ASN1ObjectIdentifier DMD_NAME = new ASN1ObjectIdentifier("2.5.4.54");
+
+ /**
+ * id-at-telephoneNumber
+ */
+ public static final ASN1ObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;
+
+ /**
+ * id-at-name
+ */
+ public static final ASN1ObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;
+
+ /**
+ * Email address (RSA PKCS#9 extension) - IA5String.
+ * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+ * @deprecated use a X500NameStyle
+ */
+ public static final ASN1ObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
+
+ /**
+ * more from PKCS#9
+ */
+ public static final ASN1ObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;
+ public static final ASN1ObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;
+
+ /**
+ * email address in Verisign certificates
+ */
+ public static final ASN1ObjectIdentifier E = EmailAddress;
+
+ /*
+ * others...
+ */
+ public static final ASN1ObjectIdentifier DC = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+ /**
+ * LDAP User id.
+ */
+ public static final ASN1ObjectIdentifier UID = new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+ /**
+ * determines whether or not strings should be processed and printed
+ * from back to front.
+ */
+ public static boolean DefaultReverse = false;
+
+ /**
+ * default look up table translating OID values into their common symbols following
+ * the convention in RFC 2253 with a few extras
+ */
+ public static final Hashtable DefaultSymbols = new Hashtable();
+
+ /**
+ * look up table translating OID values into their common symbols following the convention in RFC 2253
+ *
+ */
+ public static final Hashtable RFC2253Symbols = new Hashtable();
+
+ /**
+ * look up table translating OID values into their common symbols following the convention in RFC 1779
+ *
+ */
+ public static final Hashtable RFC1779Symbols = new Hashtable();
+
+ /**
+ * look up table translating common symbols into their OIDS.
+ */
+ public static final Hashtable DefaultLookUp = new Hashtable();
+
+ /**
+ * look up table translating OID values into their common symbols
+ * @deprecated use DefaultSymbols
+ */
+ public static final Hashtable OIDLookUp = DefaultSymbols;
+
+ /**
+ * look up table translating string values into their OIDS -
+ * @deprecated use DefaultLookUp
+ */
+ public static final Hashtable SymbolLookUp = DefaultLookUp;
+
+ // BEGIN android-changed
+ private static final Boolean TRUE = Boolean.TRUE;
+ private static final Boolean FALSE = Boolean.FALSE;
+ // END android-changed
+
+ static
+ {
+ DefaultSymbols.put(C, "C");
+ DefaultSymbols.put(O, "O");
+ DefaultSymbols.put(T, "T");
+ DefaultSymbols.put(OU, "OU");
+ DefaultSymbols.put(CN, "CN");
+ DefaultSymbols.put(L, "L");
+ DefaultSymbols.put(ST, "ST");
+ DefaultSymbols.put(SN, "SERIALNUMBER");
+ DefaultSymbols.put(EmailAddress, "E");
+ DefaultSymbols.put(DC, "DC");
+ DefaultSymbols.put(UID, "UID");
+ DefaultSymbols.put(STREET, "STREET");
+ DefaultSymbols.put(SURNAME, "SURNAME");
+ DefaultSymbols.put(GIVENNAME, "GIVENNAME");
+ DefaultSymbols.put(INITIALS, "INITIALS");
+ DefaultSymbols.put(GENERATION, "GENERATION");
+ DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress");
+ DefaultSymbols.put(UnstructuredName, "unstructuredName");
+ DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier");
+ DefaultSymbols.put(DN_QUALIFIER, "DN");
+ DefaultSymbols.put(PSEUDONYM, "Pseudonym");
+ DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress");
+ DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth");
+ DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship");
+ DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence");
+ DefaultSymbols.put(GENDER, "Gender");
+ DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth");
+ DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth");
+ DefaultSymbols.put(POSTAL_CODE, "PostalCode");
+ DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory");
+ DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber");
+ DefaultSymbols.put(NAME, "Name");
+
+ RFC2253Symbols.put(C, "C");
+ RFC2253Symbols.put(O, "O");
+ RFC2253Symbols.put(OU, "OU");
+ RFC2253Symbols.put(CN, "CN");
+ RFC2253Symbols.put(L, "L");
+ RFC2253Symbols.put(ST, "ST");
+ RFC2253Symbols.put(STREET, "STREET");
+ RFC2253Symbols.put(DC, "DC");
+ RFC2253Symbols.put(UID, "UID");
+
+ RFC1779Symbols.put(C, "C");
+ RFC1779Symbols.put(O, "O");
+ RFC1779Symbols.put(OU, "OU");
+ RFC1779Symbols.put(CN, "CN");
+ RFC1779Symbols.put(L, "L");
+ RFC1779Symbols.put(ST, "ST");
+ RFC1779Symbols.put(STREET, "STREET");
+
+ DefaultLookUp.put("c", C);
+ DefaultLookUp.put("o", O);
+ DefaultLookUp.put("t", T);
+ DefaultLookUp.put("ou", OU);
+ DefaultLookUp.put("cn", CN);
+ DefaultLookUp.put("l", L);
+ DefaultLookUp.put("st", ST);
+ DefaultLookUp.put("sn", SN);
+ DefaultLookUp.put("serialnumber", SN);
+ DefaultLookUp.put("street", STREET);
+ DefaultLookUp.put("emailaddress", E);
+ DefaultLookUp.put("dc", DC);
+ DefaultLookUp.put("e", E);
+ DefaultLookUp.put("uid", UID);
+ DefaultLookUp.put("surname", SURNAME);
+ DefaultLookUp.put("givenname", GIVENNAME);
+ DefaultLookUp.put("initials", INITIALS);
+ DefaultLookUp.put("generation", GENERATION);
+ DefaultLookUp.put("unstructuredaddress", UnstructuredAddress);
+ DefaultLookUp.put("unstructuredname", UnstructuredName);
+ DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER);
+ DefaultLookUp.put("dn", DN_QUALIFIER);
+ DefaultLookUp.put("pseudonym", PSEUDONYM);
+ DefaultLookUp.put("postaladdress", POSTAL_ADDRESS);
+ DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH);
+ DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP);
+ DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE);
+ DefaultLookUp.put("gender", GENDER);
+ DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH);
+ DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH);
+ DefaultLookUp.put("postalcode", POSTAL_CODE);
+ DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY);
+ DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER);
+ DefaultLookUp.put("name", NAME);
+ }
+
+ private X509NameEntryConverter converter = null;
+ private Vector ordering = new Vector();
+ private Vector values = new Vector();
+ private Vector added = new Vector();
+
+ private ASN1Sequence seq;
+
+ private boolean isHashCodeCalculated;
+ private int hashCodeValue;
+
+ /**
+ * Return a X509Name based on the passed in tagged object.
+ *
+ * @param obj tag object holding name.
+ * @param explicit true if explicitly tagged false otherwise.
+ * @return the X509Name
+ */
+ public static X509Name getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static X509Name getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof X509Name)
+ {
+ return (X509Name)obj;
+ }
+ else if (obj instanceof X500Name)
+ {
+ return new X509Name(ASN1Sequence.getInstance(((X500Name)obj).toASN1Primitive()));
+ }
+ else if (obj != null)
+ {
+ return new X509Name(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ protected X509Name()
+ {
+ // constructure use by new X500 Name class
+ }
+ /**
+ * Constructor from ASN1Sequence
+ *
+ * the principal will be a list of constructed sets, each containing an (OID, String) pair.
+ */
+ public X509Name(
+ ASN1Sequence seq)
+ {
+ this.seq = seq;
+
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ ASN1Set set = ASN1Set.getInstance(((ASN1Encodable)e.nextElement()).toASN1Primitive());
+
+ for (int i = 0; i < set.size(); i++)
+ {
+ ASN1Sequence s = ASN1Sequence.getInstance(set.getObjectAt(i).toASN1Primitive());
+
+ if (s.size() != 2)
+ {
+ throw new IllegalArgumentException("badly sized pair");
+ }
+
+ ordering.addElement(ASN1ObjectIdentifier.getInstance(s.getObjectAt(0)));
+
+ ASN1Encodable value = s.getObjectAt(1);
+ if (value instanceof ASN1String && !(value instanceof DERUniversalString))
+ {
+ String v = ((ASN1String)value).getString();
+ if (v.length() > 0 && v.charAt(0) == '#')
+ {
+ values.addElement("\\" + v);
+ }
+ else
+ {
+ values.addElement(v);
+ }
+ }
+ else
+ {
+ try
+ {
+ values.addElement("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))));
+ }
+ catch (IOException e1)
+ {
+ throw new IllegalArgumentException("cannot encode value");
+ }
+ }
+ // BEGIN android-changed
+ added.addElement(Boolean.valueOf(i != 0));
+ // END android-changed
+ }
+ }
+ }
+
+ /**
+ * constructor from a table of attributes.
+ * <p>
+ * it's is assumed the table contains OID/String pairs, and the contents
+ * of the table are copied into an internal table as part of the
+ * construction process.
+ * <p>
+ * <b>Note:</b> if the name you are trying to generate should be
+ * following a specific ordering, you should use the constructor
+ * with the ordering specified below.
+ * @deprecated use an ordered constructor! The hashtable ordering is rarely correct
+ */
+ public X509Name(
+ Hashtable attributes)
+ {
+ this(null, attributes);
+ }
+
+ /**
+ * Constructor from a table of attributes with ordering.
+ * <p>
+ * it's is assumed the table contains OID/String pairs, and the contents
+ * of the table are copied into an internal table as part of the
+ * construction process. The ordering vector should contain the OIDs
+ * in the order they are meant to be encoded or printed in toString.
+ */
+ public X509Name(
+ Vector ordering,
+ Hashtable attributes)
+ {
+ this(ordering, attributes, new X509DefaultEntryConverter());
+ }
+
+ /**
+ * Constructor from a table of attributes with ordering.
+ * <p>
+ * it's is assumed the table contains OID/String pairs, and the contents
+ * of the table are copied into an internal table as part of the
+ * construction process. The ordering vector should contain the OIDs
+ * in the order they are meant to be encoded or printed in toString.
+ * <p>
+ * The passed in converter will be used to convert the strings into their
+ * ASN.1 counterparts.
+ */
+ public X509Name(
+ Vector ordering,
+ Hashtable attributes,
+ X509NameEntryConverter converter)
+ {
+ this.converter = converter;
+
+ if (ordering != null)
+ {
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ this.ordering.addElement(ordering.elementAt(i));
+ this.added.addElement(FALSE);
+ }
+ }
+ else
+ {
+ Enumeration e = attributes.keys();
+
+ while (e.hasMoreElements())
+ {
+ this.ordering.addElement(e.nextElement());
+ this.added.addElement(FALSE);
+ }
+ }
+
+ for (int i = 0; i != this.ordering.size(); i++)
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)this.ordering.elementAt(i);
+
+ if (attributes.get(oid) == null)
+ {
+ throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name");
+ }
+
+ this.values.addElement(attributes.get(oid)); // copy the hash table
+ }
+ }
+
+ /**
+ * Takes two vectors one of the oids and the other of the values.
+ */
+ public X509Name(
+ Vector oids,
+ Vector values)
+ {
+ this(oids, values, new X509DefaultEntryConverter());
+ }
+
+ /**
+ * Takes two vectors one of the oids and the other of the values.
+ * <p>
+ * The passed in converter will be used to convert the strings into their
+ * ASN.1 counterparts.
+ */
+ public X509Name(
+ Vector oids,
+ Vector values,
+ X509NameEntryConverter converter)
+ {
+ this.converter = converter;
+
+ if (oids.size() != values.size())
+ {
+ throw new IllegalArgumentException("oids vector must be same length as values.");
+ }
+
+ for (int i = 0; i < oids.size(); i++)
+ {
+ this.ordering.addElement(oids.elementAt(i));
+ this.values.addElement(values.elementAt(i));
+ this.added.addElement(FALSE);
+ }
+ }
+
+// private Boolean isEncoded(String s)
+// {
+// if (s.charAt(0) == '#')
+// {
+// return TRUE;
+// }
+//
+// return FALSE;
+// }
+
+ /**
+ * 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.
+ */
+ public X509Name(
+ String dirName)
+ {
+ this(DefaultReverse, DefaultLookUp, dirName);
+ }
+
+ /**
+ * 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 with each
+ * string value being converted to its associated ASN.1 type using the passed
+ * in converter.
+ */
+ public X509Name(
+ String dirName,
+ X509NameEntryConverter converter)
+ {
+ this(DefaultReverse, DefaultLookUp, dirName, converter);
+ }
+
+ /**
+ * 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. If reverse
+ * is true, create the encoded version of the sequence starting from the
+ * last element in the string.
+ */
+ public X509Name(
+ boolean reverse,
+ String dirName)
+ {
+ this(reverse, DefaultLookUp, dirName);
+ }
+
+ /**
+ * 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 with each
+ * string value being converted to its associated ASN.1 type using the passed
+ * in converter. If reverse is true the ASN.1 sequence representing the DN will
+ * be built by starting at the end of the string, rather than the start.
+ */
+ public X509Name(
+ boolean reverse,
+ String dirName,
+ X509NameEntryConverter converter)
+ {
+ this(reverse, DefaultLookUp, dirName, converter);
+ }
+
+ /**
+ * 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 ASN1ObjectIdentifier, other than that OID. and numeric oids
+ * will be processed automatically.
+ * <br>
+ * If reverse is true, create the encoded version of the sequence
+ * starting from the last element in the string.
+ * @param reverse true if we should start scanning from the end (RFC 2553).
+ * @param lookUp table of names and their oids.
+ * @param dirName the X.500 string to be parsed.
+ */
+ public X509Name(
+ boolean reverse,
+ Hashtable lookUp,
+ String dirName)
+ {
+ this(reverse, lookUp, dirName, new X509DefaultEntryConverter());
+ }
+
+ private ASN1ObjectIdentifier decodeOID(
+ String name,
+ Hashtable lookUp)
+ {
+ if (Strings.toUpperCase(name).startsWith("OID."))
+ {
+ return new ASN1ObjectIdentifier(name.substring(4));
+ }
+ else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
+ {
+ return new ASN1ObjectIdentifier(name);
+ }
+
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
+ if (oid == null)
+ {
+ throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+ }
+
+ return oid;
+ }
+
+ /**
+ * 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 ASN1ObjectIdentifier, other than that OID. and numeric oids
+ * will be processed automatically. The passed in converter is used to convert the
+ * string values to the right of each equals sign to their ASN.1 counterparts.
+ * <br>
+ * @param reverse true if we should start scanning from the end, false otherwise.
+ * @param lookUp table of names and oids.
+ * @param dirName the string dirName
+ * @param converter the converter to convert string values into their ASN.1 equivalents
+ */
+ public X509Name(
+ boolean reverse,
+ Hashtable lookUp,
+ String dirName,
+ X509NameEntryConverter converter)
+ {
+ this.converter = converter;
+ X509NameTokenizer nTok = new X509NameTokenizer(dirName);
+
+ while (nTok.hasMoreTokens())
+ {
+ String token = nTok.nextToken();
+ int index = token.indexOf('=');
+
+ if (index == -1)
+ {
+ // BEGIN android-changed
+ throw new IllegalArgumentException("badly formatted directory string");
+ // END android-changed
+ }
+
+ String name = token.substring(0, index);
+ String value = token.substring(index + 1);
+ ASN1ObjectIdentifier oid = decodeOID(name, lookUp);
+
+ if (value.indexOf('+') > 0)
+ {
+ X509NameTokenizer vTok = new X509NameTokenizer(value, '+');
+ String v = vTok.nextToken();
+
+ this.ordering.addElement(oid);
+ this.values.addElement(v);
+ this.added.addElement(FALSE);
+
+ while (vTok.hasMoreTokens())
+ {
+ String sv = vTok.nextToken();
+ int ndx = sv.indexOf('=');
+
+ String nm = sv.substring(0, ndx);
+ String vl = sv.substring(ndx + 1);
+ this.ordering.addElement(decodeOID(nm, lookUp));
+ this.values.addElement(vl);
+ this.added.addElement(TRUE);
+ }
+ }
+ else
+ {
+ this.ordering.addElement(oid);
+ this.values.addElement(value);
+ this.added.addElement(FALSE);
+ }
+ }
+
+ if (reverse)
+ {
+ Vector o = new Vector();
+ Vector v = new Vector();
+ Vector a = new Vector();
+
+ int count = 1;
+
+ for (int i = 0; i < this.ordering.size(); i++)
+ {
+ if (((Boolean)this.added.elementAt(i)).booleanValue())
+ {
+ o.insertElementAt(this.ordering.elementAt(i), count);
+ v.insertElementAt(this.values.elementAt(i), count);
+ a.insertElementAt(this.added.elementAt(i), count);
+ count++;
+ }
+ else
+ {
+ o.insertElementAt(this.ordering.elementAt(i), 0);
+ v.insertElementAt(this.values.elementAt(i), 0);
+ a.insertElementAt(this.added.elementAt(i), 0);
+ count = 1;
+ }
+ }
+
+ this.ordering = o;
+ this.values = v;
+ this.added = a;
+ }
+ }
+
+ /**
+ * return a vector of the oids in the name, in the order they were found.
+ */
+ public Vector getOIDs()
+ {
+ Vector v = new Vector();
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ v.addElement(ordering.elementAt(i));
+ }
+
+ return v;
+ }
+
+ /**
+ * return a vector of the values found in the name, in the order they
+ * were found.
+ */
+ public Vector getValues()
+ {
+ Vector v = new Vector();
+
+ for (int i = 0; i != values.size(); i++)
+ {
+ v.addElement(values.elementAt(i));
+ }
+
+ return v;
+ }
+
+ /**
+ * return a vector of the values found in the name, in the order they
+ * were found, with the DN label corresponding to passed in oid.
+ */
+ public Vector getValues(
+ ASN1ObjectIdentifier oid)
+ {
+ Vector v = new Vector();
+
+ for (int i = 0; i != values.size(); i++)
+ {
+ if (ordering.elementAt(i).equals(oid))
+ {
+ String val = (String)values.elementAt(i);
+
+ if (val.length() > 2 && val.charAt(0) == '\\' && val.charAt(1) == '#')
+ {
+ v.addElement(val.substring(1));
+ }
+ else
+ {
+ v.addElement(val);
+ }
+ }
+ }
+
+ return v;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ if (seq == null)
+ {
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ ASN1EncodableVector sVec = new ASN1EncodableVector();
+ ASN1ObjectIdentifier lstOid = null;
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+
+ v.add(oid);
+
+ String str = (String)values.elementAt(i);
+
+ v.add(converter.getConvertedValue(oid, str));
+
+ if (lstOid == null
+ || ((Boolean)this.added.elementAt(i)).booleanValue())
+ {
+ sVec.add(new DERSequence(v));
+ }
+ else
+ {
+ vec.add(new DERSet(sVec));
+ sVec = new ASN1EncodableVector();
+
+ sVec.add(new DERSequence(v));
+ }
+
+ lstOid = oid;
+ }
+
+ vec.add(new DERSet(sVec));
+
+ seq = new DERSequence(vec);
+ }
+
+ return seq;
+ }
+
+ /**
+ * @param inOrder if true the order of both X509 names must be the same,
+ * as well as the values associated with each element.
+ */
+ public boolean equals(Object obj, boolean inOrder)
+ {
+ if (!inOrder)
+ {
+ return this.equals(obj);
+ }
+
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))
+ {
+ return false;
+ }
+
+ ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
+
+ if (this.toASN1Primitive().equals(derO))
+ {
+ return true;
+ }
+
+ X509Name other;
+
+ try
+ {
+ other = X509Name.getInstance(obj);
+ }
+ catch (IllegalArgumentException e)
+ {
+ return false;
+ }
+
+ int orderingSize = ordering.size();
+
+ if (orderingSize != other.ordering.size())
+ {
+ return false;
+ }
+
+ for (int i = 0; i < orderingSize; i++)
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+ ASN1ObjectIdentifier oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(i);
+
+ if (oid.equals(oOid))
+ {
+ String value = (String)values.elementAt(i);
+ String oValue = (String)other.values.elementAt(i);
+
+ if (!equivalentStrings(value, oValue))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ if (isHashCodeCalculated)
+ {
+ return hashCodeValue;
+ }
+
+ isHashCodeCalculated = true;
+
+ // this needs to be order independent, like equals
+ for (int i = 0; i != ordering.size(); i += 1)
+ {
+ String value = (String)values.elementAt(i);
+
+ value = canonicalize(value);
+ value = stripInternalSpaces(value);
+
+ hashCodeValue ^= ordering.elementAt(i).hashCode();
+ hashCodeValue ^= value.hashCode();
+ }
+
+ return hashCodeValue;
+ }
+
+ /**
+ * test for equality - note: case is ignored.
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))
+ {
+ return false;
+ }
+
+ ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
+
+ if (this.toASN1Primitive().equals(derO))
+ {
+ return true;
+ }
+
+ X509Name other;
+
+ try
+ {
+ other = X509Name.getInstance(obj);
+ }
+ catch (IllegalArgumentException e)
+ {
+ return false;
+ }
+
+ int orderingSize = ordering.size();
+
+ if (orderingSize != other.ordering.size())
+ {
+ return false;
+ }
+
+ boolean[] indexes = new boolean[orderingSize];
+ int start, end, delta;
+
+ if (ordering.elementAt(0).equals(other.ordering.elementAt(0))) // guess forward
+ {
+ start = 0;
+ end = orderingSize;
+ delta = 1;
+ }
+ else // guess reversed - most common problem
+ {
+ start = orderingSize - 1;
+ end = -1;
+ delta = -1;
+ }
+
+ for (int i = start; i != end; i += delta)
+ {
+ boolean found = false;
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i);
+ String value = (String)values.elementAt(i);
+
+ for (int j = 0; j < orderingSize; j++)
+ {
+ if (indexes[j])
+ {
+ continue;
+ }
+
+ ASN1ObjectIdentifier oOid = (ASN1ObjectIdentifier)other.ordering.elementAt(j);
+
+ if (oid.equals(oOid))
+ {
+ String oValue = (String)other.values.elementAt(j);
+
+ if (equivalentStrings(value, oValue))
+ {
+ indexes[j] = true;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private boolean equivalentStrings(String s1, String s2)
+ {
+ String value = canonicalize(s1);
+ String oValue = canonicalize(s2);
+
+ if (!value.equals(oValue))
+ {
+ value = stripInternalSpaces(value);
+ oValue = stripInternalSpaces(oValue);
+
+ if (!value.equals(oValue))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private String canonicalize(String s)
+ {
+ String value = Strings.toLowerCase(s.trim());
+
+ if (value.length() > 0 && value.charAt(0) == '#')
+ {
+ ASN1Primitive obj = decodeObject(value);
+
+ if (obj instanceof ASN1String)
+ {
+ value = Strings.toLowerCase(((ASN1String)obj).getString().trim());
+ }
+ }
+
+ return value;
+ }
+
+ private ASN1Primitive decodeObject(String oValue)
+ {
+ try
+ {
+ return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("unknown encoding in name: " + e);
+ }
+ }
+
+ private String stripInternalSpaces(
+ String str)
+ {
+ StringBuffer res = new StringBuffer();
+
+ if (str.length() != 0)
+ {
+ char c1 = str.charAt(0);
+
+ res.append(c1);
+
+ for (int k = 1; k < str.length(); k++)
+ {
+ char c2 = str.charAt(k);
+ if (!(c1 == ' ' && c2 == ' '))
+ {
+ res.append(c2);
+ }
+ c1 = c2;
+ }
+ }
+
+ return res.toString();
+ }
+
+ private void appendValue(
+ StringBuffer buf,
+ Hashtable oidSymbols,
+ ASN1ObjectIdentifier oid,
+ String value)
+ {
+ String sym = (String)oidSymbols.get(oid);
+
+ if (sym != null)
+ {
+ buf.append(sym);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ }
+
+ buf.append('=');
+
+ int index = buf.length();
+
+ buf.append(value);
+
+ int end = buf.length();
+
+ if (value.length() >= 2 && value.charAt(0) == '\\' && value.charAt(1) == '#')
+ {
+ index += 2;
+ }
+
+ while (index != end)
+ {
+ if ((buf.charAt(index) == ',')
+ || (buf.charAt(index) == '"')
+ || (buf.charAt(index) == '\\')
+ || (buf.charAt(index) == '+')
+ || (buf.charAt(index) == '=')
+ || (buf.charAt(index) == '<')
+ || (buf.charAt(index) == '>')
+ || (buf.charAt(index) == ';'))
+ {
+ buf.insert(index, "\\");
+ index++;
+ end++;
+ }
+
+ index++;
+ }
+ }
+
+ /**
+ * convert the structure to a string - if reverse is true the
+ * oids and values are listed out starting with the last element
+ * in the sequence (ala RFC 2253), otherwise the string will begin
+ * with the first element of the structure. If no string definition
+ * for the oid is found in oidSymbols the string value of the oid is
+ * added. Two standard symbol tables are provided DefaultSymbols, and
+ * RFC2253Symbols as part of this class.
+ *
+ * @param reverse if true start at the end of the sequence and work back.
+ * @param oidSymbols look up table strings for oids.
+ */
+ public String toString(
+ boolean reverse,
+ Hashtable oidSymbols)
+ {
+ StringBuffer buf = new StringBuffer();
+ Vector components = new Vector();
+ boolean first = true;
+
+ StringBuffer ava = null;
+
+ for (int i = 0; i < ordering.size(); i++)
+ {
+ if (((Boolean)added.elementAt(i)).booleanValue())
+ {
+ ava.append('+');
+ appendValue(ava, oidSymbols,
+ (ASN1ObjectIdentifier)ordering.elementAt(i),
+ (String)values.elementAt(i));
+ }
+ else
+ {
+ ava = new StringBuffer();
+ appendValue(ava, oidSymbols,
+ (ASN1ObjectIdentifier)ordering.elementAt(i),
+ (String)values.elementAt(i));
+ components.addElement(ava);
+ }
+ }
+
+ if (reverse)
+ {
+ for (int i = components.size() - 1; i >= 0; i--)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(',');
+ }
+
+ buf.append(components.elementAt(i).toString());
+ }
+ }
+ else
+ {
+ for (int i = 0; i < components.size(); i++)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(',');
+ }
+
+ buf.append(components.elementAt(i).toString());
+ }
+ }
+
+ return buf.toString();
+ }
+
+ private String bytesToString(
+ byte[] data)
+ {
+ char[] cs = new char[data.length];
+
+ for (int i = 0; i != cs.length; i++)
+ {
+ cs[i] = (char)(data[i] & 0xff);
+ }
+
+ return new String(cs);
+ }
+
+ public String toString()
+ {
+ return toString(DefaultReverse, DefaultSymbols);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java
new file mode 100644
index 0000000..5d919e1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameEntryConverter.java
@@ -0,0 +1,113 @@
+package org.bouncycastle.asn1.x509;
+
+import java.io.IOException;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DERPrintableString;
+import org.bouncycastle.util.Strings;
+
+/**
+ * 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 X509Name class
+ * will produce UTF8Strings in line with the current recommendations (RFC 3280).
+ * <p>
+ * An example of an encoder look like below:
+ * <pre>
+ * public class X509DirEntryConverter
+ * extends X509NameEntryConverter
+ * {
+ * public ASN1Primitive getConvertedValue(
+ * ASN1ObjectIdentifier oid,
+ * String value)
+ * {
+ * if (str.length() != 0 && str.charAt(0) == '#')
+ * {
+ * return convertHexEncoded(str, 1);
+ * }
+ * if (oid.equals(EmailAddress))
+ * {
+ * return new DERIA5String(str);
+ * }
+ * else if (canBePrintable(str))
+ * {
+ * return new DERPrintableString(str);
+ * }
+ * else if (canBeUTF8(str))
+ * {
+ * return new DERUTF8String(str);
+ * }
+ * else
+ * {
+ * return new DERBMPString(str);
+ * }
+ * }
+ * }
+ */
+public abstract class X509NameEntryConverter
+{
+ /**
+ * Convert an inline encoded hex string rendition of an ASN.1
+ * object back into its corresponding ASN.1 object.
+ *
+ * @param str the hex encoded object
+ * @param off the index at which the encoding starts
+ * @return the decoded object
+ */
+ protected ASN1Primitive convertHexEncoded(
+ String str,
+ int off)
+ throws IOException
+ {
+ str = Strings.toLowerCase(str);
+ byte[] data = new byte[(str.length() - off) / 2];
+ for (int index = 0; index != data.length; index++)
+ {
+ char left = str.charAt((index * 2) + off);
+ char right = str.charAt((index * 2) + off + 1);
+
+ if (left < 'a')
+ {
+ data[index] = (byte)((left - '0') << 4);
+ }
+ else
+ {
+ data[index] = (byte)((left - 'a' + 10) << 4);
+ }
+ if (right < 'a')
+ {
+ data[index] |= (byte)(right - '0');
+ }
+ else
+ {
+ data[index] |= (byte)(right - 'a' + 10);
+ }
+ }
+
+ ASN1InputStream aIn = new ASN1InputStream(data);
+
+ return aIn.readObject();
+ }
+
+ /**
+ * return true if the passed in String can be represented without
+ * loss as a PrintableString, false otherwise.
+ */
+ protected boolean canBePrintable(
+ String str)
+ {
+ return DERPrintableString.isPrintableString(str);
+ }
+
+ /**
+ * Convert the passed in String value into the appropriate ASN.1
+ * encoded object.
+ *
+ * @param oid the oid associated with the value in the DN.
+ * @param value the value of the particular DN component.
+ * @return the ASN.1 equivalent for the value.
+ */
+ public abstract ASN1Primitive getConvertedValue(ASN1ObjectIdentifier oid, String value);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java
new file mode 100644
index 0000000..32e9346
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java
@@ -0,0 +1,110 @@
+package org.bouncycastle.asn1.x509;
+
+/**
+ * class for breaking up an X500 Name 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.
+ */
+public class X509NameTokenizer
+{
+ private String value;
+ private int index;
+ private char seperator;
+ private StringBuffer buf = new StringBuffer();
+
+ public X509NameTokenizer(
+ String oid)
+ {
+ this(oid, ',');
+ }
+
+ public X509NameTokenizer(
+ String oid,
+ char seperator)
+ {
+ this.value = oid;
+ this.index = -1;
+ this.seperator = seperator;
+ }
+
+ public boolean hasMoreTokens()
+ {
+ return (index != value.length());
+ }
+
+ public String nextToken()
+ {
+ if (index == value.length())
+ {
+ return null;
+ }
+
+ int end = index + 1;
+ boolean quoted = false;
+ boolean escaped = false;
+
+ buf.setLength(0);
+
+ while (end != value.length())
+ {
+ char c = value.charAt(end);
+
+ if (c == '"')
+ {
+ if (!escaped)
+ {
+ quoted = !quoted;
+ }
+ else
+ {
+ // BEGIN android-added
+ // copied from a newer version of BouncyCastle
+ if (c == '#' && buf.charAt(buf.length() - 1) == '=')
+ {
+ buf.append('\\');
+ }
+ else if (c == '+' && seperator != '+')
+ {
+ buf.append('\\');
+ }
+ // END android-added
+ buf.append(c);
+ }
+ escaped = false;
+ }
+ else
+ {
+ if (escaped || quoted)
+ {
+ if (c == '#' && buf.charAt(buf.length() - 1) == '=')
+ {
+ buf.append('\\');
+ }
+ else if (c == '+' && seperator != '+')
+ {
+ buf.append('\\');
+ }
+ buf.append(c);
+ escaped = false;
+ }
+ else if (c == '\\')
+ {
+ escaped = true;
+ }
+ else if (c == seperator)
+ {
+ break;
+ }
+ else
+ {
+ buf.append(c);
+ }
+ }
+ end++;
+ }
+
+ index = end;
+ return buf.toString().trim();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
new file mode 100644
index 0000000..ed4dd32
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java
@@ -0,0 +1,67 @@
+package org.bouncycastle.asn1.x509;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface X509ObjectIdentifiers
+{
+ //
+ // base id
+ //
+ static final String id = "2.5.4";
+
+ static final ASN1ObjectIdentifier commonName = new ASN1ObjectIdentifier(id + ".3");
+ static final ASN1ObjectIdentifier countryName = new ASN1ObjectIdentifier(id + ".6");
+ static final ASN1ObjectIdentifier localityName = new ASN1ObjectIdentifier(id + ".7");
+ static final ASN1ObjectIdentifier stateOrProvinceName = new ASN1ObjectIdentifier(id + ".8");
+ static final ASN1ObjectIdentifier organization = new ASN1ObjectIdentifier(id + ".10");
+ static final ASN1ObjectIdentifier organizationalUnitName = new ASN1ObjectIdentifier(id + ".11");
+
+ static final ASN1ObjectIdentifier id_at_telephoneNumber = new ASN1ObjectIdentifier("2.5.4.20");
+ static final ASN1ObjectIdentifier id_at_name = new ASN1ObjectIdentifier(id + ".41");
+
+ // id-SHA1 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } //
+ static final ASN1ObjectIdentifier id_SHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26");
+
+ //
+ // ripemd160 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) hashAlgorithm(2) RIPEMD-160(1)}
+ //
+ static final ASN1ObjectIdentifier ripemd160 = new ASN1ObjectIdentifier("1.3.36.3.2.1");
+
+ //
+ // ripemd160WithRSAEncryption OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) TeleTrust(36) algorithm(3) signatureAlgorithm(3) rsaSignature(1) rsaSignatureWithripemd160(2) }
+ //
+ static final ASN1ObjectIdentifier ripemd160WithRSAEncryption = new ASN1ObjectIdentifier("1.3.36.3.3.1.2");
+
+
+ static final ASN1ObjectIdentifier id_ea_rsa = new ASN1ObjectIdentifier("2.5.8.1.1");
+
+ // id-pkix
+ static final ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7");
+
+ //
+ // private internet extensions
+ //
+ static final ASN1ObjectIdentifier id_pe = new ASN1ObjectIdentifier(id_pkix + ".1");
+
+ //
+ // ISO ARC for standard certificate and CRL extensions
+ //
+ static final ASN1ObjectIdentifier id_ce = new ASN1ObjectIdentifier("2.5.29");
+
+ //
+ // authority information access
+ //
+ static final ASN1ObjectIdentifier id_ad = new ASN1ObjectIdentifier(id_pkix + ".48");
+ static final ASN1ObjectIdentifier id_ad_caIssuers = new ASN1ObjectIdentifier(id_ad + ".2");
+ static final ASN1ObjectIdentifier id_ad_ocsp = new ASN1ObjectIdentifier(id_ad + ".1");
+
+ //
+ // OID for ocsp and crl uri in AuthorityInformationAccess extension
+ //
+ static final ASN1ObjectIdentifier ocspAccessMethod = id_ad_ocsp;
+ static final ASN1ObjectIdentifier crlAccessMethod = id_ad_caIssuers;
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
new file mode 100644
index 0000000..6a97a48
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java
@@ -0,0 +1,139 @@
+package org.bouncycastle.asn1.x9;
+
+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;
+
+public class DHDomainParameters
+ extends ASN1Object
+{
+ private ASN1Integer p, g, q, j;
+ private DHValidationParms validationParms;
+
+ public static DHDomainParameters getInstance(ASN1TaggedObject obj, boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static DHDomainParameters getInstance(Object obj)
+ {
+ if (obj == null || obj instanceof DHDomainParameters)
+ {
+ return (DHDomainParameters)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new DHDomainParameters((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid DHDomainParameters: "
+ + obj.getClass().getName());
+ }
+
+ public DHDomainParameters(ASN1Integer p, ASN1Integer g, ASN1Integer q, ASN1Integer 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 = p;
+ this.g = g;
+ this.q = q;
+ this.j = j;
+ this.validationParms = validationParms;
+ }
+
+ private DHDomainParameters(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);
+ }
+
+ if (next != null)
+ {
+ this.validationParms = DHValidationParms.getInstance(next.toASN1Primitive());
+ }
+ }
+
+ private static ASN1Encodable getNext(Enumeration e)
+ {
+ return e.hasMoreElements() ? (ASN1Encodable)e.nextElement() : null;
+ }
+
+ public ASN1Integer getP()
+ {
+ return this.p;
+ }
+
+ public ASN1Integer getG()
+ {
+ return this.g;
+ }
+
+ public ASN1Integer getQ()
+ {
+ return this.q;
+ }
+
+ public ASN1Integer getJ()
+ {
+ return this.j;
+ }
+
+ public DHValidationParms getValidationParms()
+ {
+ return this.validationParms;
+ }
+
+ 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.validationParms != null)
+ {
+ v.add(this.validationParms);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java
new file mode 100644
index 0000000..7c6d217
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHPublicKey.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+
+public class DHPublicKey
+ extends ASN1Object
+{
+ private ASN1Integer y;
+
+ public static DHPublicKey getInstance(ASN1TaggedObject obj, boolean explicit)
+ {
+ return getInstance(ASN1Integer.getInstance(obj, explicit));
+ }
+
+ public static DHPublicKey getInstance(Object obj)
+ {
+ if (obj == null || obj instanceof DHPublicKey)
+ {
+ return (DHPublicKey)obj;
+ }
+
+ if (obj instanceof ASN1Integer)
+ {
+ return new DHPublicKey((ASN1Integer)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid DHPublicKey: " + obj.getClass().getName());
+ }
+
+ public DHPublicKey(ASN1Integer y)
+ {
+ if (y == null)
+ {
+ throw new IllegalArgumentException("'y' cannot be null");
+ }
+
+ this.y = y;
+ }
+
+ public ASN1Integer getY()
+ {
+ return this.y;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return this.y;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java
new file mode 100644
index 0000000..78b0979
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/DHValidationParms.java
@@ -0,0 +1,80 @@
+package org.bouncycastle.asn1.x9;
+
+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;
+
+public class DHValidationParms extends ASN1Object
+{
+ private DERBitString seed;
+ private ASN1Integer pgenCounter;
+
+ public static DHValidationParms getInstance(ASN1TaggedObject obj, boolean explicit)
+ {
+ return getInstance(ASN1Sequence.getInstance(obj, explicit));
+ }
+
+ public static DHValidationParms getInstance(Object obj)
+ {
+ if (obj == null || obj instanceof DHDomainParameters)
+ {
+ return (DHValidationParms)obj;
+ }
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new DHValidationParms((ASN1Sequence)obj);
+ }
+
+ throw new IllegalArgumentException("Invalid DHValidationParms: " + obj.getClass().getName());
+ }
+
+ public DHValidationParms(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 DHValidationParms(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 DERBitString getSeed()
+ {
+ return this.seed;
+ }
+
+ public ASN1Integer getPgenCounter()
+ {
+ return this.pgenCounter;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ v.add(this.seed);
+ v.add(this.pgenCounter);
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
new file mode 100644
index 0000000..06e47b6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962NamedCurves.java
@@ -0,0 +1,621 @@
+package org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+
+/**
+ * table of the current named curves defined in X.962 EC-DSA.
+ */
+public class X962NamedCurves
+{
+ static X9ECParametersHolder prime192v1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ ECCurve cFp192v1 = new ECCurve.Fp(
+ new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+ new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+ new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16));
+
+ return new X9ECParameters(
+ cFp192v1,
+ cFp192v1.decodePoint(
+ Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")),
+ new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16),
+ BigInteger.valueOf(1),
+ Hex.decode("3045AE6FC8422f64ED579528D38120EAE12196D5"));
+ }
+ };
+
+ static X9ECParametersHolder prime192v2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ ECCurve cFp192v2 = new ECCurve.Fp(
+ new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+ new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+ new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16));
+
+ return new X9ECParameters(
+ cFp192v2,
+ cFp192v2.decodePoint(
+ Hex.decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")),
+ new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16),
+ BigInteger.valueOf(1),
+ Hex.decode("31a92ee2029fd10d901b113e990710f0d21ac6b6"));
+ }
+ };
+
+ static X9ECParametersHolder prime192v3 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ ECCurve cFp192v3 = new ECCurve.Fp(
+ new BigInteger("6277101735386680763835789423207666416083908700390324961279"),
+ new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16),
+ new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16));
+
+ return new X9ECParameters(
+ cFp192v3,
+ cFp192v3.decodePoint(
+ Hex.decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")),
+ new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16),
+ BigInteger.valueOf(1),
+ Hex.decode("c469684435deb378c4b65ca9591e2a5763059a2e"));
+ }
+ };
+
+ static X9ECParametersHolder prime239v1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ ECCurve cFp239v1 = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+ new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16));
+
+ return new X9ECParameters(
+ cFp239v1,
+ cFp239v1.decodePoint(
+ Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")),
+ new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16),
+ BigInteger.valueOf(1),
+ Hex.decode("e43bb460f0b80cc0c0b075798e948060f8321b7d"));
+ }
+ };
+
+ static X9ECParametersHolder prime239v2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ ECCurve cFp239v2 = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+ new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16));
+
+ return new X9ECParameters(
+ cFp239v2,
+ cFp239v2.decodePoint(
+ Hex.decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")),
+ new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16),
+ BigInteger.valueOf(1),
+ Hex.decode("e8b4011604095303ca3b8099982be09fcb9ae616"));
+ }
+ };
+
+ static X9ECParametersHolder prime239v3 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ ECCurve cFp239v3 = new ECCurve.Fp(
+ new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"),
+ new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16),
+ new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16));
+
+ return new X9ECParameters(
+ cFp239v3,
+ cFp239v3.decodePoint(
+ Hex.decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")),
+ new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16),
+ BigInteger.valueOf(1),
+ Hex.decode("7d7374168ffe3471b60a857686a19475d3bfa2ff"));
+ }
+ };
+
+ static X9ECParametersHolder prime256v1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ ECCurve cFp256v1 = new ECCurve.Fp(
+ new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"),
+ new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16),
+ new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16));
+
+ return new X9ECParameters(
+ cFp256v1,
+ cFp256v1.decodePoint(
+ Hex.decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")),
+ new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16),
+ BigInteger.valueOf(1),
+ Hex.decode("c49d360886e704936a6678e1139d26b7819f7e90"));
+ }
+ };
+
+ /*
+ * F2m Curves
+ */
+ static X9ECParametersHolder c2pnb163v1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m163v1n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16);
+ BigInteger c2m163v1h = BigInteger.valueOf(2);
+
+ ECCurve c2m163v1 = new ECCurve.F2m(
+ 163,
+ 1, 2, 8,
+ new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16),
+ new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16),
+ c2m163v1n, c2m163v1h);
+
+ return new X9ECParameters(
+ c2m163v1,
+ c2m163v1.decodePoint(
+ Hex.decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")),
+ c2m163v1n, c2m163v1h,
+ Hex.decode("D2COFB15760860DEF1EEF4D696E6768756151754"));
+ }
+ };
+
+ static X9ECParametersHolder c2pnb163v2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m163v2n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16);
+ BigInteger c2m163v2h = BigInteger.valueOf(2);
+
+ ECCurve c2m163v2 = new ECCurve.F2m(
+ 163,
+ 1, 2, 8,
+ new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16),
+ new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16),
+ c2m163v2n, c2m163v2h);
+
+ return new X9ECParameters(
+ c2m163v2,
+ c2m163v2.decodePoint(
+ Hex.decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")),
+ c2m163v2n, c2m163v2h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2pnb163v3 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m163v3n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16);
+ BigInteger c2m163v3h = BigInteger.valueOf(2);
+
+ ECCurve c2m163v3 = new ECCurve.F2m(
+ 163,
+ 1, 2, 8,
+ new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16),
+ new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16),
+ c2m163v3n, c2m163v3h);
+
+ return new X9ECParameters(
+ c2m163v3,
+ c2m163v3.decodePoint(
+ Hex.decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
+ c2m163v3n, c2m163v3h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2pnb176w1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m176w1n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16);
+ BigInteger c2m176w1h = BigInteger.valueOf(0xFF6E);
+
+ ECCurve c2m176w1 = new ECCurve.F2m(
+ 176,
+ 1, 2, 43,
+ new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16),
+ new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16),
+ c2m176w1n, c2m176w1h);
+
+ return new X9ECParameters(
+ c2m176w1,
+ c2m176w1.decodePoint(
+ Hex.decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")),
+ c2m176w1n, c2m176w1h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2tnb191v1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m191v1n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16);
+ BigInteger c2m191v1h = BigInteger.valueOf(2);
+
+ ECCurve c2m191v1 = new ECCurve.F2m(
+ 191,
+ 9,
+ new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16),
+ new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16),
+ c2m191v1n, c2m191v1h);
+
+ return new X9ECParameters(
+ c2m191v1,
+ c2m191v1.decodePoint(
+ Hex.decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")),
+ c2m191v1n, c2m191v1h,
+ Hex.decode("4E13CA542744D696E67687561517552F279A8C84"));
+ }
+ };
+
+ static X9ECParametersHolder c2tnb191v2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m191v2n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16);
+ BigInteger c2m191v2h = BigInteger.valueOf(4);
+
+ ECCurve c2m191v2 = new ECCurve.F2m(
+ 191,
+ 9,
+ new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16),
+ new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16),
+ c2m191v2n, c2m191v2h);
+
+ return new X9ECParameters(
+ c2m191v2,
+ c2m191v2.decodePoint(
+ Hex.decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")),
+ c2m191v2n, c2m191v2h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2tnb191v3 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m191v3n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16);
+ BigInteger c2m191v3h = BigInteger.valueOf(6);
+
+ ECCurve c2m191v3 = new ECCurve.F2m(
+ 191,
+ 9,
+ new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16),
+ new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16),
+ c2m191v3n, c2m191v3h);
+
+ return new X9ECParameters(
+ c2m191v3,
+ c2m191v3.decodePoint(
+ Hex.decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")),
+ c2m191v3n, c2m191v3h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2pnb208w1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m208w1n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16);
+ BigInteger c2m208w1h = BigInteger.valueOf(0xFE48);
+
+ ECCurve c2m208w1 = new ECCurve.F2m(
+ 208,
+ 1, 2, 83,
+ new BigInteger("0", 16),
+ new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16),
+ c2m208w1n, c2m208w1h);
+
+ return new X9ECParameters(
+ c2m208w1,
+ c2m208w1.decodePoint(
+ Hex.decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")),
+ c2m208w1n, c2m208w1h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2tnb239v1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m239v1n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16);
+ BigInteger c2m239v1h = BigInteger.valueOf(4);
+
+ ECCurve c2m239v1 = new ECCurve.F2m(
+ 239,
+ 36,
+ new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16),
+ new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16),
+ c2m239v1n, c2m239v1h);
+
+ return new X9ECParameters(
+ c2m239v1,
+ c2m239v1.decodePoint(
+ Hex.decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")),
+ c2m239v1n, c2m239v1h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2tnb239v2 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m239v2n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16);
+ BigInteger c2m239v2h = BigInteger.valueOf(6);
+
+ ECCurve c2m239v2 = new ECCurve.F2m(
+ 239,
+ 36,
+ new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16),
+ new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16),
+ c2m239v2n, c2m239v2h);
+
+ return new X9ECParameters(
+ c2m239v2,
+ c2m239v2.decodePoint(
+ Hex.decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")),
+ c2m239v2n, c2m239v2h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2tnb239v3 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m239v3n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16);
+ BigInteger c2m239v3h = BigInteger.valueOf(10);
+
+ ECCurve c2m239v3 = new ECCurve.F2m(
+ 239,
+ 36,
+ new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16),
+ new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16),
+ c2m239v3n, c2m239v3h);
+
+ return new X9ECParameters(
+ c2m239v3,
+ c2m239v3.decodePoint(
+ Hex.decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")),
+ c2m239v3n, c2m239v3h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2pnb272w1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m272w1n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16);
+ BigInteger c2m272w1h = BigInteger.valueOf(0xFF06);
+
+ ECCurve c2m272w1 = new ECCurve.F2m(
+ 272,
+ 1, 3, 56,
+ new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16),
+ new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16),
+ c2m272w1n, c2m272w1h);
+
+ return new X9ECParameters(
+ c2m272w1,
+ c2m272w1.decodePoint(
+ Hex.decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")),
+ c2m272w1n, c2m272w1h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2pnb304w1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m304w1n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16);
+ BigInteger c2m304w1h = BigInteger.valueOf(0xFE2E);
+
+ ECCurve c2m304w1 = new ECCurve.F2m(
+ 304,
+ 1, 2, 11,
+ new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16),
+ new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16),
+ c2m304w1n, c2m304w1h);
+
+ return new X9ECParameters(
+ c2m304w1,
+ c2m304w1.decodePoint(
+ Hex.decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")),
+ c2m304w1n, c2m304w1h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2tnb359v1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m359v1n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16);
+ BigInteger c2m359v1h = BigInteger.valueOf(0x4C);
+
+ ECCurve c2m359v1 = new ECCurve.F2m(
+ 359,
+ 68,
+ new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16),
+ new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16),
+ c2m359v1n, c2m359v1h);
+
+ return new X9ECParameters(
+ c2m359v1,
+ c2m359v1.decodePoint(
+ Hex.decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")),
+ c2m359v1n, c2m359v1h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2pnb368w1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m368w1n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16);
+ BigInteger c2m368w1h = BigInteger.valueOf(0xFF70);
+
+ ECCurve c2m368w1 = new ECCurve.F2m(
+ 368,
+ 1, 2, 85,
+ new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16),
+ new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16),
+ c2m368w1n, c2m368w1h);
+
+ return new X9ECParameters(
+ c2m368w1,
+ c2m368w1.decodePoint(
+ Hex.decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")),
+ c2m368w1n, c2m368w1h,
+ null);
+ }
+ };
+
+ static X9ECParametersHolder c2tnb431r1 = new X9ECParametersHolder()
+ {
+ protected X9ECParameters createParameters()
+ {
+ BigInteger c2m431r1n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16);
+ BigInteger c2m431r1h = BigInteger.valueOf(0x2760);
+
+ ECCurve c2m431r1 = new ECCurve.F2m(
+ 431,
+ 120,
+ new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16),
+ new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16),
+ c2m431r1n, c2m431r1h);
+
+ return new X9ECParameters(
+ c2m431r1,
+ c2m431r1.decodePoint(
+ Hex.decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")),
+ c2m431r1n, c2m431r1h,
+ null);
+ }
+ };
+
+ static final Hashtable objIds = new Hashtable();
+ static final Hashtable curves = new Hashtable();
+ static final Hashtable names = new Hashtable();
+
+ static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder)
+ {
+ objIds.put(name, oid);
+ names.put(oid, name);
+ curves.put(oid, holder);
+ }
+
+ static
+ {
+ defineCurve("prime192v1", X9ObjectIdentifiers.prime192v1, prime192v1);
+ defineCurve("prime192v2", X9ObjectIdentifiers.prime192v2, prime192v2);
+ defineCurve("prime192v3", X9ObjectIdentifiers.prime192v3, prime192v3);
+ defineCurve("prime239v1", X9ObjectIdentifiers.prime239v1, prime239v1);
+ defineCurve("prime239v2", X9ObjectIdentifiers.prime239v2, prime239v2);
+ defineCurve("prime239v3", X9ObjectIdentifiers.prime239v3, prime239v3);
+ defineCurve("prime256v1", X9ObjectIdentifiers.prime256v1, prime256v1);
+ defineCurve("c2pnb163v1", X9ObjectIdentifiers.c2pnb163v1, c2pnb163v1);
+ defineCurve("c2pnb163v2", X9ObjectIdentifiers.c2pnb163v2, c2pnb163v2);
+ defineCurve("c2pnb163v3", X9ObjectIdentifiers.c2pnb163v3, c2pnb163v3);
+ defineCurve("c2pnb176w1", X9ObjectIdentifiers.c2pnb176w1, c2pnb176w1);
+ defineCurve("c2tnb191v1", X9ObjectIdentifiers.c2tnb191v1, c2tnb191v1);
+ defineCurve("c2tnb191v2", X9ObjectIdentifiers.c2tnb191v2, c2tnb191v2);
+ defineCurve("c2tnb191v3", X9ObjectIdentifiers.c2tnb191v3, c2tnb191v3);
+ defineCurve("c2pnb208w1", X9ObjectIdentifiers.c2pnb208w1, c2pnb208w1);
+ defineCurve("c2tnb239v1", X9ObjectIdentifiers.c2tnb239v1, c2tnb239v1);
+ defineCurve("c2tnb239v2", X9ObjectIdentifiers.c2tnb239v2, c2tnb239v2);
+ defineCurve("c2tnb239v3", X9ObjectIdentifiers.c2tnb239v3, c2tnb239v3);
+ defineCurve("c2pnb272w1", X9ObjectIdentifiers.c2pnb272w1, c2pnb272w1);
+ defineCurve("c2pnb304w1", X9ObjectIdentifiers.c2pnb304w1, c2pnb304w1);
+ defineCurve("c2tnb359v1", X9ObjectIdentifiers.c2tnb359v1, c2tnb359v1);
+ defineCurve("c2pnb368w1", X9ObjectIdentifiers.c2pnb368w1, c2pnb368w1);
+ defineCurve("c2tnb431r1", X9ObjectIdentifiers.c2tnb431r1, c2tnb431r1);
+ }
+
+ public static X9ECParameters getByName(
+ String name)
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name));
+
+ if (oid != null)
+ {
+ return getByOID(oid);
+ }
+
+ return null;
+ }
+
+ /**
+ * 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)curves.get(oid);
+
+ if (holder != null)
+ {
+ return holder.getParameters();
+ }
+
+ return null;
+ }
+
+ /**
+ * 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)objIds.get(Strings.toLowerCase(name));
+ }
+
+ /**
+ * return the named curve name represented by the given object identifier.
+ */
+ public static String getName(
+ ASN1ObjectIdentifier oid)
+ {
+ return (String)names.get(oid);
+ }
+
+ /**
+ * returns an enumeration containing the name strings for curves
+ * contained in this structure.
+ */
+ public static Enumeration getNames()
+ {
+ return objIds.keys();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
new file mode 100644
index 0000000..1c395d2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X962Parameters.java
@@ -0,0 +1,86 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1Choice;
+import org.bouncycastle.asn1.ASN1Null;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+
+public class X962Parameters
+ extends ASN1Object
+ implements ASN1Choice
+{
+ private ASN1Primitive params = null;
+
+ public static X962Parameters getInstance(
+ Object obj)
+ {
+ if (obj == null || obj instanceof X962Parameters)
+ {
+ return (X962Parameters)obj;
+ }
+
+ if (obj instanceof ASN1Primitive)
+ {
+ return new X962Parameters((ASN1Primitive)obj);
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance()");
+ }
+
+ public static X962Parameters getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit)
+ {
+ return getInstance(obj.getObject()); // must be explicitly tagged
+ }
+
+ public X962Parameters(
+ X9ECParameters ecParameters)
+ {
+ this.params = ecParameters.toASN1Primitive();
+ }
+
+ public X962Parameters(
+ ASN1ObjectIdentifier namedCurve)
+ {
+ this.params = namedCurve;
+ }
+
+ public X962Parameters(
+ ASN1Primitive obj)
+ {
+ this.params = obj;
+ }
+
+ public boolean isNamedCurve()
+ {
+ return (params instanceof ASN1ObjectIdentifier);
+ }
+
+ public boolean isImplicitlyCA()
+ {
+ return (params instanceof ASN1Null);
+ }
+
+ public ASN1Primitive getParameters()
+ {
+ return params;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * Parameters ::= CHOICE {
+ * ecParameters ECParameters,
+ * namedCurve CURVES.&id({CurveNames}),
+ * implicitlyCA NULL
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return (ASN1Primitive)params;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java
new file mode 100644
index 0000000..5c5afdb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java
@@ -0,0 +1,161 @@
+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.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+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.ECCurve;
+
+/**
+ * ASN.1 def for Elliptic-Curve Curve structure. See
+ * X9.62, for further details.
+ */
+public class X9Curve
+ extends ASN1Object
+ implements X9ObjectIdentifiers
+{
+ private ECCurve curve;
+ private byte[] seed;
+ private ASN1ObjectIdentifier fieldIdentifier = null;
+
+ public X9Curve(
+ ECCurve curve)
+ {
+ this.curve = curve;
+ this.seed = null;
+ setFieldIdentifier();
+ }
+
+ public X9Curve(
+ ECCurve curve,
+ byte[] seed)
+ {
+ this.curve = curve;
+ this.seed = seed;
+ setFieldIdentifier();
+ }
+
+ public X9Curve(
+ X9FieldID fieldID,
+ ASN1Sequence seq)
+ {
+ fieldIdentifier = fieldID.getIdentifier();
+ if (fieldIdentifier.equals(prime_field))
+ {
+ BigInteger p = ((ASN1Integer)fieldID.getParameters()).getValue();
+ X9FieldElement x9A = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(0));
+ X9FieldElement x9B = new X9FieldElement(p, (ASN1OctetString)seq.getObjectAt(1));
+ curve = new ECCurve.Fp(p, x9A.getValue().toBigInteger(), x9B.getValue().toBigInteger());
+ }
+ else
+ {
+ if (fieldIdentifier.equals(characteristic_two_field))
+ {
+ // Characteristic two field
+ ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters());
+ int m = ((ASN1Integer)parameters.getObjectAt(0)).getValue().
+ intValue();
+ ASN1ObjectIdentifier representation
+ = (ASN1ObjectIdentifier)parameters.getObjectAt(1);
+
+ int k1 = 0;
+ int k2 = 0;
+ int k3 = 0;
+ if (representation.equals(tpBasis))
+ {
+ // Trinomial basis representation
+ k1 = ((ASN1Integer)parameters.getObjectAt(2)).getValue().
+ intValue();
+ }
+ else
+ {
+ // Pentanomial basis representation
+ DERSequence pentanomial
+ = (DERSequence)parameters.getObjectAt(2);
+ k1 = ((ASN1Integer)pentanomial.getObjectAt(0)).getValue().
+ intValue();
+ k2 = ((ASN1Integer)pentanomial.getObjectAt(1)).getValue().
+ intValue();
+ k3 = ((ASN1Integer)pentanomial.getObjectAt(2)).getValue().
+ intValue();
+ }
+ 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());
+ }
+ }
+
+ if (seq.size() == 3)
+ {
+ seed = ((DERBitString)seq.getObjectAt(2)).getBytes();
+ }
+ }
+
+ private void setFieldIdentifier()
+ {
+ if (curve instanceof ECCurve.Fp)
+ {
+ fieldIdentifier = prime_field;
+ }
+ else if (curve instanceof ECCurve.F2m)
+ {
+ fieldIdentifier = characteristic_two_field;
+ }
+ else
+ {
+ throw new IllegalArgumentException("This type of ECCurve is not "
+ + "implemented");
+ }
+ }
+
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * Curve ::= SEQUENCE {
+ * a FieldElement,
+ * b FieldElement,
+ * seed BIT STRING OPTIONAL
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (fieldIdentifier.equals(prime_field))
+ {
+ v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
+ v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
+ }
+ else if (fieldIdentifier.equals(characteristic_two_field))
+ {
+ v.add(new X9FieldElement(curve.getA()).toASN1Primitive());
+ v.add(new X9FieldElement(curve.getB()).toASN1Primitive());
+ }
+
+ if (seed != null)
+ {
+ v.add(new DERBitString(seed));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
new file mode 100644
index 0000000..e059089
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
@@ -0,0 +1,176 @@
+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.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * ASN.1 def for Elliptic-Curve ECParameters structure. See
+ * X9.62, for further details.
+ */
+public class X9ECParameters
+ extends ASN1Object
+ implements X9ObjectIdentifiers
+{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
+ private X9FieldID fieldID;
+ private ECCurve curve;
+ private ECPoint g;
+ private BigInteger n;
+ private BigInteger h;
+ private byte[] seed;
+
+ private X9ECParameters(
+ ASN1Sequence seq)
+ {
+ if (!(seq.getObjectAt(0) instanceof ASN1Integer)
+ || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE))
+ {
+ throw new IllegalArgumentException("bad version in X9ECParameters");
+ }
+
+ X9Curve x9c = new X9Curve(
+ new X9FieldID((ASN1Sequence)seq.getObjectAt(1)),
+ (ASN1Sequence)seq.getObjectAt(2));
+
+ this.curve = x9c.getCurve();
+ this.g = new X9ECPoint(curve, (ASN1OctetString)seq.getObjectAt(3)).getPoint();
+ this.n = ((ASN1Integer)seq.getObjectAt(4)).getValue();
+ this.seed = x9c.getSeed();
+
+ if (seq.size() == 6)
+ {
+ this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue();
+ }
+ }
+
+ public static X9ECParameters getInstance(Object obj)
+ {
+ if (obj instanceof X9ECParameters)
+ {
+ return (X9ECParameters)obj;
+ }
+
+ if (obj != null)
+ {
+ return new X9ECParameters(ASN1Sequence.getInstance(obj));
+ }
+
+ return null;
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n)
+ {
+ this(curve, g, n, ONE, null);
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ {
+ this(curve, g, n, h, null);
+ }
+
+ public X9ECParameters(
+ ECCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ this.curve = curve;
+ this.g = g;
+ this.n = n;
+ this.h = h;
+ this.seed = seed;
+
+ if (curve instanceof ECCurve.Fp)
+ {
+ this.fieldID = new X9FieldID(((ECCurve.Fp)curve).getQ());
+ }
+ else
+ {
+ if (curve instanceof ECCurve.F2m)
+ {
+ ECCurve.F2m curveF2m = (ECCurve.F2m)curve;
+ this.fieldID = new X9FieldID(curveF2m.getM(), curveF2m.getK1(),
+ curveF2m.getK2(), curveF2m.getK3());
+ }
+ }
+ }
+
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ public ECPoint getG()
+ {
+ return g;
+ }
+
+ public BigInteger getN()
+ {
+ return n;
+ }
+
+ public BigInteger getH()
+ {
+ if (h == null)
+ {
+ return ONE; // TODO - this should be calculated, it will cause issues with custom curves.
+ }
+
+ return h;
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * ECParameters ::= SEQUENCE {
+ * version INTEGER { ecpVer1(1) } (ecpVer1),
+ * fieldID FieldID {{FieldTypes}},
+ * curve X9Curve,
+ * base X9ECPoint,
+ * order INTEGER,
+ * cofactor INTEGER OPTIONAL
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new ASN1Integer(1));
+ v.add(fieldID);
+ v.add(new X9Curve(curve, seed));
+ v.add(new X9ECPoint(g));
+ v.add(new ASN1Integer(n));
+
+ if (h != null)
+ {
+ v.add(new ASN1Integer(h));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java
new file mode 100644
index 0000000..47361f8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECParametersHolder.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.asn1.x9;
+
+public abstract class X9ECParametersHolder
+{
+ private X9ECParameters params;
+
+ public X9ECParameters getParameters()
+ {
+ if (params == null)
+ {
+ params = createParameters();
+ }
+
+ return params;
+ }
+
+ protected abstract X9ECParameters createParameters();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
new file mode 100644
index 0000000..a4acb6e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ECPoint.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * class for describing an ECPoint as a DER object.
+ */
+public class X9ECPoint
+ extends ASN1Object
+{
+ ECPoint p;
+
+ public X9ECPoint(
+ ECPoint p)
+ {
+ this.p = p;
+ }
+
+ public X9ECPoint(
+ ECCurve c,
+ ASN1OctetString s)
+ {
+ this.p = c.decodePoint(s.getOctets());
+ }
+
+ public ECPoint getPoint()
+ {
+ return p;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * ECPoint ::= OCTET STRING
+ * </pre>
+ * <p>
+ * Octet string produced using ECPoint.getEncoded().
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ return new DEROctetString(p.getEncoded());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java
new file mode 100644
index 0000000..13fe772
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldElement.java
@@ -0,0 +1,64 @@
+package org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.math.ec.ECFieldElement;
+
+/**
+ * class for processing an FieldElement as a DER object.
+ */
+public class X9FieldElement
+ extends ASN1Object
+{
+ protected ECFieldElement f;
+
+ private static X9IntegerConverter converter = new X9IntegerConverter();
+
+ public X9FieldElement(ECFieldElement f)
+ {
+ this.f = f;
+ }
+
+ public X9FieldElement(BigInteger p, ASN1OctetString s)
+ {
+ this(new ECFieldElement.Fp(p, new BigInteger(1, s.getOctets())));
+ }
+
+ public X9FieldElement(int m, int k1, int k2, int k3, ASN1OctetString s)
+ {
+ this(new ECFieldElement.F2m(m, k1, k2, k3, new BigInteger(1, s.getOctets())));
+ }
+
+ public ECFieldElement getValue()
+ {
+ return f;
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ * <pre>
+ * FieldElement ::= OCTET STRING
+ * </pre>
+ * <p>
+ * <ol>
+ * <li> if <i>q</i> is an odd prime then the field element is
+ * processed as an Integer and converted to an octet string
+ * according to x 9.62 4.3.1.</li>
+ * <li> if <i>q</i> is 2<sup>m</sup> then the bit string
+ * contained in the field element is converted into an octet
+ * string with the same ordering padded at the front if necessary.
+ * </li>
+ * </ol>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ int byteCount = converter.getByteLength(f);
+ byte[] paddedBigInteger = converter.integerToBytes(f.toBigInteger(), byteCount);
+
+ return new DEROctetString(paddedBigInteger);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
new file mode 100644
index 0000000..30598e2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
@@ -0,0 +1,109 @@
+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.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+
+/**
+ * ASN.1 def for Elliptic-Curve Field ID structure. See
+ * X9.62, for further details.
+ */
+public class X9FieldID
+ extends ASN1Object
+ implements X9ObjectIdentifiers
+{
+ private ASN1ObjectIdentifier id;
+ private ASN1Primitive parameters;
+
+ /**
+ * Constructor for elliptic curves over prime fields
+ * <code>F<sub>2</sub></code>.
+ * @param primeP The prime <code>p</code> defining the prime field.
+ */
+ public X9FieldID(BigInteger primeP)
+ {
+ this.id = prime_field;
+ this.parameters = new ASN1Integer(primeP);
+ }
+
+ /**
+ * Constructor for elliptic curves over binary fields
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>..
+ */
+ public X9FieldID(int m, int k1, int k2, int k3)
+ {
+ this.id = characteristic_two_field;
+ ASN1EncodableVector fieldIdParams = new ASN1EncodableVector();
+ fieldIdParams.add(new ASN1Integer(m));
+
+ if (k2 == 0)
+ {
+ fieldIdParams.add(tpBasis);
+ fieldIdParams.add(new ASN1Integer(k1));
+ }
+ else
+ {
+ fieldIdParams.add(ppBasis);
+ ASN1EncodableVector pentanomialParams = new ASN1EncodableVector();
+ pentanomialParams.add(new ASN1Integer(k1));
+ pentanomialParams.add(new ASN1Integer(k2));
+ pentanomialParams.add(new ASN1Integer(k3));
+ fieldIdParams.add(new DERSequence(pentanomialParams));
+ }
+
+ this.parameters = new DERSequence(fieldIdParams);
+ }
+
+ public X9FieldID(
+ ASN1Sequence seq)
+ {
+ this.id = (ASN1ObjectIdentifier)seq.getObjectAt(0);
+ this.parameters = (ASN1Primitive)seq.getObjectAt(1);
+ }
+
+ public ASN1ObjectIdentifier getIdentifier()
+ {
+ return id;
+ }
+
+ public ASN1Primitive getParameters()
+ {
+ return parameters;
+ }
+
+ /**
+ * Produce a DER encoding of the following structure.
+ * <pre>
+ * FieldID ::= SEQUENCE {
+ * fieldType FIELD-ID.&amp;id({IOSet}),
+ * parameters FIELD-ID.&amp;Type({IOSet}{&#64;fieldType})
+ * }
+ * </pre>
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(this.id);
+ v.add(this.parameters);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
new file mode 100644
index 0000000..16a803c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9IntegerConverter.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.asn1.x9;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECFieldElement;
+
+public class X9IntegerConverter
+{
+ public int getByteLength(
+ ECCurve c)
+ {
+ return (c.getFieldSize() + 7) / 8;
+ }
+
+ public int getByteLength(
+ ECFieldElement fe)
+ {
+ return (fe.getFieldSize() + 7) / 8;
+ }
+
+ public byte[] integerToBytes(
+ BigInteger s,
+ int qLength)
+ {
+ byte[] bytes = s.toByteArray();
+
+ if (qLength < bytes.length)
+ {
+ byte[] tmp = new byte[qLength];
+
+ System.arraycopy(bytes, bytes.length - tmp.length, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+ else if (qLength > bytes.length)
+ {
+ byte[] tmp = new byte[qLength];
+
+ System.arraycopy(bytes, 0, tmp, tmp.length - bytes.length, bytes.length);
+
+ return tmp;
+ }
+
+ return bytes;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
new file mode 100644
index 0000000..6c1fcd7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
@@ -0,0 +1,132 @@
+package org.bouncycastle.asn1.x9;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface X9ObjectIdentifiers
+{
+ //
+ // X9.62
+ //
+ // ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-x962(10045) }
+ //
+ static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045");
+ static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1");
+
+ static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1");
+
+ static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2");
+
+ static final ASN1ObjectIdentifier gnBasis = id_fieldType.branch("2.3.1");
+
+ static final ASN1ObjectIdentifier tpBasis = id_fieldType.branch("2.3.2");
+
+ static final ASN1ObjectIdentifier ppBasis = id_fieldType.branch("2.3.3");
+
+ static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA1 = new ASN1ObjectIdentifier(id_ecSigType + ".1");
+
+ static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2");
+
+ static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3");
+
+ static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4");
+
+ //
+ // named curves
+ //
+ static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3");
+
+ //
+ // Two Curves
+ //
+ static final ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0");
+
+ static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1");
+ static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2");
+ static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3");
+ static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4");
+ static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5");
+ static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6");
+ static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7");
+ static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8");
+ static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9");
+ static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10");
+ static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11");
+ static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12");
+ static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13");
+ static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14");
+ static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15");
+ static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16");
+ static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17");
+ static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18");
+ static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19");
+ static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20");
+
+ //
+ // Prime
+ //
+ static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1");
+
+ static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1");
+ static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2");
+ static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3");
+ static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4");
+ static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5");
+ static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6");
+ static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7");
+
+ //
+ // DSA
+ //
+ // dsapublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-x957(10040) number-type(4) 1 }
+ static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1");
+
+ /**
+ * id-dsa-with-sha1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) x9-57
+ * (10040) x9cm(4) 3 }
+ */
+ public static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3");
+
+ /**
+ * X9.63
+ */
+ public static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0");
+ public static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2");
+ public static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3");
+ public static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16");
+
+ /**
+ * X9.42
+ */
+
+ static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046");
+
+ //
+ // Diffie-Hellman
+ //
+ // dhpublicnumber OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ // us(840) ansi-x942(10046) number-type(2) 1 }
+ //
+ public static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1");
+
+ public static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3");
+ public static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1");
+ public static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2");
+ public static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3");
+ public static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4");
+ public static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5");
+ public static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6");
+ public static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7");
+ public static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8");
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricBlockCipher.java
new file mode 100644
index 0000000..565effc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricBlockCipher.java
@@ -0,0 +1,45 @@
+package org.bouncycastle.crypto;
+
+
+/**
+ * base interface that a public/private key block cipher needs
+ * to conform to.
+ */
+public interface AsymmetricBlockCipher
+{
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param param the key and other data required by the cipher.
+ */
+ public void init(boolean forEncryption, CipherParameters param);
+
+ /**
+ * returns the largest size an input block can be.
+ *
+ * @return maximum size for an input block.
+ */
+ public int getInputBlockSize();
+
+ /**
+ * returns the maximum size of the block produced by this cipher.
+ *
+ * @return maximum size of the output block produced by the cipher.
+ */
+ public int getOutputBlockSize();
+
+ /**
+ * process the block of len bytes stored in in from offset inOff.
+ *
+ * @param in the input data
+ * @param inOff offset into the in array where the data starts
+ * @param len the length of the block to be processed.
+ * @return the resulting byte array of the encryption/decryption process.
+ * @exception InvalidCipherTextException data decrypts improperly.
+ * @exception DataLengthException the input data is too large for the cipher.
+ */
+ public byte[] processBlock(byte[] in, int inOff, int len)
+ throws InvalidCipherTextException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java b/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java
new file mode 100644
index 0000000..85bec73
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java
@@ -0,0 +1,44 @@
+package org.bouncycastle.crypto;
+
+/**
+ * a holding class for public/private parameter pairs.
+ */
+public class AsymmetricCipherKeyPair
+{
+ private CipherParameters publicParam;
+ private CipherParameters privateParam;
+
+ /**
+ * basic constructor.
+ *
+ * @param publicParam a public key parameters object.
+ * @param privateParam the corresponding private key parameters.
+ */
+ public AsymmetricCipherKeyPair(
+ CipherParameters publicParam,
+ CipherParameters privateParam)
+ {
+ this.publicParam = publicParam;
+ this.privateParam = privateParam;
+ }
+
+ /**
+ * return the public key parameters.
+ *
+ * @return the public key parameters.
+ */
+ public CipherParameters getPublic()
+ {
+ return publicParam;
+ }
+
+ /**
+ * return the private key parameters.
+ *
+ * @return the private key parameters.
+ */
+ public CipherParameters getPrivate()
+ {
+ return privateParam;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java
new file mode 100644
index 0000000..919db19
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPairGenerator.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.crypto;
+
+/**
+ * interface that a public/private key pair generator should conform to.
+ */
+public interface AsymmetricCipherKeyPairGenerator
+{
+ /**
+ * intialise the key pair generator.
+ *
+ * @param param the parameters the key pair is to be initialised with.
+ */
+ public void init(KeyGenerationParameters param);
+
+ /**
+ * return an AsymmetricCipherKeyPair containing the generated keys.
+ *
+ * @return an AsymmetricCipherKeyPair containing the generated keys.
+ */
+ public AsymmetricCipherKeyPair generateKeyPair();
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/BasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/BasicAgreement.java
new file mode 100644
index 0000000..4907427
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/BasicAgreement.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.crypto;
+
+import java.math.BigInteger;
+
+/**
+ * The basic interface that basic Diffie-Hellman implementations
+ * conforms to.
+ */
+public interface BasicAgreement
+{
+ /**
+ * initialise the agreement engine.
+ */
+ public void init(CipherParameters param);
+
+ /**
+ * given a public key from a given party calculate the next
+ * message in the agreement sequence.
+ */
+ public BigInteger calculateAgreement(CipherParameters pubKey);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/BlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/BlockCipher.java
new file mode 100644
index 0000000..3cfa25a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/BlockCipher.java
@@ -0,0 +1,56 @@
+package org.bouncycastle.crypto;
+
+
+/**
+ * Block cipher engines are expected to conform to this interface.
+ */
+public interface BlockCipher
+{
+ /**
+ * Initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public String getAlgorithmName();
+
+ /**
+ * Return the block size for this cipher (in bytes).
+ *
+ * @return the block size for this cipher in bytes.
+ */
+ public int getBlockSize();
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException;
+
+ /**
+ * Reset the cipher. After resetting the cipher is in the same state
+ * as it was after the last init (if there was one).
+ */
+ public void reset();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
new file mode 100644
index 0000000..4878786
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java
@@ -0,0 +1,313 @@
+package org.bouncycastle.crypto;
+
+
+/**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
+ * buffer is full and more data is being added, or on a doFinal.
+ * <p>
+ * Note: in the case where the underlying cipher is either a CFB cipher or an
+ * OFB one the last block may not be a multiple of the block size.
+ */
+public class BufferedBlockCipher
+{
+ protected byte[] buf;
+ protected int bufOff;
+
+ protected boolean forEncryption;
+ protected BlockCipher cipher;
+
+ protected boolean partialBlockOkay;
+ protected boolean pgpCFB;
+
+ /**
+ * constructor for subclasses
+ */
+ protected BufferedBlockCipher()
+ {
+ }
+
+ /**
+ * Create a buffered block cipher without padding.
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ */
+ public BufferedBlockCipher(
+ BlockCipher cipher)
+ {
+ this.cipher = cipher;
+
+ buf = new byte[cipher.getBlockSize()];
+ bufOff = 0;
+
+ //
+ // check if we can handle partial blocks on doFinal.
+ //
+ String name = cipher.getAlgorithmName();
+ int idx = name.indexOf('/') + 1;
+
+ pgpCFB = (idx > 0 && name.startsWith("PGP", idx));
+
+ if (pgpCFB)
+ {
+ partialBlockOkay = true;
+ }
+ else
+ {
+ partialBlockOkay = (idx > 0 && (name.startsWith("CFB", idx) || name.startsWith("OFB", idx) || name.startsWith("OpenPGP", idx) || name.startsWith("SIC", idx) || name.startsWith("GCTR", idx)));
+ }
+ }
+
+ /**
+ * return the cipher this object wraps.
+ *
+ * @return the cipher this object wraps.
+ */
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+
+ reset();
+
+ cipher.init(forEncryption, params);
+ }
+
+ /**
+ * return the blocksize for the underlying cipher.
+ *
+ * @return the blocksize for the underlying cipher.
+ */
+ public int getBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public int getUpdateOutputSize(
+ int len)
+ {
+ int total = len + bufOff;
+ int leftOver;
+
+ if (pgpCFB)
+ {
+ leftOver = total % buf.length - (cipher.getBlockSize() + 2);
+ }
+ else
+ {
+ leftOver = total % buf.length;
+ }
+
+ return total - leftOver;
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of 'length' bytes.
+ *
+ * @param length the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with 'length' bytes of input.
+ */
+ public int getOutputSize(
+ int length)
+ {
+ // Note: Can assume partialBlockOkay is true for purposes of this calculation
+ return length + bufOff;
+ }
+
+ /**
+ * process a single byte, producing an output block if neccessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processByte(
+ byte in,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ int resultLen = 0;
+
+ buf[bufOff++] = in;
+
+ if (bufOff == buf.length)
+ {
+ resultLen = cipher.processBlock(buf, 0, out, outOff);
+ bufOff = 0;
+ }
+
+ return resultLen;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = getBlockSize();
+ int length = getUpdateOutputSize(len);
+
+ if (length > 0)
+ {
+ if ((outOff + length) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.length - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.processBlock(buf, 0, out, outOff);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > buf.length)
+ {
+ resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+
+ if (bufOff == buf.length)
+ {
+ resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+ bufOff = 0;
+ }
+
+ return resultLen;
+ }
+
+ /**
+ * Process the last block in the buffer.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output, or the input is not block size aligned and should be.
+ * @exception IllegalStateException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if padding is expected and not found.
+ * @exception DataLengthException if the input is not block size
+ * aligned.
+ */
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException, InvalidCipherTextException
+ {
+ try
+ {
+ int resultLen = 0;
+
+ if (outOff + bufOff > out.length)
+ {
+ throw new DataLengthException("output buffer too short for doFinal()");
+ }
+
+ if (bufOff != 0)
+ {
+ if (!partialBlockOkay)
+ {
+ throw new DataLengthException("data not block size aligned");
+ }
+
+ cipher.processBlock(buf, 0, buf, 0);
+ resultLen = bufOff;
+ bufOff = 0;
+ System.arraycopy(buf, 0, out, outOff, resultLen);
+ }
+
+ return resultLen;
+ }
+ finally
+ {
+ reset();
+ }
+ }
+
+ /**
+ * Reset the buffer and cipher. After resetting the object is in the same
+ * state as it was after the last init (if there was one).
+ */
+ public void reset()
+ {
+ //
+ // clean the buffer.
+ //
+ for (int i = 0; i < buf.length; i++)
+ {
+ buf[i] = 0;
+ }
+
+ bufOff = 0;
+
+ //
+ // reset the underlying cipher.
+ //
+ cipher.reset();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/CipherKeyGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/CipherKeyGenerator.java
new file mode 100644
index 0000000..451f8e8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/CipherKeyGenerator.java
@@ -0,0 +1,38 @@
+package org.bouncycastle.crypto;
+
+import java.security.SecureRandom;
+
+/**
+ * The base class for symmetric, or secret, cipher key generators.
+ */
+public class CipherKeyGenerator
+{
+ protected SecureRandom random;
+ protected int strength;
+
+ /**
+ * initialise the key generator.
+ *
+ * @param param the parameters to be used for key generation
+ */
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.random = param.getRandom();
+ this.strength = (param.getStrength() + 7) / 8;
+ }
+
+ /**
+ * generate a secret key.
+ *
+ * @return a byte array containing the key value.
+ */
+ public byte[] generateKey()
+ {
+ byte[] key = new byte[strength];
+
+ random.nextBytes(key);
+
+ return key;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/CipherParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/CipherParameters.java
new file mode 100644
index 0000000..5be8730
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/CipherParameters.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.crypto;
+
+/**
+ * all parameter classes implement this.
+ */
+public interface CipherParameters
+{
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/CryptoException.java b/bcprov/src/main/java/org/bouncycastle/crypto/CryptoException.java
new file mode 100644
index 0000000..352c556
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/CryptoException.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto;
+
+/**
+ * the foundation class for the hard exceptions thrown by the crypto packages.
+ */
+public class CryptoException
+ extends Exception
+{
+ private Throwable cause;
+
+ /**
+ * base constructor.
+ */
+ public CryptoException()
+ {
+ }
+
+ /**
+ * create a CryptoException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public CryptoException(
+ String message)
+ {
+ super(message);
+ }
+
+ /**
+ * Create a CryptoException with the given message and underlying cause.
+ *
+ * @param message message describing exception.
+ * @param cause the throwable that was the underlying cause.
+ */
+ public CryptoException(
+ String message,
+ Throwable cause)
+ {
+ super(message);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/DSA.java b/bcprov/src/main/java/org/bouncycastle/crypto/DSA.java
new file mode 100644
index 0000000..1f58476
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/DSA.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.crypto;
+
+import java.math.BigInteger;
+
+/**
+ * interface for classes implementing algorithms modeled similar to the Digital Signature Alorithm.
+ */
+public interface DSA
+{
+ /**
+ * initialise the signer for signature generation or signature
+ * verification.
+ *
+ * @param forSigning true if we are generating a signature, false
+ * otherwise.
+ * @param param key parameters for signature generation.
+ */
+ public void init(boolean forSigning, CipherParameters param);
+
+ /**
+ * sign the passed in message (usually the output of a hash function).
+ *
+ * @param message the message to be signed.
+ * @return two big integers representing the r and s values respectively.
+ */
+ public BigInteger[] generateSignature(byte[] message);
+
+ /**
+ * verify the message message against the signature values r and s.
+ *
+ * @param message the message that was supposed to have been signed.
+ * @param r the r signature value.
+ * @param s the s signature value.
+ */
+ public boolean verifySignature(byte[] message, BigInteger r, BigInteger s);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/DataLengthException.java b/bcprov/src/main/java/org/bouncycastle/crypto/DataLengthException.java
new file mode 100644
index 0000000..fbf047c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/DataLengthException.java
@@ -0,0 +1,29 @@
+package org.bouncycastle.crypto;
+
+/**
+ * this exception is thrown if a buffer that is meant to have output
+ * copied into it turns out to be too short, or if we've been given
+ * insufficient input. In general this exception will get thrown rather
+ * than an ArrayOutOfBounds exception.
+ */
+public class DataLengthException
+ extends RuntimeCryptoException
+{
+ /**
+ * base constructor.
+ */
+ public DataLengthException()
+ {
+ }
+
+ /**
+ * create a DataLengthException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public DataLengthException(
+ String message)
+ {
+ super(message);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java b/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java
new file mode 100644
index 0000000..ef6e29e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/DerivationFunction.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.crypto;
+
+/**
+ * base interface for general purpose byte derivation functions.
+ */
+public interface DerivationFunction
+{
+ public void init(DerivationParameters param);
+
+ /**
+ * return the message digest used as the basis for the function
+ */
+ public Digest getDigest();
+
+ public int generateBytes(byte[] out, int outOff, int len)
+ throws DataLengthException, IllegalArgumentException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/DerivationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/DerivationParameters.java
new file mode 100644
index 0000000..e11eb86
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/DerivationParameters.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.crypto;
+
+/**
+ * Parameters for key/byte stream derivation classes
+ */
+public interface DerivationParameters
+{
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/Digest.java
new file mode 100644
index 0000000..f44fad0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/Digest.java
@@ -0,0 +1,51 @@
+package org.bouncycastle.crypto;
+
+/**
+ * interface that a message digest conforms to.
+ */
+public interface Digest
+{
+ /**
+ * return the algorithm name
+ *
+ * @return the algorithm name
+ */
+ public String getAlgorithmName();
+
+ /**
+ * return the size, in bytes, of the digest produced by this message digest.
+ *
+ * @return the size, in bytes, of the digest produced by this message digest.
+ */
+ public int getDigestSize();
+
+ /**
+ * update the message digest with a single byte.
+ *
+ * @param in the input byte to be entered.
+ */
+ public void update(byte in);
+
+ /**
+ * update the message digest with a block of bytes.
+ *
+ * @param in the byte array containing the data.
+ * @param inOff the offset into the byte array where the data starts.
+ * @param len the length of the data.
+ */
+ public void update(byte[] in, int inOff, int len);
+
+ /**
+ * close the digest, producing the final digest value. The doFinal
+ * call leaves the digest reset.
+ *
+ * @param out the array the digest is to be copied into.
+ * @param outOff the offset into the out array the digest is to start at.
+ */
+ public int doFinal(byte[] out, int outOff);
+
+ /**
+ * reset the digest back to it's initial state.
+ */
+ public void reset();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/ExtendedDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/ExtendedDigest.java
new file mode 100644
index 0000000..c5e9e8b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/ExtendedDigest.java
@@ -0,0 +1,13 @@
+package org.bouncycastle.crypto;
+
+public interface ExtendedDigest
+ extends Digest
+{
+ /**
+ * Return the size in bytes of the internal buffer the digest applies it's compression
+ * function to.
+ *
+ * @return byte length of the digests internal buffer.
+ */
+ public int getByteLength();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java b/bcprov/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java
new file mode 100644
index 0000000..59e4b26
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/InvalidCipherTextException.java
@@ -0,0 +1,27 @@
+package org.bouncycastle.crypto;
+
+/**
+ * this exception is thrown whenever we find something we don't expect in a
+ * message.
+ */
+public class InvalidCipherTextException
+ extends CryptoException
+{
+ /**
+ * base constructor.
+ */
+ public InvalidCipherTextException()
+ {
+ }
+
+ /**
+ * create a InvalidCipherTextException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public InvalidCipherTextException(
+ String message)
+ {
+ super(message);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/KeyGenerationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/KeyGenerationParameters.java
new file mode 100644
index 0000000..9a63522
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/KeyGenerationParameters.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto;
+
+import java.security.SecureRandom;
+
+/**
+ * The base class for parameters to key generators.
+ */
+public class KeyGenerationParameters
+{
+ private SecureRandom random;
+ private int strength;
+
+ /**
+ * initialise the generator with a source of randomness
+ * and a strength (in bits).
+ *
+ * @param random the random byte source.
+ * @param strength the size, in bits, of the keys we want to produce.
+ */
+ public KeyGenerationParameters(
+ SecureRandom random,
+ int strength)
+ {
+ this.random = random;
+ this.strength = strength;
+ }
+
+ /**
+ * return the random source associated with this
+ * generator.
+ *
+ * @return the generators random source.
+ */
+ public SecureRandom getRandom()
+ {
+ return random;
+ }
+
+ /**
+ * return the bit strength for keys produced by this generator,
+ *
+ * @return the strength of the keys this generator produces (in bits).
+ */
+ public int getStrength()
+ {
+ return strength;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/Mac.java b/bcprov/src/main/java/org/bouncycastle/crypto/Mac.java
new file mode 100644
index 0000000..c00cd58
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/Mac.java
@@ -0,0 +1,71 @@
+package org.bouncycastle.crypto;
+
+
+/**
+ * The base interface for implementations of message authentication codes (MACs).
+ */
+public interface Mac
+{
+ /**
+ * Initialise the MAC.
+ *
+ * @param params the key and other data required by the MAC.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(CipherParameters params)
+ throws IllegalArgumentException;
+
+ /**
+ * Return the name of the algorithm the MAC implements.
+ *
+ * @return the name of the algorithm the MAC implements.
+ */
+ public String getAlgorithmName();
+
+ /**
+ * Return the block size for this MAC (in bytes).
+ *
+ * @return the block size for this MAC in bytes.
+ */
+ public int getMacSize();
+
+ /**
+ * add a single byte to the mac for processing.
+ *
+ * @param in the byte to be processed.
+ * @exception IllegalStateException if the MAC is not initialised.
+ */
+ public void update(byte in)
+ throws IllegalStateException;
+
+ /**
+ * @param in the array containing the input.
+ * @param inOff the index in the array the data begins at.
+ * @param len the length of the input starting at inOff.
+ * @exception IllegalStateException if the MAC is not initialised.
+ * @exception DataLengthException if there isn't enough data in in.
+ */
+ public void update(byte[] in, int inOff, int len)
+ throws DataLengthException, IllegalStateException;
+
+ /**
+ * Compute the final stage of the MAC writing the output to the out
+ * parameter.
+ * <p>
+ * doFinal leaves the MAC in the same state it was after the last init.
+ *
+ * @param out the array the MAC is to be output to.
+ * @param outOff the offset into the out buffer the output is to start at.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the MAC is not initialised.
+ */
+ public int doFinal(byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException;
+
+ /**
+ * Reset the MAC. At the end of resetting the MAC should be in the
+ * in the same state it was after the last init (if there was one).
+ */
+ public void reset();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java
new file mode 100644
index 0000000..dbf550d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/PBEParametersGenerator.java
@@ -0,0 +1,159 @@
+package org.bouncycastle.crypto;
+
+import org.bouncycastle.util.Strings;
+
+/**
+ * super class for all Password Based Encryption (PBE) parameter generator classes.
+ */
+public abstract class PBEParametersGenerator
+{
+ protected byte[] password;
+ protected byte[] salt;
+ protected int iterationCount;
+
+ /**
+ * base constructor.
+ */
+ protected PBEParametersGenerator()
+ {
+ }
+
+ /**
+ * initialise the PBE generator.
+ *
+ * @param password the password converted into bytes (see below).
+ * @param salt the salt to be mixed with the password.
+ * @param iterationCount the number of iterations the "mixing" function
+ * is to be applied for.
+ */
+ public void init(
+ byte[] password,
+ byte[] salt,
+ int iterationCount)
+ {
+ this.password = password;
+ this.salt = salt;
+ this.iterationCount = iterationCount;
+ }
+
+ /**
+ * return the password byte array.
+ *
+ * @return the password byte array.
+ */
+ public byte[] getPassword()
+ {
+ return password;
+ }
+
+ /**
+ * return the salt byte array.
+ *
+ * @return the salt byte array.
+ */
+ public byte[] getSalt()
+ {
+ return salt;
+ }
+
+ /**
+ * return the iteration count.
+ *
+ * @return the iteration count.
+ */
+ public int getIterationCount()
+ {
+ return iterationCount;
+ }
+
+ /**
+ * generate derived parameters for a key of length keySize.
+ *
+ * @param keySize the length, in bits, of the key required.
+ * @return a parameters object representing a key.
+ */
+ public abstract CipherParameters generateDerivedParameters(int keySize);
+
+ /**
+ * generate derived parameters for a key of length keySize, and
+ * an initialisation vector (IV) of length ivSize.
+ *
+ * @param keySize the length, in bits, of the key required.
+ * @param ivSize the length, in bits, of the iv required.
+ * @return a parameters object representing a key and an IV.
+ */
+ public abstract CipherParameters generateDerivedParameters(int keySize, int ivSize);
+
+ /**
+ * generate derived parameters for a key of length keySize, specifically
+ * for use with a MAC.
+ *
+ * @param keySize the length, in bits, of the key required.
+ * @return a parameters object representing a key.
+ */
+ public abstract CipherParameters generateDerivedMacParameters(int keySize);
+
+ /**
+ * converts a password to a byte array according to the scheme in
+ * PKCS5 (ascii, no padding)
+ *
+ * @param password a character array representing the password.
+ * @return a byte array representing the password.
+ */
+ public static byte[] PKCS5PasswordToBytes(
+ char[] password)
+ {
+ byte[] bytes = new byte[password.length];
+
+ for (int i = 0; i != bytes.length; i++)
+ {
+ bytes[i] = (byte)password[i];
+ }
+
+ return bytes;
+ }
+
+ /**
+ * converts a password to a byte array according to the scheme in
+ * PKCS5 (UTF-8, no padding)
+ *
+ * @param password a character array representing the password.
+ * @return a byte array representing the password.
+ */
+ public static byte[] PKCS5PasswordToUTF8Bytes(
+ char[] password)
+ {
+ return Strings.toUTF8ByteArray(password);
+ }
+
+ /**
+ * converts a password to a byte array according to the scheme in
+ * PKCS12 (unicode, big endian, 2 zero pad bytes at the end).
+ *
+ * @param password a character array representing the password.
+ * @return a byte array representing the password.
+ */
+ public static byte[] PKCS12PasswordToBytes(
+ char[] password)
+ {
+ // BEGIN android-changed
+ if (password != null && password.length > 0)
+ {
+ // +1 for extra 2 pad bytes.
+ byte[] bytes = new byte[(password.length + 1) * 2];
+
+ for (int i = 0; i != password.length; i ++)
+ {
+ bytes[i * 2] = (byte)(password[i] >>> 8);
+ bytes[i * 2 + 1] = (byte)password[i];
+ }
+
+ return bytes;
+ }
+ else
+ {
+ return new byte[0];
+ }
+ // END android-changed
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/RuntimeCryptoException.java b/bcprov/src/main/java/org/bouncycastle/crypto/RuntimeCryptoException.java
new file mode 100644
index 0000000..c157202
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/RuntimeCryptoException.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.crypto;
+
+/**
+ * the foundation class for the exceptions thrown by the crypto packages.
+ */
+public class RuntimeCryptoException
+ extends RuntimeException
+{
+ /**
+ * base constructor.
+ */
+ public RuntimeCryptoException()
+ {
+ }
+
+ /**
+ * create a RuntimeCryptoException with the given message.
+ *
+ * @param message the message to be carried with the exception.
+ */
+ public RuntimeCryptoException(
+ String message)
+ {
+ super(message);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/Signer.java b/bcprov/src/main/java/org/bouncycastle/crypto/Signer.java
new file mode 100644
index 0000000..357b0da
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/Signer.java
@@ -0,0 +1,43 @@
+package org.bouncycastle.crypto;
+
+/**
+ * Generic signer interface for hash based and message recovery signers.
+ */
+public interface Signer
+{
+ /**
+ * Initialise the signer for signing or verification.
+ *
+ * @param forSigning true if for signing, false otherwise
+ * @param param necessary parameters.
+ */
+ public void init(boolean forSigning, CipherParameters param);
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void update(byte b);
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void update(byte[] in, int off, int len);
+
+ /**
+ * generate a signature for the message we've been loaded with using
+ * the key we were initialised with.
+ */
+ public byte[] generateSignature()
+ throws CryptoException, DataLengthException;
+
+ /**
+ * return true if the internal state represents the signature described
+ * in the passed in array.
+ */
+ public boolean verifySignature(byte[] signature);
+
+ /**
+ * reset the internal state
+ */
+ public void reset();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java b/bcprov/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java
new file mode 100644
index 0000000..452b367
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/SignerWithRecovery.java
@@ -0,0 +1,34 @@
+package org.bouncycastle.crypto;
+
+/**
+ * Signer with message recovery.
+ */
+public interface SignerWithRecovery
+ extends Signer
+{
+ /**
+ * Returns true if the signer has recovered the full message as
+ * part of signature verification.
+ *
+ * @return true if full message recovered.
+ */
+ public boolean hasFullMessage();
+
+ /**
+ * Returns a reference to what message was recovered (if any).
+ *
+ * @return full/partial message, null if nothing.
+ */
+ public byte[] getRecoveredMessage();
+
+ /**
+ * Perform an update with the recovered message before adding any other data. This must
+ * be the first update method called, and calling it will result in the signer assuming
+ * that further calls to update will include message content past what is recoverable.
+ *
+ * @param signature the signature that we are in the process of verifying.
+ * @throws IllegalStateException
+ */
+ public void updateWithRecoveredMessage(byte[] signature)
+ throws InvalidCipherTextException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java
new file mode 100644
index 0000000..8fdd232
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/StreamBlockCipher.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.crypto;
+
+/**
+ * a wrapper for block ciphers with a single byte block size, so that they
+ * can be treated like stream ciphers.
+ */
+public class StreamBlockCipher
+ implements StreamCipher
+{
+ private 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)
+ {
+ if (cipher.getBlockSize() != 1)
+ {
+ throw new IllegalArgumentException("block cipher block size != 1.");
+ }
+
+ this.cipher = cipher;
+ }
+
+ /**
+ * initialise the underlying cipher.
+ *
+ * @param forEncryption true if we are setting up for encryption, false otherwise.
+ * @param params the necessary parameters for the underlying cipher to be initialised.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ /**
+ * return the name of the algorithm we are wrapping.
+ *
+ * @return the name of the algorithm we are wrapping.
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName();
+ }
+
+ /**
+ * 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)
+ throws DataLengthException
+ {
+ if (outOff + len > out.length)
+ {
+ throw new DataLengthException("output buffer too small in processBytes()");
+ }
+
+ for (int i = 0; i != len; i++)
+ {
+ cipher.processBlock(in, inOff + i, out, outOff + i);
+ }
+ }
+
+ /**
+ * 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();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java
new file mode 100644
index 0000000..2a55d4f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/StreamCipher.java
@@ -0,0 +1,53 @@
+package org.bouncycastle.crypto;
+
+/**
+ * the interface stream ciphers conform to.
+ */
+public interface StreamCipher
+{
+ /**
+ * Initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public String getAlgorithmName();
+
+ /**
+ * 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);
+
+ /**
+ * 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 starts at.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ public void processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException;
+
+ /**
+ * reset the cipher. This leaves it in the same state
+ * it was at after the last init (if there was one).
+ */
+ public void reset();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/Wrapper.java b/bcprov/src/main/java/org/bouncycastle/crypto/Wrapper.java
new file mode 100644
index 0000000..3956a6f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/Wrapper.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.crypto;
+
+public interface Wrapper
+{
+ public void init(boolean forWrapping, CipherParameters param);
+
+ /**
+ * Return the name of the algorithm the wrapper implements.
+ *
+ * @return the name of the algorithm the wrapper implements.
+ */
+ public String getAlgorithmName();
+
+ public byte[] wrap(byte[] in, int inOff, int inLen);
+
+ public byte[] unwrap(byte[] in, int inOff, int inLen)
+ throws InvalidCipherTextException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java
new file mode 100644
index 0000000..40893bf
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/DHBasicAgreement.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.crypto.agreement;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.BasicAgreement;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * a Diffie-Hellman key agreement class.
+ * <p>
+ * note: This is only the basic algorithm, it doesn't take advantage of
+ * long term public keys if they are available. See the DHAgreement class
+ * for a "better" implementation.
+ */
+public class DHBasicAgreement
+ implements BasicAgreement
+{
+ private DHPrivateKeyParameters key;
+ private DHParameters dhParams;
+
+ public void init(
+ CipherParameters param)
+ {
+ AsymmetricKeyParameter kParam;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+ kParam = (AsymmetricKeyParameter)rParam.getParameters();
+ }
+ else
+ {
+ kParam = (AsymmetricKeyParameter)param;
+ }
+
+ if (!(kParam instanceof DHPrivateKeyParameters))
+ {
+ throw new IllegalArgumentException("DHEngine expects DHPrivateKeyParameters");
+ }
+
+ this.key = (DHPrivateKeyParameters)kParam;
+ this.dhParams = key.getParameters();
+ }
+
+ /**
+ * given a short term public key from a given party calculate the next
+ * message in the agreement sequence.
+ */
+ public BigInteger calculateAgreement(
+ CipherParameters pubKey)
+ {
+ DHPublicKeyParameters pub = (DHPublicKeyParameters)pubKey;
+
+ if (!pub.getParameters().equals(dhParams))
+ {
+ throw new IllegalArgumentException("Diffie-Hellman public key has wrong parameters.");
+ }
+
+ return pub.getY().modPow(key.getX(), dhParams.getP());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
new file mode 100644
index 0000000..3ad3e1c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/agreement/ECDHBasicAgreement.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.crypto.agreement;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+import org.bouncycastle.crypto.BasicAgreement;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+
+/**
+ * P1363 7.2.1 ECSVDP-DH
+ *
+ * ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
+ * Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
+ * and [Kob87]. This primitive derives a shared secret value from one
+ * party's private key and another party's public key, where both have
+ * the same set of EC domain parameters. If two parties correctly
+ * execute this primitive, they will produce the same output. This
+ * primitive can be invoked by a scheme to derive a shared secret key;
+ * specifically, it may be used with the schemes ECKAS-DH1 and
+ * DL/ECKAS-DH2. It assumes that the input keys are valid (see also
+ * Section 7.2.2).
+ */
+public class ECDHBasicAgreement
+ implements BasicAgreement
+{
+ private ECPrivateKeyParameters key;
+
+ public void init(
+ CipherParameters key)
+ {
+ this.key = (ECPrivateKeyParameters)key;
+ }
+
+ public BigInteger calculateAgreement(
+ CipherParameters pubKey)
+ {
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey;
+ ECPoint P = pub.getQ().multiply(key.getD());
+
+ // if (p.isInfinity()) throw new RuntimeException("d*Q == infinity");
+
+ return P.getX().toBigInteger();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactory.java
new file mode 100644
index 0000000..1a82a46
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactory.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 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 org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.Digest;
+
+/**
+ * Level of indirection to let us select OpenSSLDigest implementations
+ * for libcore but fallback to BouncyCastle ones on the RI.
+ */
+public final class AndroidDigestFactory {
+ private static final String OpenSSLFactoryClassName
+ = AndroidDigestFactory.class.getName() + "OpenSSL";
+ private static final String BouncyCastleFactoryClassName
+ = AndroidDigestFactory.class.getName() + "BouncyCastle";
+
+ private static final AndroidDigestFactoryInterface FACTORY;
+ static {
+ Class factoryImplementationClass;
+ try {
+ factoryImplementationClass = Class.forName(OpenSSLFactoryClassName);
+ } catch (ClassNotFoundException e1) {
+ try {
+ factoryImplementationClass = Class.forName(BouncyCastleFactoryClassName);
+ } catch (ClassNotFoundException e2) {
+ throw new AssertionError("Failed to find AndroidDigestFactoryInterface "
+ + "implementation. Looked for "
+ + OpenSSLFactoryClassName + " and "
+ + BouncyCastleFactoryClassName);
+ }
+ }
+ if (!AndroidDigestFactoryInterface.class.isAssignableFrom(factoryImplementationClass)) {
+ throw new AssertionError(factoryImplementationClass
+ + "does not implement AndroidDigestFactoryInterface");
+ }
+ try {
+ FACTORY = (AndroidDigestFactoryInterface) factoryImplementationClass.newInstance();
+ } catch (InstantiationException e) {
+ throw new AssertionError(e);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ public static Digest getMD5() {
+ return FACTORY.getMD5();
+ }
+
+ public static Digest getSHA1() {
+ return FACTORY.getSHA1();
+ }
+
+ public static Digest getSHA256() {
+ return FACTORY.getSHA256();
+ }
+
+ public static Digest getSHA384() {
+ return FACTORY.getSHA384();
+ }
+
+ public static Digest getSHA512() {
+ return FACTORY.getSHA512();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java
new file mode 100644
index 0000000..47d3852
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryBouncyCastle.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 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 org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.Digest;
+
+public class AndroidDigestFactoryBouncyCastle implements AndroidDigestFactoryInterface {
+ public Digest getMD5() {
+ return new MD5Digest();
+ }
+ public Digest getSHA1() {
+ return new SHA1Digest();
+ }
+ public Digest getSHA256() {
+ return new SHA256Digest();
+ }
+ public Digest getSHA384() {
+ return new SHA384Digest();
+ }
+ public Digest getSHA512() {
+ return new SHA512Digest();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java
new file mode 100644
index 0000000..e2e020b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryInterface.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 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 org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.Digest;
+
+interface AndroidDigestFactoryInterface {
+ public Digest getMD5();
+ public Digest getSHA1();
+ public Digest getSHA256();
+ public Digest getSHA384();
+ public Digest getSHA512();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java
new file mode 100644
index 0000000..cd07bd9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/AndroidDigestFactoryOpenSSL.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 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 org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.Digest;
+
+public class AndroidDigestFactoryOpenSSL implements AndroidDigestFactoryInterface {
+ public Digest getMD5() {
+ return new OpenSSLDigest.MD5();
+ }
+ public Digest getSHA1() {
+ return new OpenSSLDigest.SHA1();
+ }
+ public Digest getSHA256() {
+ return new OpenSSLDigest.SHA256();
+ }
+ public Digest getSHA384() {
+ return new OpenSSLDigest.SHA384();
+ }
+ public Digest getSHA512() {
+ return new OpenSSLDigest.SHA512();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
new file mode 100644
index 0000000..f2c9967
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/GeneralDigest.java
@@ -0,0 +1,135 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.ExtendedDigest;
+
+/**
+ * base implementation of MD4 family style digest as outlined in
+ * "Handbook of Applied Cryptography", pages 344 - 347.
+ */
+public abstract class GeneralDigest
+ implements ExtendedDigest
+{
+ 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];
+ 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;
+ }
+ }
+
+ public int getByteLength()
+ {
+ return BYTE_LENGTH;
+ }
+
+ protected abstract void processWord(byte[] in, int inOff);
+
+ protected abstract void processLength(long bitLength);
+
+ protected abstract void processBlock();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
new file mode 100644
index 0000000..22d457b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/LongDigest.java
@@ -0,0 +1,354 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.crypto.util.Pack;
+
+/**
+ * Base class for SHA-384 and SHA-512.
+ */
+public abstract class LongDigest
+ implements ExtendedDigest
+{
+ private static final int BYTE_LENGTH = 128;
+
+ private byte[] xBuf;
+ private int xBufOff;
+
+ private long byteCount1;
+ private long byteCount2;
+
+ protected long H1, H2, H3, H4, H5, H6, H7, H8;
+
+ private long[] W = new long[80];
+ private int wOff;
+
+ /**
+ * Constructor for variable length word
+ */
+ protected LongDigest()
+ {
+ xBuf = new byte[8];
+ xBufOff = 0;
+
+ reset();
+ }
+
+ /**
+ * Copy constructor. We are using copy constructors in place
+ * of the Object.clone() interface as this interface is not
+ * supported by J2ME.
+ */
+ protected LongDigest(LongDigest t)
+ {
+ xBuf = new byte[t.xBuf.length];
+ System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
+
+ xBufOff = t.xBufOff;
+ byteCount1 = t.byteCount1;
+ byteCount2 = t.byteCount2;
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+
+ System.arraycopy(t.W, 0, W, 0, t.W.length);
+ wOff = t.wOff;
+ }
+
+ public void update(
+ byte in)
+ {
+ xBuf[xBufOff++] = in;
+
+ if (xBufOff == xBuf.length)
+ {
+ processWord(xBuf, 0);
+ xBufOff = 0;
+ }
+
+ byteCount1++;
+ }
+
+ 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;
+ byteCount1 += xBuf.length;
+ }
+
+ //
+ // load in the remainder.
+ //
+ while (len > 0)
+ {
+ update(in[inOff]);
+
+ inOff++;
+ len--;
+ }
+ }
+
+ public void finish()
+ {
+ adjustByteCounts();
+
+ long lowBitLength = byteCount1 << 3;
+ long hiBitLength = byteCount2;
+
+ //
+ // add the pad bytes.
+ //
+ update((byte)128);
+
+ while (xBufOff != 0)
+ {
+ update((byte)0);
+ }
+
+ processLength(lowBitLength, hiBitLength);
+
+ processBlock();
+ }
+
+ public void reset()
+ {
+ byteCount1 = 0;
+ byteCount2 = 0;
+
+ xBufOff = 0;
+ for (int i = 0; i < xBuf.length; i++)
+ {
+ xBuf[i] = 0;
+ }
+
+ wOff = 0;
+ for (int i = 0; i != W.length; i++)
+ {
+ W[i] = 0;
+ }
+ }
+
+ public int getByteLength()
+ {
+ return BYTE_LENGTH;
+ }
+
+ protected void processWord(
+ byte[] in,
+ int inOff)
+ {
+ W[wOff] = Pack.bigEndianToLong(in, inOff);
+
+ if (++wOff == 16)
+ {
+ processBlock();
+ }
+ }
+
+ /**
+ * adjust the byte counts so that byteCount2 represents the
+ * upper long (less 3 bits) word of the byte count.
+ */
+ private void adjustByteCounts()
+ {
+ if (byteCount1 > 0x1fffffffffffffffL)
+ {
+ byteCount2 += (byteCount1 >>> 61);
+ byteCount1 &= 0x1fffffffffffffffL;
+ }
+ }
+
+ protected void processLength(
+ long lowW,
+ long hiW)
+ {
+ if (wOff > 14)
+ {
+ processBlock();
+ }
+
+ W[14] = hiW;
+ W[15] = lowW;
+ }
+
+ protected void processBlock()
+ {
+ adjustByteCounts();
+
+ //
+ // expand 16 word block into 80 word blocks.
+ //
+ for (int t = 16; t <= 79; t++)
+ {
+ W[t] = Sigma1(W[t - 2]) + W[t - 7] + Sigma0(W[t - 15]) + W[t - 16];
+ }
+
+ //
+ // set up working variables.
+ //
+ long a = H1;
+ long b = H2;
+ long c = H3;
+ long d = H4;
+ long e = H5;
+ long f = H6;
+ long g = H7;
+ long h = H8;
+
+ int t = 0;
+ for(int i = 0; i < 10; i ++)
+ {
+ // t = 8 * i
+ h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
+ d += h;
+ h += Sum0(a) + Maj(a, b, c);
+
+ // t = 8 * i + 1
+ g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
+ c += g;
+ g += Sum0(h) + Maj(h, a, b);
+
+ // t = 8 * i + 2
+ f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
+ b += f;
+ f += Sum0(g) + Maj(g, h, a);
+
+ // t = 8 * i + 3
+ e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
+ a += e;
+ e += Sum0(f) + Maj(f, g, h);
+
+ // t = 8 * i + 4
+ d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
+ h += d;
+ d += Sum0(e) + Maj(e, f, g);
+
+ // t = 8 * i + 5
+ c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
+ g += c;
+ c += Sum0(d) + Maj(d, e, f);
+
+ // t = 8 * i + 6
+ b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
+ f += b;
+ b += Sum0(c) + Maj(c, d, e);
+
+ // t = 8 * i + 7
+ a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
+ e += a;
+ a += Sum0(b) + Maj(b, c, d);
+ }
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+ H5 += e;
+ H6 += f;
+ H7 += g;
+ H8 += h;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ wOff = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ W[i] = 0;
+ }
+ }
+
+ /* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
+ private long Ch(
+ long x,
+ long y,
+ long z)
+ {
+ return ((x & y) ^ ((~x) & z));
+ }
+
+ private long Maj(
+ long x,
+ long y,
+ long z)
+ {
+ return ((x & y) ^ (x & z) ^ (y & z));
+ }
+
+ private long Sum0(
+ long x)
+ {
+ return ((x << 36)|(x >>> 28)) ^ ((x << 30)|(x >>> 34)) ^ ((x << 25)|(x >>> 39));
+ }
+
+ private long Sum1(
+ long x)
+ {
+ return ((x << 50)|(x >>> 14)) ^ ((x << 46)|(x >>> 18)) ^ ((x << 23)|(x >>> 41));
+ }
+
+ private long Sigma0(
+ long x)
+ {
+ return ((x << 63)|(x >>> 1)) ^ ((x << 56)|(x >>> 8)) ^ (x >>> 7);
+ }
+
+ private long Sigma1(
+ long x)
+ {
+ return ((x << 45)|(x >>> 19)) ^ ((x << 3)|(x >>> 61)) ^ (x >>> 6);
+ }
+
+ /* SHA-384 and SHA-512 Constants
+ * (represent the first 64 bits of the fractional parts of the
+ * cube roots of the first sixty-four prime numbers)
+ */
+ static final long K[] = {
+0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, 0xe9b5dba58189dbbcL,
+0x3956c25bf348b538L, 0x59f111f1b605d019L, 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L,
+0xd807aa98a3030242L, 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
+0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, 0xc19bf174cf692694L,
+0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L,
+0x2de92c6f592b0275L, 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
+0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, 0xbf597fc7beef0ee4L,
+0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, 0x06ca6351e003826fL, 0x142929670a0e6e70L,
+0x27b70a8546d22ffcL, 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
+0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, 0x92722c851482353bL,
+0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, 0xc24b8b70d0f89791L, 0xc76c51a30654be30L,
+0xd192e819d6ef5218L, 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
+0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, 0x34b0bcb5e19b48a8L,
+0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L,
+0x748f82ee5defb2fcL, 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
+0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, 0xc67178f2e372532bL,
+0xca273eceea26619cL, 0xd186b8c721c0c207L, 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L,
+0x06f067aa72176fbaL, 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
+0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, 0x431d67c49c100d4cL,
+0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
+ };
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
new file mode 100644
index 0000000..05ed27a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/MD5Digest.java
@@ -0,0 +1,302 @@
+package org.bouncycastle.crypto.digests;
+
+
+/**
+ * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
+ */
+public class MD5Digest
+ extends GeneralDigest
+{
+ private static final int DIGEST_LENGTH = 16;
+
+ private int H1, H2, H3, H4; // IV's
+
+ private int[] X = new int[16];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public MD5Digest()
+ {
+ reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public MD5Digest(MD5Digest t)
+ {
+ super(t);
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+
+ System.arraycopy(t.X, 0, X, 0, t.X.length);
+ xOff = t.xOff;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "MD5";
+ }
+
+ public int getDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+ protected void processWord(
+ byte[] in,
+ int inOff)
+ {
+ X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)
+ | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24);
+
+ if (xOff == 16)
+ {
+ processBlock();
+ }
+ }
+
+ protected void processLength(
+ long bitLength)
+ {
+ if (xOff > 14)
+ {
+ processBlock();
+ }
+
+ X[14] = (int)(bitLength & 0xffffffff);
+ X[15] = (int)(bitLength >>> 32);
+ }
+
+ private void unpackWord(
+ int word,
+ byte[] out,
+ int outOff)
+ {
+ out[outOff] = (byte)word;
+ out[outOff + 1] = (byte)(word >>> 8);
+ out[outOff + 2] = (byte)(word >>> 16);
+ out[outOff + 3] = (byte)(word >>> 24);
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ finish();
+
+ unpackWord(H1, out, outOff);
+ unpackWord(H2, out, outOff + 4);
+ unpackWord(H3, out, outOff + 8);
+ unpackWord(H4, out, outOff + 12);
+
+ reset();
+
+ return DIGEST_LENGTH;
+ }
+
+ /**
+ * reset the chaining variables to the IV values.
+ */
+ public void reset()
+ {
+ super.reset();
+
+ H1 = 0x67452301;
+ H2 = 0xefcdab89;
+ H3 = 0x98badcfe;
+ H4 = 0x10325476;
+
+ xOff = 0;
+
+ for (int i = 0; i != X.length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ //
+ // round 1 left rotates
+ //
+ private static final int S11 = 7;
+ private static final int S12 = 12;
+ private static final int S13 = 17;
+ private static final int S14 = 22;
+
+ //
+ // round 2 left rotates
+ //
+ private static final int S21 = 5;
+ private static final int S22 = 9;
+ private static final int S23 = 14;
+ private static final int S24 = 20;
+
+ //
+ // round 3 left rotates
+ //
+ private static final int S31 = 4;
+ private static final int S32 = 11;
+ private static final int S33 = 16;
+ private static final int S34 = 23;
+
+ //
+ // round 4 left rotates
+ //
+ private static final int S41 = 6;
+ private static final int S42 = 10;
+ private static final int S43 = 15;
+ private static final int S44 = 21;
+
+ /*
+ * rotate int x left n bits.
+ */
+ private int rotateLeft(
+ int x,
+ int n)
+ {
+ return (x << n) | (x >>> (32 - n));
+ }
+
+ /*
+ * F, G, H and I are the basic MD5 functions.
+ */
+ private int F(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & v) | (~u & w);
+ }
+
+ private int G(
+ int u,
+ int v,
+ int w)
+ {
+ return (u & w) | (v & ~w);
+ }
+
+ private int H(
+ int u,
+ int v,
+ int w)
+ {
+ return u ^ v ^ w;
+ }
+
+ private int K(
+ int u,
+ int v,
+ int w)
+ {
+ return v ^ (u | ~w);
+ }
+
+ protected void processBlock()
+ {
+ int a = H1;
+ int b = H2;
+ int c = H3;
+ int d = H4;
+
+ //
+ // Round 1 - F cycle, 16 times.
+ //
+ a = rotateLeft(a + F(b, c, d) + X[ 0] + 0xd76aa478, S11) + b;
+ d = rotateLeft(d + F(a, b, c) + X[ 1] + 0xe8c7b756, S12) + a;
+ c = rotateLeft(c + F(d, a, b) + X[ 2] + 0x242070db, S13) + d;
+ b = rotateLeft(b + F(c, d, a) + X[ 3] + 0xc1bdceee, S14) + c;
+ a = rotateLeft(a + F(b, c, d) + X[ 4] + 0xf57c0faf, S11) + b;
+ d = rotateLeft(d + F(a, b, c) + X[ 5] + 0x4787c62a, S12) + a;
+ c = rotateLeft(c + F(d, a, b) + X[ 6] + 0xa8304613, S13) + d;
+ b = rotateLeft(b + F(c, d, a) + X[ 7] + 0xfd469501, S14) + c;
+ a = rotateLeft(a + F(b, c, d) + X[ 8] + 0x698098d8, S11) + b;
+ d = rotateLeft(d + F(a, b, c) + X[ 9] + 0x8b44f7af, S12) + a;
+ c = rotateLeft(c + F(d, a, b) + X[10] + 0xffff5bb1, S13) + d;
+ b = rotateLeft(b + F(c, d, a) + X[11] + 0x895cd7be, S14) + c;
+ a = rotateLeft(a + F(b, c, d) + X[12] + 0x6b901122, S11) + b;
+ d = rotateLeft(d + F(a, b, c) + X[13] + 0xfd987193, S12) + a;
+ c = rotateLeft(c + F(d, a, b) + X[14] + 0xa679438e, S13) + d;
+ b = rotateLeft(b + F(c, d, a) + X[15] + 0x49b40821, S14) + c;
+
+ //
+ // Round 2 - G cycle, 16 times.
+ //
+ a = rotateLeft(a + G(b, c, d) + X[ 1] + 0xf61e2562, S21) + b;
+ d = rotateLeft(d + G(a, b, c) + X[ 6] + 0xc040b340, S22) + a;
+ c = rotateLeft(c + G(d, a, b) + X[11] + 0x265e5a51, S23) + d;
+ b = rotateLeft(b + G(c, d, a) + X[ 0] + 0xe9b6c7aa, S24) + c;
+ a = rotateLeft(a + G(b, c, d) + X[ 5] + 0xd62f105d, S21) + b;
+ d = rotateLeft(d + G(a, b, c) + X[10] + 0x02441453, S22) + a;
+ c = rotateLeft(c + G(d, a, b) + X[15] + 0xd8a1e681, S23) + d;
+ b = rotateLeft(b + G(c, d, a) + X[ 4] + 0xe7d3fbc8, S24) + c;
+ a = rotateLeft(a + G(b, c, d) + X[ 9] + 0x21e1cde6, S21) + b;
+ d = rotateLeft(d + G(a, b, c) + X[14] + 0xc33707d6, S22) + a;
+ c = rotateLeft(c + G(d, a, b) + X[ 3] + 0xf4d50d87, S23) + d;
+ b = rotateLeft(b + G(c, d, a) + X[ 8] + 0x455a14ed, S24) + c;
+ a = rotateLeft(a + G(b, c, d) + X[13] + 0xa9e3e905, S21) + b;
+ d = rotateLeft(d + G(a, b, c) + X[ 2] + 0xfcefa3f8, S22) + a;
+ c = rotateLeft(c + G(d, a, b) + X[ 7] + 0x676f02d9, S23) + d;
+ b = rotateLeft(b + G(c, d, a) + X[12] + 0x8d2a4c8a, S24) + c;
+
+ //
+ // Round 3 - H cycle, 16 times.
+ //
+ a = rotateLeft(a + H(b, c, d) + X[ 5] + 0xfffa3942, S31) + b;
+ d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x8771f681, S32) + a;
+ c = rotateLeft(c + H(d, a, b) + X[11] + 0x6d9d6122, S33) + d;
+ b = rotateLeft(b + H(c, d, a) + X[14] + 0xfde5380c, S34) + c;
+ a = rotateLeft(a + H(b, c, d) + X[ 1] + 0xa4beea44, S31) + b;
+ d = rotateLeft(d + H(a, b, c) + X[ 4] + 0x4bdecfa9, S32) + a;
+ c = rotateLeft(c + H(d, a, b) + X[ 7] + 0xf6bb4b60, S33) + d;
+ b = rotateLeft(b + H(c, d, a) + X[10] + 0xbebfbc70, S34) + c;
+ a = rotateLeft(a + H(b, c, d) + X[13] + 0x289b7ec6, S31) + b;
+ d = rotateLeft(d + H(a, b, c) + X[ 0] + 0xeaa127fa, S32) + a;
+ c = rotateLeft(c + H(d, a, b) + X[ 3] + 0xd4ef3085, S33) + d;
+ b = rotateLeft(b + H(c, d, a) + X[ 6] + 0x04881d05, S34) + c;
+ a = rotateLeft(a + H(b, c, d) + X[ 9] + 0xd9d4d039, S31) + b;
+ d = rotateLeft(d + H(a, b, c) + X[12] + 0xe6db99e5, S32) + a;
+ c = rotateLeft(c + H(d, a, b) + X[15] + 0x1fa27cf8, S33) + d;
+ b = rotateLeft(b + H(c, d, a) + X[ 2] + 0xc4ac5665, S34) + c;
+
+ //
+ // Round 4 - K cycle, 16 times.
+ //
+ a = rotateLeft(a + K(b, c, d) + X[ 0] + 0xf4292244, S41) + b;
+ d = rotateLeft(d + K(a, b, c) + X[ 7] + 0x432aff97, S42) + a;
+ c = rotateLeft(c + K(d, a, b) + X[14] + 0xab9423a7, S43) + d;
+ b = rotateLeft(b + K(c, d, a) + X[ 5] + 0xfc93a039, S44) + c;
+ a = rotateLeft(a + K(b, c, d) + X[12] + 0x655b59c3, S41) + b;
+ d = rotateLeft(d + K(a, b, c) + X[ 3] + 0x8f0ccc92, S42) + a;
+ c = rotateLeft(c + K(d, a, b) + X[10] + 0xffeff47d, S43) + d;
+ b = rotateLeft(b + K(c, d, a) + X[ 1] + 0x85845dd1, S44) + c;
+ a = rotateLeft(a + K(b, c, d) + X[ 8] + 0x6fa87e4f, S41) + b;
+ d = rotateLeft(d + K(a, b, c) + X[15] + 0xfe2ce6e0, S42) + a;
+ c = rotateLeft(c + K(d, a, b) + X[ 6] + 0xa3014314, S43) + d;
+ b = rotateLeft(b + K(c, d, a) + X[13] + 0x4e0811a1, S44) + c;
+ a = rotateLeft(a + K(b, c, d) + X[ 4] + 0xf7537e82, S41) + b;
+ d = rotateLeft(d + K(a, b, c) + X[11] + 0xbd3af235, S42) + a;
+ c = rotateLeft(c + K(d, a, b) + X[ 2] + 0x2ad7d2bb, S43) + d;
+ b = rotateLeft(b + K(c, d, a) + X[ 9] + 0xeb86d391, S44) + c;
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i != X.length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java
new file mode 100644
index 0000000..6cb0d4a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/NullDigest.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto.digests;
+
+import java.io.ByteArrayOutputStream;
+
+import org.bouncycastle.crypto.Digest;
+
+
+public class NullDigest
+ implements Digest
+{
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public String getAlgorithmName()
+ {
+ return "NULL";
+ }
+
+ public int getDigestSize()
+ {
+ return bOut.size();
+ }
+
+ public void update(byte in)
+ {
+ bOut.write(in);
+ }
+
+ public void update(byte[] in, int inOff, int len)
+ {
+ bOut.write(in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ {
+ byte[] res = bOut.toByteArray();
+
+ System.arraycopy(res, 0, out, outOff, res.length);
+
+ reset();
+
+ return res.length;
+ }
+
+ public void reset()
+ {
+ bOut.reset();
+ }
+} \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java
new file mode 100644
index 0000000..d2f9f25
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/OpenSSLDigest.java
@@ -0,0 +1,159 @@
+/*
+ * 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 org.bouncycastle.crypto.digests;
+
+import org.apache.harmony.xnet.provider.jsse.NativeCrypto;
+import org.bouncycastle.crypto.ExtendedDigest;
+
+/**
+ * Implements the BouncyCastle Digest interface using OpenSSL's EVP API.
+ */
+public class OpenSSLDigest implements ExtendedDigest {
+
+ /**
+ * Holds the standard name of the hashing algorithm, e.g. "SHA-1";
+ */
+ private final String algorithm;
+
+ /**
+ * Holds the EVP_MD for the hashing algorithm, e.g. EVP_get_digestbyname("sha1");
+ */
+ private final int evp_md;
+
+ /**
+ * Holds the output size of the message digest.
+ */
+ private final int size;
+
+ /**
+ * Holds the block size of the message digest.
+ */
+ private final int blockSize;
+
+ /**
+ * Holds a pointer to the native message digest context. It is
+ * lazily initialized to avoid having to reallocate on reset when
+ * its unlikely to be reused.
+ */
+ private int ctx;
+
+ /**
+ * Holds a dummy buffer for writing single bytes to the digest.
+ */
+ private final byte[] singleByte = new byte[1];
+
+ /**
+ * Creates a new OpenSSLMessageDigest instance for the given algorithm
+ * name.
+ */
+ private OpenSSLDigest(String algorithm, int evp_md, int size, int blockSize) {
+ this.algorithm = algorithm;
+ this.evp_md = evp_md;
+ this.size = size;
+ this.blockSize = blockSize;
+ }
+
+ public String getAlgorithmName() {
+ return algorithm;
+ }
+
+ public int getDigestSize() {
+ return size;
+ }
+
+ public int getByteLength() {
+ return blockSize;
+ }
+
+ public void reset() {
+ free();
+ }
+
+ public void update(byte in) {
+ singleByte[0] = in;
+ update(singleByte, 0, 1);
+ }
+
+ public void update(byte[] in, int inOff, int len) {
+ NativeCrypto.EVP_DigestUpdate(getCtx(), in, inOff, len);
+ }
+
+ public int doFinal(byte[] out, int outOff) {
+ int i = NativeCrypto.EVP_DigestFinal(getCtx(), out, outOff);
+ ctx = 0; // EVP_DigestFinal frees the context as a side effect
+ reset();
+ return i;
+ }
+
+ private int getCtx() {
+ if (ctx == 0) {
+ ctx = NativeCrypto.EVP_DigestInit(evp_md);
+ }
+ return ctx;
+ }
+
+ private void free() {
+ if (ctx != 0) {
+ NativeCrypto.EVP_MD_CTX_destroy(ctx);
+ ctx = 0;
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ free();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ public static class MD5 extends OpenSSLDigest {
+ private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("md5");
+ private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+ private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+ public MD5() { super("MD5", EVP_MD, SIZE, BLOCK_SIZE); }
+ }
+
+ public static class SHA1 extends OpenSSLDigest {
+ private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha1");
+ private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+ private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+ public SHA1() { super("SHA-1", EVP_MD, SIZE, BLOCK_SIZE); }
+ }
+
+ public static class SHA256 extends OpenSSLDigest {
+ private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha256");
+ private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+ private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+ public SHA256() { super("SHA-256", EVP_MD, SIZE, BLOCK_SIZE); }
+ }
+
+ public static class SHA384 extends OpenSSLDigest {
+ private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha384");
+ private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+ private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+ public SHA384() { super("SHA-384", EVP_MD, SIZE, BLOCK_SIZE); }
+ }
+
+ public static class SHA512 extends OpenSSLDigest {
+ private static final int EVP_MD = NativeCrypto.EVP_get_digestbyname("sha512");
+ private static final int SIZE = NativeCrypto.EVP_MD_size(EVP_MD);
+ private static final int BLOCK_SIZE = NativeCrypto.EVP_MD_block_size(EVP_MD);
+ public SHA512() { super("SHA-512", EVP_MD, SIZE, BLOCK_SIZE); }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
new file mode 100644
index 0000000..7f8d30a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA1Digest.java
@@ -0,0 +1,290 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.util.Pack;
+
+/**
+ * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
+ *
+ * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
+ * is the "endienness" of the word processing!
+ */
+public 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();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public SHA1Digest(SHA1Digest t)
+ {
+ super(t);
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+
+ System.arraycopy(t.X, 0, X, 0, t.X.length);
+ xOff = t.xOff;
+ }
+
+ 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/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
new file mode 100644
index 0000000..abd9c1b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA256Digest.java
@@ -0,0 +1,295 @@
+package org.bouncycastle.crypto.digests;
+
+
+import org.bouncycastle.crypto.digests.GeneralDigest;
+import org.bouncycastle.crypto.util.Pack;
+
+
+/**
+ * FIPS 180-2 implementation of SHA-256.
+ *
+ * <pre>
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ * </pre>
+ */
+public class SHA256Digest
+ extends GeneralDigest
+{
+ private static final int DIGEST_LENGTH = 32;
+
+ private int H1, H2, H3, H4, H5, H6, H7, H8;
+
+ private int[] X = new int[64];
+ private int xOff;
+
+ /**
+ * Standard constructor
+ */
+ public SHA256Digest()
+ {
+ reset();
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public SHA256Digest(SHA256Digest t)
+ {
+ super(t);
+
+ H1 = t.H1;
+ H2 = t.H2;
+ H3 = t.H3;
+ H4 = t.H4;
+ H5 = t.H5;
+ H6 = t.H6;
+ H7 = t.H7;
+ H8 = t.H8;
+
+ System.arraycopy(t.X, 0, X, 0, t.X.length);
+ xOff = t.xOff;
+ }
+
+ public String getAlgorithmName()
+ {
+ return "SHA-256";
+ }
+
+ 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);
+ Pack.intToBigEndian(H6, out, outOff + 20);
+ Pack.intToBigEndian(H7, out, outOff + 24);
+ Pack.intToBigEndian(H8, out, outOff + 28);
+
+ reset();
+
+ return DIGEST_LENGTH;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public void reset()
+ {
+ super.reset();
+
+ /* SHA-256 initial hash value
+ * The first 32 bits of the fractional parts of the square roots
+ * of the first eight prime numbers
+ */
+
+ H1 = 0x6a09e667;
+ H2 = 0xbb67ae85;
+ H3 = 0x3c6ef372;
+ H4 = 0xa54ff53a;
+ H5 = 0x510e527f;
+ H6 = 0x9b05688c;
+ H7 = 0x1f83d9ab;
+ H8 = 0x5be0cd19;
+
+ xOff = 0;
+ for (int i = 0; i != X.length; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ protected void processBlock()
+ {
+ //
+ // expand 16 word block into 64 word blocks.
+ //
+ for (int t = 16; t <= 63; t++)
+ {
+ X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16];
+ }
+
+ //
+ // set up working variables.
+ //
+ int a = H1;
+ int b = H2;
+ int c = H3;
+ int d = H4;
+ int e = H5;
+ int f = H6;
+ int g = H7;
+ int h = H8;
+
+ int t = 0;
+ for(int i = 0; i < 8; i ++)
+ {
+ // t = 8 * i
+ h += Sum1(e) + Ch(e, f, g) + K[t] + X[t];
+ d += h;
+ h += Sum0(a) + Maj(a, b, c);
+ ++t;
+
+ // t = 8 * i + 1
+ g += Sum1(d) + Ch(d, e, f) + K[t] + X[t];
+ c += g;
+ g += Sum0(h) + Maj(h, a, b);
+ ++t;
+
+ // t = 8 * i + 2
+ f += Sum1(c) + Ch(c, d, e) + K[t] + X[t];
+ b += f;
+ f += Sum0(g) + Maj(g, h, a);
+ ++t;
+
+ // t = 8 * i + 3
+ e += Sum1(b) + Ch(b, c, d) + K[t] + X[t];
+ a += e;
+ e += Sum0(f) + Maj(f, g, h);
+ ++t;
+
+ // t = 8 * i + 4
+ d += Sum1(a) + Ch(a, b, c) + K[t] + X[t];
+ h += d;
+ d += Sum0(e) + Maj(e, f, g);
+ ++t;
+
+ // t = 8 * i + 5
+ c += Sum1(h) + Ch(h, a, b) + K[t] + X[t];
+ g += c;
+ c += Sum0(d) + Maj(d, e, f);
+ ++t;
+
+ // t = 8 * i + 6
+ b += Sum1(g) + Ch(g, h, a) + K[t] + X[t];
+ f += b;
+ b += Sum0(c) + Maj(c, d, e);
+ ++t;
+
+ // t = 8 * i + 7
+ a += Sum1(f) + Ch(f, g, h) + K[t] + X[t];
+ e += a;
+ a += Sum0(b) + Maj(b, c, d);
+ ++t;
+ }
+
+ H1 += a;
+ H2 += b;
+ H3 += c;
+ H4 += d;
+ H5 += e;
+ H6 += f;
+ H7 += g;
+ H8 += h;
+
+ //
+ // reset the offset and clean out the word buffer.
+ //
+ xOff = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ X[i] = 0;
+ }
+ }
+
+ /* SHA-256 functions */
+ private int Ch(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & y) ^ ((~x) & z);
+ }
+
+ private int Maj(
+ int x,
+ int y,
+ int z)
+ {
+ return (x & y) ^ (x & z) ^ (y & z);
+ }
+
+ private int Sum0(
+ int x)
+ {
+ return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10));
+ }
+
+ private int Sum1(
+ int x)
+ {
+ return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7));
+ }
+
+ private int Theta0(
+ int x)
+ {
+ return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
+ }
+
+ private int Theta1(
+ int x)
+ {
+ return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
+ }
+
+ /* SHA-256 Constants
+ * (represent the first 32 bits of the fractional parts of the
+ * cube roots of the first sixty-four prime numbers)
+ */
+ static final int K[] = {
+ 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
+ };
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
new file mode 100644
index 0000000..cdd979a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA384Digest.java
@@ -0,0 +1,87 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.util.Pack;
+
+
+/**
+ * FIPS 180-2 implementation of SHA-384.
+ *
+ * <pre>
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ * </pre>
+ */
+public class SHA384Digest
+ extends LongDigest
+{
+
+ private static final int DIGEST_LENGTH = 48;
+
+ /**
+ * Standard constructor
+ */
+ public SHA384Digest()
+ {
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public SHA384Digest(SHA384Digest t)
+ {
+ super(t);
+ }
+
+ public String getAlgorithmName()
+ {
+ return "SHA-384";
+ }
+
+ public int getDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ finish();
+
+ Pack.longToBigEndian(H1, out, outOff);
+ Pack.longToBigEndian(H2, out, outOff + 8);
+ Pack.longToBigEndian(H3, out, outOff + 16);
+ Pack.longToBigEndian(H4, out, outOff + 24);
+ Pack.longToBigEndian(H5, out, outOff + 32);
+ Pack.longToBigEndian(H6, out, outOff + 40);
+
+ reset();
+
+ return DIGEST_LENGTH;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public void reset()
+ {
+ super.reset();
+
+ /* SHA-384 initial hash value
+ * The first 64 bits of the fractional parts of the square roots
+ * of the 9th through 16th prime numbers
+ */
+ H1 = 0xcbbb9d5dc1059ed8l;
+ H2 = 0x629a292a367cd507l;
+ H3 = 0x9159015a3070dd17l;
+ H4 = 0x152fecd8f70e5939l;
+ H5 = 0x67332667ffc00b31l;
+ H6 = 0x8eb44a8768581511l;
+ H7 = 0xdb0c2e0d64f98fa7l;
+ H8 = 0x47b5481dbefa4fa4l;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
new file mode 100644
index 0000000..34a8e4e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/digests/SHA512Digest.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.crypto.digests;
+
+import org.bouncycastle.crypto.util.Pack;
+
+
+/**
+ * FIPS 180-2 implementation of SHA-512.
+ *
+ * <pre>
+ * block word digest
+ * SHA-1 512 32 160
+ * SHA-256 512 32 256
+ * SHA-384 1024 64 384
+ * SHA-512 1024 64 512
+ * </pre>
+ */
+public class SHA512Digest
+ extends LongDigest
+{
+ private static final int DIGEST_LENGTH = 64;
+
+ /**
+ * Standard constructor
+ */
+ public SHA512Digest()
+ {
+ }
+
+ /**
+ * Copy constructor. This will copy the state of the provided
+ * message digest.
+ */
+ public SHA512Digest(SHA512Digest t)
+ {
+ super(t);
+ }
+
+ public String getAlgorithmName()
+ {
+ return "SHA-512";
+ }
+
+ public int getDigestSize()
+ {
+ return DIGEST_LENGTH;
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ finish();
+
+ Pack.longToBigEndian(H1, out, outOff);
+ Pack.longToBigEndian(H2, out, outOff + 8);
+ Pack.longToBigEndian(H3, out, outOff + 16);
+ Pack.longToBigEndian(H4, out, outOff + 24);
+ Pack.longToBigEndian(H5, out, outOff + 32);
+ Pack.longToBigEndian(H6, out, outOff + 40);
+ Pack.longToBigEndian(H7, out, outOff + 48);
+ Pack.longToBigEndian(H8, out, outOff + 56);
+
+ reset();
+
+ return DIGEST_LENGTH;
+ }
+
+ /**
+ * reset the chaining variables
+ */
+ public void reset()
+ {
+ super.reset();
+
+ /* SHA-512 initial hash value
+ * The first 64 bits of the fractional parts of the square roots
+ * of the first eight prime numbers
+ */
+ H1 = 0x6a09e667f3bcc908L;
+ H2 = 0xbb67ae8584caa73bL;
+ H3 = 0x3c6ef372fe94f82bL;
+ H4 = 0xa54ff53a5f1d36f1L;
+ H5 = 0x510e527fade682d1L;
+ H6 = 0x9b05688c2b3e6c1fL;
+ H7 = 0x1f83d9abfb41bd6bL;
+ H8 = 0x5be0cd19137e2179L;
+ }
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
new file mode 100644
index 0000000..c4719cf
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/OAEPEncoding.java
@@ -0,0 +1,352 @@
+package org.bouncycastle.crypto.encodings;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-changed
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+import java.security.SecureRandom;
+
+/**
+ * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
+ */
+public class OAEPEncoding
+ implements AsymmetricBlockCipher
+{
+ private byte[] defHash;
+ private Digest hash;
+ private Digest mgf1Hash;
+
+ private AsymmetricBlockCipher engine;
+ private SecureRandom random;
+ private boolean forEncryption;
+
+ public OAEPEncoding(
+ AsymmetricBlockCipher cipher)
+ {
+ // BEGIN android-changed
+ this(cipher, AndroidDigestFactory.getSHA1(), null);
+ // END android-changed
+ }
+
+ public OAEPEncoding(
+ AsymmetricBlockCipher cipher,
+ Digest hash)
+ {
+ this(cipher, hash, null);
+ }
+
+ public OAEPEncoding(
+ AsymmetricBlockCipher cipher,
+ Digest hash,
+ byte[] encodingParams)
+ {
+ this(cipher, hash, hash, encodingParams);
+ }
+
+ public OAEPEncoding(
+ AsymmetricBlockCipher cipher,
+ Digest hash,
+ Digest mgf1Hash,
+ byte[] encodingParams)
+ {
+ this.engine = cipher;
+ this.hash = hash;
+ this.mgf1Hash = mgf1Hash;
+ this.defHash = new byte[hash.getDigestSize()];
+
+ if (encodingParams != null)
+ {
+ hash.update(encodingParams, 0, encodingParams.length);
+ }
+
+ hash.doFinal(defHash, 0);
+ }
+
+ public AsymmetricBlockCipher getUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public void init(
+ boolean forEncryption,
+ CipherParameters param)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.random = rParam.getRandom();
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+
+ engine.init(forEncryption, param);
+
+ this.forEncryption = forEncryption;
+ }
+
+ public int getInputBlockSize()
+ {
+ int baseBlockSize = engine.getInputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize - 1 - 2 * defHash.length;
+ }
+ else
+ {
+ return baseBlockSize;
+ }
+ }
+
+ public int getOutputBlockSize()
+ {
+ int baseBlockSize = engine.getOutputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize;
+ }
+ else
+ {
+ return baseBlockSize - 1 - 2 * defHash.length;
+ }
+ }
+
+ public byte[] processBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ if (forEncryption)
+ {
+ return encodeBlock(in, inOff, inLen);
+ }
+ else
+ {
+ return decodeBlock(in, inOff, inLen);
+ }
+ }
+
+ public byte[] encodeBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ byte[] block = new byte[getInputBlockSize() + 1 + 2 * defHash.length];
+
+ //
+ // copy in the message
+ //
+ System.arraycopy(in, inOff, block, block.length - inLen, inLen);
+
+ //
+ // add sentinel
+ //
+ block[block.length - inLen - 1] = 0x01;
+
+ //
+ // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0)
+ //
+
+ //
+ // add the hash of the encoding params.
+ //
+ System.arraycopy(defHash, 0, block, defHash.length, defHash.length);
+
+ //
+ // generate the seed.
+ //
+ byte[] seed = new byte[defHash.length];
+
+ random.nextBytes(seed);
+
+ //
+ // mask the message block.
+ //
+ byte[] mask = maskGeneratorFunction1(seed, 0, seed.length, block.length - defHash.length);
+
+ for (int i = defHash.length; i != block.length; i++)
+ {
+ block[i] ^= mask[i - defHash.length];
+ }
+
+ //
+ // add in the seed
+ //
+ System.arraycopy(seed, 0, block, 0, defHash.length);
+
+ //
+ // mask the seed.
+ //
+ mask = maskGeneratorFunction1(
+ block, defHash.length, block.length - defHash.length, defHash.length);
+
+ for (int i = 0; i != defHash.length; i++)
+ {
+ block[i] ^= mask[i];
+ }
+
+ return engine.processBlock(block, 0, block.length);
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block turns out to
+ * be badly formatted.
+ */
+ public byte[] decodeBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ byte[] data = engine.processBlock(in, inOff, inLen);
+ byte[] block;
+
+ //
+ // as we may have zeros in our leading bytes for the block we produced
+ // on encryption, we need to make sure our decrypted block comes back
+ // the same size.
+ //
+ if (data.length < engine.getOutputBlockSize())
+ {
+ block = new byte[engine.getOutputBlockSize()];
+
+ System.arraycopy(data, 0, block, block.length - data.length, data.length);
+ }
+ else
+ {
+ block = data;
+ }
+
+ if (block.length < (2 * defHash.length) + 1)
+ {
+ throw new InvalidCipherTextException("data too short");
+ }
+
+ //
+ // unmask the seed.
+ //
+ byte[] mask = maskGeneratorFunction1(
+ block, defHash.length, block.length - defHash.length, defHash.length);
+
+ for (int i = 0; i != defHash.length; i++)
+ {
+ block[i] ^= mask[i];
+ }
+
+ //
+ // unmask the message block.
+ //
+ mask = maskGeneratorFunction1(block, 0, defHash.length, block.length - defHash.length);
+
+ for (int i = defHash.length; i != block.length; i++)
+ {
+ block[i] ^= mask[i - defHash.length];
+ }
+
+ //
+ // check the hash of the encoding params.
+ //
+ for (int i = 0; i != defHash.length; i++)
+ {
+ if (defHash[i] != block[defHash.length + i])
+ {
+ throw new InvalidCipherTextException("data hash wrong");
+ }
+ }
+
+ //
+ // find the data block
+ //
+ int start;
+
+ for (start = 2 * defHash.length; start != block.length; start++)
+ {
+ if (block[start] != 0)
+ {
+ break;
+ }
+ }
+
+ if (start >= (block.length - 1) || block[start] != 1)
+ {
+ throw new InvalidCipherTextException("data start wrong " + start);
+ }
+
+ start++;
+
+ //
+ // extract the data block
+ //
+ byte[] output = new byte[block.length - start];
+
+ System.arraycopy(block, start, output, 0, output.length);
+
+ return output;
+ }
+
+ /**
+ * int to octet string.
+ */
+ private void ItoOSP(
+ int i,
+ byte[] sp)
+ {
+ sp[0] = (byte)(i >>> 24);
+ sp[1] = (byte)(i >>> 16);
+ sp[2] = (byte)(i >>> 8);
+ sp[3] = (byte)(i >>> 0);
+ }
+
+ /**
+ * mask generator function, as described in PKCS1v2.
+ */
+ private byte[] maskGeneratorFunction1(
+ byte[] Z,
+ int zOff,
+ int zLen,
+ int length)
+ {
+ byte[] mask = new byte[length];
+ byte[] hashBuf = new byte[mgf1Hash.getDigestSize()];
+ byte[] C = new byte[4];
+ int counter = 0;
+
+ hash.reset();
+
+ do
+ {
+ ItoOSP(counter, C);
+
+ mgf1Hash.update(Z, zOff, zLen);
+ mgf1Hash.update(C, 0, C.length);
+ mgf1Hash.doFinal(hashBuf, 0);
+
+ System.arraycopy(hashBuf, 0, mask, counter * hashBuf.length, hashBuf.length);
+ }
+ while (++counter < (length / hashBuf.length));
+
+ if ((counter * hashBuf.length) < length)
+ {
+ ItoOSP(counter, C);
+
+ mgf1Hash.update(Z, zOff, zLen);
+ mgf1Hash.update(C, 0, C.length);
+ mgf1Hash.doFinal(hashBuf, 0);
+
+ System.arraycopy(hashBuf, 0, mask, counter * hashBuf.length, mask.length - (counter * hashBuf.length));
+ }
+
+ return mask;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
new file mode 100644
index 0000000..8bcfe26
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/encodings/PKCS1Encoding.java
@@ -0,0 +1,253 @@
+package org.bouncycastle.crypto.encodings;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * this does your basic PKCS 1 v1.5 padding - whether or not you should be using this
+ * depends on your application - see PKCS1 Version 2 for details.
+ */
+public class PKCS1Encoding
+ implements AsymmetricBlockCipher
+{
+ /**
+ * 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.
+ * <p>
+ * The system property is checked during construction of the encoding object, it is set to
+ * true by default.
+ * </p>
+ */
+ public static final String STRICT_LENGTH_ENABLED_PROPERTY = "org.bouncycastle.pkcs1.strict";
+
+ private static final int HEADER_LENGTH = 10;
+
+ private SecureRandom random;
+ private AsymmetricBlockCipher engine;
+ private boolean forEncryption;
+ private boolean forPrivateKey;
+ private boolean useStrictLength;
+
+ /**
+ * Basic constructor.
+ * @param cipher
+ */
+ public PKCS1Encoding(
+ AsymmetricBlockCipher cipher)
+ {
+ this.engine = cipher;
+ this.useStrictLength = useStrict();
+ }
+
+ //
+ // for J2ME compatibility
+ //
+ private boolean useStrict()
+ {
+ // required if security manager has been installed.
+ String strict = (String)AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ return System.getProperty(STRICT_LENGTH_ENABLED_PROPERTY);
+ }
+ });
+
+ return strict == null || strict.equals("true");
+ }
+
+ public AsymmetricBlockCipher getUnderlyingCipher()
+ {
+ return engine;
+ }
+
+ public void init(
+ boolean forEncryption,
+ CipherParameters param)
+ {
+ AsymmetricKeyParameter kParam;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.random = rParam.getRandom();
+ kParam = (AsymmetricKeyParameter)rParam.getParameters();
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ kParam = (AsymmetricKeyParameter)param;
+ }
+
+ engine.init(forEncryption, param);
+
+ this.forPrivateKey = kParam.isPrivate();
+ this.forEncryption = forEncryption;
+ }
+
+ public int getInputBlockSize()
+ {
+ int baseBlockSize = engine.getInputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize - HEADER_LENGTH;
+ }
+ else
+ {
+ return baseBlockSize;
+ }
+ }
+
+ public int getOutputBlockSize()
+ {
+ int baseBlockSize = engine.getOutputBlockSize();
+
+ if (forEncryption)
+ {
+ return baseBlockSize;
+ }
+ else
+ {
+ return baseBlockSize - HEADER_LENGTH;
+ }
+ }
+
+ public byte[] processBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ if (forEncryption)
+ {
+ return encodeBlock(in, inOff, inLen);
+ }
+ else
+ {
+ return decodeBlock(in, inOff, inLen);
+ }
+ }
+
+ private byte[] encodeBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ if (inLen > getInputBlockSize())
+ {
+ throw new IllegalArgumentException("input data too large");
+ }
+
+ byte[] block = new byte[engine.getInputBlockSize()];
+
+ if (forPrivateKey)
+ {
+ block[0] = 0x01; // type code 1
+
+ for (int i = 1; i != block.length - inLen - 1; i++)
+ {
+ block[i] = (byte)0xFF;
+ }
+ }
+ else
+ {
+ random.nextBytes(block); // random fill
+
+ block[0] = 0x02; // type code 2
+
+ //
+ // a zero byte marks the end of the padding, so all
+ // the pad bytes must be non-zero.
+ //
+ for (int i = 1; i != block.length - inLen - 1; i++)
+ {
+ while (block[i] == 0)
+ {
+ block[i] = (byte)random.nextInt();
+ }
+ }
+ }
+
+ block[block.length - inLen - 1] = 0x00; // mark the end of the padding
+ System.arraycopy(in, inOff, block, block.length - inLen, inLen);
+
+ return engine.processBlock(block, 0, block.length);
+ }
+
+ /**
+ * @exception InvalidCipherTextException if the decrypted block is not in PKCS1 format.
+ */
+ private byte[] decodeBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ byte[] block = engine.processBlock(in, inOff, inLen);
+
+ if (block.length < getOutputBlockSize())
+ {
+ throw new InvalidCipherTextException("block truncated");
+ }
+
+ byte type = block[0];
+
+ if (type != 1 && type != 2)
+ {
+ throw new InvalidCipherTextException("unknown block type");
+ }
+ // BEGIN android-added
+ if ((type == 1 && forPrivateKey) || (type == 2 && !forPrivateKey))
+ {
+ throw new InvalidCipherTextException("invalid block type " + type);
+ }
+ // END android-added
+
+ if (useStrictLength && block.length != engine.getOutputBlockSize())
+ {
+ throw new InvalidCipherTextException("block incorrect size");
+ }
+
+ //
+ // find and extract the message block.
+ //
+ int start;
+
+ for (start = 1; start != block.length; start++)
+ {
+ byte pad = block[start];
+
+ if (pad == 0)
+ {
+ break;
+ }
+ if (type == 1 && pad != (byte)0xff)
+ {
+ throw new InvalidCipherTextException("block padding incorrect");
+ }
+ }
+
+ start++; // data should start at the next byte
+
+ if (start > block.length || start < HEADER_LENGTH)
+ {
+ throw new InvalidCipherTextException("no data in block");
+ }
+
+ byte[] result = new byte[block.length - start];
+
+ System.arraycopy(block, start, result, 0, result.length);
+
+ return result;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
new file mode 100644
index 0000000..d9bb482
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java
@@ -0,0 +1,547 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first.
+ *
+ * The slowest version uses no static tables at all and computes the values in each round.
+ * <p>
+ * This file contains the middle performance version with 2Kbytes of static tables for round precomputation.
+ *
+ */
+public class AESEngine
+ implements BlockCipher
+{
+ // The S box
+ private static final byte[] S = {
+ (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
+ (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+ (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240,
+ (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+ (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204,
+ (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
+ (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154,
+ (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
+ (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160,
+ (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
+ (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91,
+ (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
+ (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133,
+ (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
+ (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245,
+ (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
+ (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23,
+ (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
+ (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136,
+ (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
+ (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92,
+ (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+ (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169,
+ (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
+ (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198,
+ (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
+ (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14,
+ (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
+ (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
+ (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
+ (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104,
+ (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
+ };
+
+ // The inverse S-box
+ private static final byte[] Si = {
+ (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56,
+ (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+ (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135,
+ (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+ (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61,
+ (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
+ (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178,
+ (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
+ (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22,
+ (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
+ (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
+ (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+ (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10,
+ (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
+ (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2,
+ (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
+ (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234,
+ (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+ (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133,
+ (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
+ (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137,
+ (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
+ (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32,
+ (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
+ (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49,
+ (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
+ (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13,
+ (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+ (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176,
+ (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
+ (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38,
+ (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static final int[] rcon = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 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 =
+ {
+ 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
+ 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
+ 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
+ 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+ 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
+ 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
+ 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
+ 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+ 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
+ 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
+ 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
+ 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+ 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
+ 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
+ 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
+ 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+ 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
+ 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
+ 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
+ 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+ 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
+ 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
+ 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
+ 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+ 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
+ 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
+ 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
+ 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+ 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
+ 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
+ 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
+ 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+ 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
+ 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
+ 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
+ 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+ 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
+ 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
+ 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
+ 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+ 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
+ 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
+ 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
+ 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+ 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
+ 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
+ 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
+ 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+ 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
+ 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
+ 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
+ 0x3a16162c};
+
+private static final int[] Tinv0 =
+ {
+ 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
+ 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
+ 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
+ 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
+ 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
+ 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
+ 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
+ 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
+ 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
+ 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
+ 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
+ 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
+ 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
+ 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
+ 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
+ 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
+ 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
+ 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
+ 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
+ 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
+ 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
+ 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
+ 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
+ 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+ 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
+ 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
+ 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
+ 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
+ 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
+ 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
+ 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
+ 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
+ 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
+ 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
+ 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
+ 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
+ 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
+ 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
+ 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
+ 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
+ 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
+ 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
+ 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
+ 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
+ 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
+ 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
+ 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
+ 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+ 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
+ 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
+ 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
+ 0x4257b8d0};
+
+ private int shift(
+ int r,
+ int shift)
+ {
+ return (r >>> shift) | (r << -shift);
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private static final int m1 = 0x80808080;
+ private static final int m2 = 0x7f7f7f7f;
+ private static final int m3 = 0x0000001b;
+
+ private int FFmulX(int x)
+ {
+ return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
+ }
+
+ /*
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private 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);
+ }
+
+ private 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);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * 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)
+ {
+ int KC = key.length / 4; // key length in words
+ int t;
+
+ if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length))
+ {
+ throw new IllegalArgumentException("Key length not 128/192/256 bits.");
+ }
+
+ 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)
+ {
+ 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++;
+ }
+
+ //
+ // while not enough round key material calculated
+ // calculate new values
+ //
+ int k = (ROUNDS + 1) << 2;
+ for (i = KC; (i < k); i++)
+ {
+ 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;
+ }
+
+ if (!forEncryption)
+ {
+ for (int j = 1; j < ROUNDS; j++)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ W[j][i] = inv_mcol(W[j][i]);
+ }
+ }
+ }
+
+ return W;
+ }
+
+ private int ROUNDS;
+ private int[][] WorkingKey = null;
+ private int C0, C1, C2, C3;
+ private boolean forEncryption;
+
+ private static final int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AESEngine()
+ {
+ }
+
+ /**
+ * initialise an AES cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ {
+ if (params instanceof KeyParameter)
+ {
+ WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption);
+ this.forEncryption = forEncryption;
+ return;
+ }
+
+ throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
+ }
+
+ public String getAlgorithmName()
+ {
+ return "AES";
+ }
+
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ {
+ throw new IllegalStateException("AES engine not initialised");
+ }
+
+ if ((inOff + (32 / 2)) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + (32 / 2)) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (forEncryption)
+ {
+ unpackBlock(in, inOff);
+ encryptBlock(WorkingKey);
+ packBlock(out, outOff);
+ }
+ else
+ {
+ unpackBlock(in, inOff);
+ decryptBlock(WorkingKey);
+ packBlock(out, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void reset()
+ {
+ }
+
+ 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;
+ }
+
+ 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);
+ }
+
+
+ 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;
+
+ 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[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];
+
+ // 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];
+
+ }
+
+ 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;
+
+ 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[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];
+
+ // 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];
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
new file mode 100644
index 0000000..2374be1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESFastEngine.java
@@ -0,0 +1,876 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * an implementation of the AES (Rijndael), from FIPS-197.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>.
+ *
+ * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at
+ * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a>
+ *
+ * There are three levels of tradeoff of speed vs memory
+ * Because java has no preprocessor, they are written as three separate classes from which to choose
+ *
+ * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption
+ * and 4 for decryption.
+ *
+ * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes,
+ * adding 12 rotate operations per round to compute the values contained in the other tables from
+ * the contents of the first
+ *
+ * The slowest version uses no static tables at all and computes the values in each round
+ * <p>
+ * This file contains the fast version with 8Kbytes of static tables for round precomputation
+ *
+ */
+public class AESFastEngine
+ implements BlockCipher
+{
+ // The S box
+ private static final byte[] S = {
+ (byte)99, (byte)124, (byte)119, (byte)123, (byte)242, (byte)107, (byte)111, (byte)197,
+ (byte)48, (byte)1, (byte)103, (byte)43, (byte)254, (byte)215, (byte)171, (byte)118,
+ (byte)202, (byte)130, (byte)201, (byte)125, (byte)250, (byte)89, (byte)71, (byte)240,
+ (byte)173, (byte)212, (byte)162, (byte)175, (byte)156, (byte)164, (byte)114, (byte)192,
+ (byte)183, (byte)253, (byte)147, (byte)38, (byte)54, (byte)63, (byte)247, (byte)204,
+ (byte)52, (byte)165, (byte)229, (byte)241, (byte)113, (byte)216, (byte)49, (byte)21,
+ (byte)4, (byte)199, (byte)35, (byte)195, (byte)24, (byte)150, (byte)5, (byte)154,
+ (byte)7, (byte)18, (byte)128, (byte)226, (byte)235, (byte)39, (byte)178, (byte)117,
+ (byte)9, (byte)131, (byte)44, (byte)26, (byte)27, (byte)110, (byte)90, (byte)160,
+ (byte)82, (byte)59, (byte)214, (byte)179, (byte)41, (byte)227, (byte)47, (byte)132,
+ (byte)83, (byte)209, (byte)0, (byte)237, (byte)32, (byte)252, (byte)177, (byte)91,
+ (byte)106, (byte)203, (byte)190, (byte)57, (byte)74, (byte)76, (byte)88, (byte)207,
+ (byte)208, (byte)239, (byte)170, (byte)251, (byte)67, (byte)77, (byte)51, (byte)133,
+ (byte)69, (byte)249, (byte)2, (byte)127, (byte)80, (byte)60, (byte)159, (byte)168,
+ (byte)81, (byte)163, (byte)64, (byte)143, (byte)146, (byte)157, (byte)56, (byte)245,
+ (byte)188, (byte)182, (byte)218, (byte)33, (byte)16, (byte)255, (byte)243, (byte)210,
+ (byte)205, (byte)12, (byte)19, (byte)236, (byte)95, (byte)151, (byte)68, (byte)23,
+ (byte)196, (byte)167, (byte)126, (byte)61, (byte)100, (byte)93, (byte)25, (byte)115,
+ (byte)96, (byte)129, (byte)79, (byte)220, (byte)34, (byte)42, (byte)144, (byte)136,
+ (byte)70, (byte)238, (byte)184, (byte)20, (byte)222, (byte)94, (byte)11, (byte)219,
+ (byte)224, (byte)50, (byte)58, (byte)10, (byte)73, (byte)6, (byte)36, (byte)92,
+ (byte)194, (byte)211, (byte)172, (byte)98, (byte)145, (byte)149, (byte)228, (byte)121,
+ (byte)231, (byte)200, (byte)55, (byte)109, (byte)141, (byte)213, (byte)78, (byte)169,
+ (byte)108, (byte)86, (byte)244, (byte)234, (byte)101, (byte)122, (byte)174, (byte)8,
+ (byte)186, (byte)120, (byte)37, (byte)46, (byte)28, (byte)166, (byte)180, (byte)198,
+ (byte)232, (byte)221, (byte)116, (byte)31, (byte)75, (byte)189, (byte)139, (byte)138,
+ (byte)112, (byte)62, (byte)181, (byte)102, (byte)72, (byte)3, (byte)246, (byte)14,
+ (byte)97, (byte)53, (byte)87, (byte)185, (byte)134, (byte)193, (byte)29, (byte)158,
+ (byte)225, (byte)248, (byte)152, (byte)17, (byte)105, (byte)217, (byte)142, (byte)148,
+ (byte)155, (byte)30, (byte)135, (byte)233, (byte)206, (byte)85, (byte)40, (byte)223,
+ (byte)140, (byte)161, (byte)137, (byte)13, (byte)191, (byte)230, (byte)66, (byte)104,
+ (byte)65, (byte)153, (byte)45, (byte)15, (byte)176, (byte)84, (byte)187, (byte)22,
+ };
+
+ // The inverse S-box
+ private static final byte[] Si = {
+ (byte)82, (byte)9, (byte)106, (byte)213, (byte)48, (byte)54, (byte)165, (byte)56,
+ (byte)191, (byte)64, (byte)163, (byte)158, (byte)129, (byte)243, (byte)215, (byte)251,
+ (byte)124, (byte)227, (byte)57, (byte)130, (byte)155, (byte)47, (byte)255, (byte)135,
+ (byte)52, (byte)142, (byte)67, (byte)68, (byte)196, (byte)222, (byte)233, (byte)203,
+ (byte)84, (byte)123, (byte)148, (byte)50, (byte)166, (byte)194, (byte)35, (byte)61,
+ (byte)238, (byte)76, (byte)149, (byte)11, (byte)66, (byte)250, (byte)195, (byte)78,
+ (byte)8, (byte)46, (byte)161, (byte)102, (byte)40, (byte)217, (byte)36, (byte)178,
+ (byte)118, (byte)91, (byte)162, (byte)73, (byte)109, (byte)139, (byte)209, (byte)37,
+ (byte)114, (byte)248, (byte)246, (byte)100, (byte)134, (byte)104, (byte)152, (byte)22,
+ (byte)212, (byte)164, (byte)92, (byte)204, (byte)93, (byte)101, (byte)182, (byte)146,
+ (byte)108, (byte)112, (byte)72, (byte)80, (byte)253, (byte)237, (byte)185, (byte)218,
+ (byte)94, (byte)21, (byte)70, (byte)87, (byte)167, (byte)141, (byte)157, (byte)132,
+ (byte)144, (byte)216, (byte)171, (byte)0, (byte)140, (byte)188, (byte)211, (byte)10,
+ (byte)247, (byte)228, (byte)88, (byte)5, (byte)184, (byte)179, (byte)69, (byte)6,
+ (byte)208, (byte)44, (byte)30, (byte)143, (byte)202, (byte)63, (byte)15, (byte)2,
+ (byte)193, (byte)175, (byte)189, (byte)3, (byte)1, (byte)19, (byte)138, (byte)107,
+ (byte)58, (byte)145, (byte)17, (byte)65, (byte)79, (byte)103, (byte)220, (byte)234,
+ (byte)151, (byte)242, (byte)207, (byte)206, (byte)240, (byte)180, (byte)230, (byte)115,
+ (byte)150, (byte)172, (byte)116, (byte)34, (byte)231, (byte)173, (byte)53, (byte)133,
+ (byte)226, (byte)249, (byte)55, (byte)232, (byte)28, (byte)117, (byte)223, (byte)110,
+ (byte)71, (byte)241, (byte)26, (byte)113, (byte)29, (byte)41, (byte)197, (byte)137,
+ (byte)111, (byte)183, (byte)98, (byte)14, (byte)170, (byte)24, (byte)190, (byte)27,
+ (byte)252, (byte)86, (byte)62, (byte)75, (byte)198, (byte)210, (byte)121, (byte)32,
+ (byte)154, (byte)219, (byte)192, (byte)254, (byte)120, (byte)205, (byte)90, (byte)244,
+ (byte)31, (byte)221, (byte)168, (byte)51, (byte)136, (byte)7, (byte)199, (byte)49,
+ (byte)177, (byte)18, (byte)16, (byte)89, (byte)39, (byte)128, (byte)236, (byte)95,
+ (byte)96, (byte)81, (byte)127, (byte)169, (byte)25, (byte)181, (byte)74, (byte)13,
+ (byte)45, (byte)229, (byte)122, (byte)159, (byte)147, (byte)201, (byte)156, (byte)239,
+ (byte)160, (byte)224, (byte)59, (byte)77, (byte)174, (byte)42, (byte)245, (byte)176,
+ (byte)200, (byte)235, (byte)187, (byte)60, (byte)131, (byte)83, (byte)153, (byte)97,
+ (byte)23, (byte)43, (byte)4, (byte)126, (byte)186, (byte)119, (byte)214, (byte)38,
+ (byte)225, (byte)105, (byte)20, (byte)99, (byte)85, (byte)33, (byte)12, (byte)125,
+ };
+
+ // vector used in calculating key schedule (powers of x in GF(256))
+ private static final int[] rcon = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
+ 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 =
+ {
+ 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff,
+ 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102,
+ 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d,
+ 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
+ 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41,
+ 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453,
+ 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d,
+ 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
+ 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2,
+ 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795,
+ 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a,
+ 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
+ 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912,
+ 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc,
+ 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7,
+ 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
+ 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040,
+ 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d,
+ 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0,
+ 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
+ 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a,
+ 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78,
+ 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080,
+ 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
+ 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020,
+ 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18,
+ 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488,
+ 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
+ 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0,
+ 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54,
+ 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b,
+ 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
+ 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992,
+ 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd,
+ 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3,
+ 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
+ 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8,
+ 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4,
+ 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a,
+ 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
+ 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96,
+ 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c,
+ 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7,
+ 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
+ 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9,
+ 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9,
+ 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715,
+ 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
+ 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65,
+ 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929,
+ 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d,
+ 0x3a16162c};
+
+ private static final int[] T1 =
+ {
+ 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d,
+ 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203,
+ 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6,
+ 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
+ 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec,
+ 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7,
+ 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae,
+ 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
+ 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293,
+ 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552,
+ 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f,
+ 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
+ 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b,
+ 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2,
+ 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761,
+ 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
+ 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060,
+ 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46,
+ 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8,
+ 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
+ 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf,
+ 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844,
+ 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0,
+ 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
+ 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030,
+ 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814,
+ 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc,
+ 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
+ 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0,
+ 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e,
+ 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3,
+ 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
+ 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db,
+ 0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e,
+ 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337,
+ 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
+ 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4,
+ 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e,
+ 0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f,
+ 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
+ 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd,
+ 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42,
+ 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701,
+ 0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
+ 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938,
+ 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970,
+ 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592,
+ 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
+ 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da,
+ 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0,
+ 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6,
+ 0x16162c3a};
+
+ private static final int[] T2 =
+ {
+ 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2,
+ 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301,
+ 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab,
+ 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
+ 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad,
+ 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4,
+ 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93,
+ 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
+ 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371,
+ 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7,
+ 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05,
+ 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
+ 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09,
+ 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e,
+ 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6,
+ 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
+ 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020,
+ 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb,
+ 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858,
+ 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
+ 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45,
+ 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c,
+ 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040,
+ 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
+ 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010,
+ 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c,
+ 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44,
+ 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
+ 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060,
+ 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a,
+ 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8,
+ 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
+ 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49,
+ 0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3,
+ 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4,
+ 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
+ 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c,
+ 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a,
+ 0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25,
+ 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
+ 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b,
+ 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e,
+ 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6,
+ 0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
+ 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1,
+ 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9,
+ 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287,
+ 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
+ 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf,
+ 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099,
+ 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb,
+ 0x162c3a16};
+
+ private static final int[] T3 =
+ {
+ 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2,
+ 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101,
+ 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab,
+ 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
+ 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad,
+ 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4,
+ 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393,
+ 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
+ 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171,
+ 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7,
+ 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505,
+ 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
+ 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909,
+ 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e,
+ 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6,
+ 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
+ 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020,
+ 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb,
+ 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858,
+ 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
+ 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545,
+ 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c,
+ 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040,
+ 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
+ 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010,
+ 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c,
+ 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444,
+ 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
+ 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060,
+ 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a,
+ 0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8,
+ 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
+ 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949,
+ 0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3,
+ 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4,
+ 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
+ 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c,
+ 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a,
+ 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525,
+ 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
+ 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b,
+ 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e,
+ 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6,
+ 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
+ 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1,
+ 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9,
+ 0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787,
+ 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
+ 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf,
+ 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999,
+ 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb,
+ 0x2c3a1616};
+
+ private static final int[] Tinv0 =
+ {
+ 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b,
+ 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad,
+ 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526,
+ 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d,
+ 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03,
+ 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458,
+ 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899,
+ 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d,
+ 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1,
+ 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f,
+ 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3,
+ 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3,
+ 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a,
+ 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506,
+ 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05,
+ 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd,
+ 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491,
+ 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6,
+ 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7,
+ 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000,
+ 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd,
+ 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68,
+ 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4,
+ 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c,
+ 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e,
+ 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af,
+ 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644,
+ 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8,
+ 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85,
+ 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc,
+ 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411,
+ 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322,
+ 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6,
+ 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850,
+ 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e,
+ 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf,
+ 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd,
+ 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa,
+ 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea,
+ 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235,
+ 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1,
+ 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43,
+ 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1,
+ 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb,
+ 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a,
+ 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7,
+ 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418,
+ 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478,
+ 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16,
+ 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08,
+ 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48,
+ 0x4257b8d0};
+
+ private static final int[] Tinv1 =
+ {
+ 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb,
+ 0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6,
+ 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680,
+ 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1,
+ 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7,
+ 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3,
+ 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b,
+ 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4,
+ 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0,
+ 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19,
+ 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357,
+ 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5,
+ 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b,
+ 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5,
+ 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532,
+ 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51,
+ 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5,
+ 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697,
+ 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738,
+ 0xeec879db, 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000,
+ 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb,
+ 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821,
+ 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2,
+ 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16,
+ 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b,
+ 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c,
+ 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5,
+ 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863,
+ 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d,
+ 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3,
+ 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa,
+ 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef,
+ 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf,
+ 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d,
+ 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e,
+ 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3,
+ 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09,
+ 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e,
+ 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4,
+ 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0,
+ 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a,
+ 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d,
+ 0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8,
+ 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e,
+ 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c,
+ 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735,
+ 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879,
+ 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886,
+ 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672,
+ 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de,
+ 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874,
+ 0x57b8d042};
+
+ private static final int[] Tinv2 =
+ {
+ 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b,
+ 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d,
+ 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044,
+ 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0,
+ 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f,
+ 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321,
+ 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e,
+ 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a,
+ 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077,
+ 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd,
+ 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f,
+ 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508,
+ 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c,
+ 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be,
+ 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1,
+ 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110,
+ 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d,
+ 0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9,
+ 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b,
+ 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000,
+ 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff,
+ 0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6,
+ 0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, 0xeeb4d296,
+ 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a,
+ 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d,
+ 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07,
+ 0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b,
+ 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1,
+ 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24,
+ 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330,
+ 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48,
+ 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90,
+ 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81,
+ 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92,
+ 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7,
+ 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312,
+ 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978,
+ 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6,
+ 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409,
+ 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066,
+ 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98,
+ 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0,
+ 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f,
+ 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41,
+ 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61,
+ 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9,
+ 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce,
+ 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db,
+ 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3,
+ 0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3,
+ 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c,
+ 0xb8d04257};
+
+ private static final int[] Tinv3 =
+ {
+ 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab,
+ 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76,
+ 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435,
+ 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe,
+ 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x03e75f8f,
+ 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174,
+ 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58,
+ 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace,
+ 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764,
+ 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45,
+ 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f,
+ 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837,
+ 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf,
+ 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05,
+ 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a,
+ 0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e,
+ 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54,
+ 0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd,
+ 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19,
+ 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000,
+ 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e,
+ 0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c,
+ 0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, 0xb4d296ee,
+ 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12,
+ 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09,
+ 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775,
+ 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66,
+ 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4,
+ 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a,
+ 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2,
+ 0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894,
+ 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033,
+ 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5,
+ 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278,
+ 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739,
+ 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225,
+ 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826,
+ 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff,
+ 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f,
+ 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2,
+ 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804,
+ 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef,
+ 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c,
+ 0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b,
+ 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7,
+ 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961,
+ 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14,
+ 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44,
+ 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d,
+ 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c,
+ 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c,
+ 0xd04257b8};
+
+ private int shift(
+ int r,
+ int shift)
+ {
+ return (r >>> shift) | (r << -shift);
+ }
+
+ /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
+
+ private static final int m1 = 0x80808080;
+ private static final int m2 = 0x7f7f7f7f;
+ private static final int m3 = 0x0000001b;
+
+ private int FFmulX(int x)
+ {
+ return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
+ }
+
+ /*
+ The following defines provide alternative definitions of FFmulX that might
+ give improved performance if a fast 32-bit multiply is not available.
+
+ private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
+ private static final int m4 = 0x1b1b1b1b;
+ private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
+
+ */
+
+ private 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);
+ }
+
+
+ private 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);
+ }
+
+ /**
+ * Calculate the necessary round keys
+ * The number of calculations depends on key size and block size
+ * 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)
+ {
+ int KC = key.length / 4; // key length in words
+ int t;
+
+ if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length))
+ {
+ throw new IllegalArgumentException("Key length not 128/192/256 bits.");
+ }
+
+ 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)
+ {
+ 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++;
+ }
+
+ //
+ // while not enough round key material calculated
+ // calculate new values
+ //
+ int k = (ROUNDS + 1) << 2;
+ for (i = KC; (i < k); i++)
+ {
+ 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;
+ }
+
+ if (!forEncryption)
+ {
+ for (int j = 1; j < ROUNDS; j++)
+ {
+ for (i = 0; i < 4; i++)
+ {
+ W[j][i] = inv_mcol(W[j][i]);
+ }
+ }
+ }
+
+ return W;
+ }
+
+ private int ROUNDS;
+ private int[][] WorkingKey = null;
+ private int C0, C1, C2, C3;
+ private boolean forEncryption;
+
+ private static final int BLOCK_SIZE = 16;
+
+ /**
+ * default constructor - 128 bit block size.
+ */
+ public AESFastEngine()
+ {
+ }
+
+ /**
+ * initialise an AES cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ {
+ if (params instanceof KeyParameter)
+ {
+ WorkingKey = generateWorkingKey(((KeyParameter)params).getKey(), forEncryption);
+ this.forEncryption = forEncryption;
+ return;
+ }
+
+ throw new IllegalArgumentException("invalid parameter passed to AES init - " + params.getClass().getName());
+ }
+
+ public String getAlgorithmName()
+ {
+ return "AES";
+ }
+
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (WorkingKey == null)
+ {
+ throw new IllegalStateException("AES engine not initialised");
+ }
+
+ if ((inOff + (32 / 2)) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + (32 / 2)) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (forEncryption)
+ {
+ unpackBlock(in, inOff);
+ encryptBlock(WorkingKey);
+ packBlock(out, outOff);
+ }
+ else
+ {
+ unpackBlock(in, inOff);
+ decryptBlock(WorkingKey);
+ packBlock(out, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void reset()
+ {
+ }
+
+ 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;
+ }
+
+ 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);
+ }
+
+ 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;
+ 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];
+ }
+
+ 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];
+
+ // 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];
+
+ }
+
+ private void decryptBlock(int[][] KW)
+ {
+ int r0, r1, r2, r3;
+
+ C0 ^= KW[ROUNDS][0];
+ C1 ^= KW[ROUNDS][1];
+ C2 ^= KW[ROUNDS][2];
+ C3 ^= KW[ROUNDS][3];
+
+ int r = ROUNDS-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];
+ }
+
+ 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];
+
+ // 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];
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java
new file mode 100644
index 0000000..5d316ac
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/AESWrapEngine.java
@@ -0,0 +1,16 @@
+package org.bouncycastle.crypto.engines;
+
+/**
+ * an implementation of the AES Key Wrapper from the NIST Key Wrap
+ * Specification.
+ * <p>
+ * For further details see: <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
+ */
+public class AESWrapEngine
+ extends RFC3394WrapEngine
+{
+ public AESWrapEngine()
+ {
+ super(new AESEngine());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/BlowfishEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/BlowfishEngine.java
new file mode 100644
index 0000000..6ee1c49
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/BlowfishEngine.java
@@ -0,0 +1,576 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * A class that provides Blowfish key encryption operations,
+ * such as encoding data and generating keys.
+ * All the algorithms herein are from Applied Cryptography
+ * and implement a simplified cryptography interface.
+ */
+public final class BlowfishEngine
+implements BlockCipher
+{
+ private final static int[]
+ KP = {
+ 0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
+ 0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
+ 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
+ 0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917,
+ 0x9216D5D9, 0x8979FB1B
+ },
+
+ KS0 = {
+ 0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7,
+ 0xB8E1AFED, 0x6A267E96, 0xBA7C9045, 0xF12C7F99,
+ 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16,
+ 0x636920D8, 0x71574E69, 0xA458FEA3, 0xF4933D7E,
+ 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE,
+ 0x7B54A41D, 0xC25A59B5, 0x9C30D539, 0x2AF26013,
+ 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
+ 0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E,
+ 0xD71577C1, 0xBD314B27, 0x78AF2FDA, 0x55605C60,
+ 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440,
+ 0x55CA396A, 0x2AAB10B6, 0xB4CC5C34, 0x1141E8CE,
+ 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A,
+ 0x2BA9C55D, 0x741831F6, 0xCE5C3E16, 0x9B87931E,
+ 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
+ 0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193,
+ 0x61D809CC, 0xFB21A991, 0x487CAC60, 0x5DEC8032,
+ 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88,
+ 0x23893E81, 0xD396ACC5, 0x0F6D6FF3, 0x83F44239,
+ 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E,
+ 0x21C66842, 0xF6E96C9A, 0x670C9C61, 0xABD388F0,
+ 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
+ 0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98,
+ 0xA1F1651D, 0x39AF0176, 0x66CA593E, 0x82430E88,
+ 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE,
+ 0xE06F75D8, 0x85C12073, 0x401A449F, 0x56C16AA6,
+ 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D,
+ 0x37D0D724, 0xD00A1248, 0xDB0FEAD3, 0x49F1C09B,
+ 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
+ 0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA,
+ 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2, 0x196A2463,
+ 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F,
+ 0x6DFC511F, 0x9B30952C, 0xCC814544, 0xAF5EBD09,
+ 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3,
+ 0xC0CBA857, 0x45C8740F, 0xD20B5F39, 0xB9D3FBDB,
+ 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
+ 0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8,
+ 0x3C7516DF, 0xFD616B15, 0x2F501EC8, 0xAD0552AB,
+ 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82,
+ 0x9E5C57BB, 0xCA6F8CA0, 0x1A87562E, 0xDF1769DB,
+ 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573,
+ 0x695B27B0, 0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0,
+ 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
+ 0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790,
+ 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341, 0xCEE4C6E8,
+ 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4,
+ 0x95DBDA4D, 0xAE909198, 0xEAAD8E71, 0x6B93D5A0,
+ 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7,
+ 0x8FF6E2FB, 0xF2122B64, 0x8888B812, 0x900DF01C,
+ 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
+ 0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1,
+ 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6, 0xCE89E299,
+ 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9,
+ 0x165FA266, 0x80957705, 0x93CC7314, 0x211A1477,
+ 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF,
+ 0xEBCDAF0C, 0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49,
+ 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
+ 0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA,
+ 0x78C14389, 0xD95A537F, 0x207D5BA2, 0x02E5B9C5,
+ 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41,
+ 0xB3472DCA, 0x7B14A94A, 0x1B510052, 0x9A532915,
+ 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400,
+ 0x08BA6FB5, 0x571BE91F, 0xF296EC6B, 0x2A0DD915,
+ 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
+ 0x53B02D5D, 0xA99F8FA1, 0x08BA4799, 0x6E85076A
+ },
+
+ KS1 = {
+ 0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623,
+ 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8, 0x8FEDB266,
+ 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1,
+ 0x193602A5, 0x75094C29, 0xA0591340, 0xE4183A3E,
+ 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6,
+ 0xA1D29C07, 0xEFE830F5, 0x4D2D38E6, 0xF0255DC1,
+ 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
+ 0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1,
+ 0x687F3584, 0x52A0E286, 0xB79C5305, 0xAA500737,
+ 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8,
+ 0xB03ADA37, 0xF0500C0D, 0xF01C1F04, 0x0200B3FF,
+ 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD,
+ 0xD19113F9, 0x7CA92FF6, 0x94324773, 0x22F54701,
+ 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
+ 0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41,
+ 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1, 0x183EB331,
+ 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF,
+ 0x2CB81290, 0x24977C79, 0x5679B072, 0xBCAF89AF,
+ 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E,
+ 0x5512721F, 0x2E6B7124, 0x501ADDE6, 0x9F84CD87,
+ 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
+ 0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2,
+ 0xEF1C1847, 0x3215D908, 0xDD433B37, 0x24C2BA16,
+ 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD,
+ 0x71DFF89E, 0x10314E55, 0x81AC77D6, 0x5F11199B,
+ 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509,
+ 0xF28FE6ED, 0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E,
+ 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
+ 0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F,
+ 0x803E89D6, 0x5266C825, 0x2E4CC978, 0x9C10B36A,
+ 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4,
+ 0xF2F74EA7, 0x361D2B3D, 0x1939260F, 0x19C27960,
+ 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66,
+ 0xE3BC4595, 0xA67BC883, 0xB17F37D1, 0x018CFF28,
+ 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
+ 0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84,
+ 0x1521B628, 0x29076170, 0xECDD4775, 0x619F1510,
+ 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF,
+ 0xB5735C90, 0x4C70A239, 0xD59E9E0B, 0xCBAADE14,
+ 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E,
+ 0x648B1EAF, 0x19BDF0CA, 0xA02369B9, 0x655ABB50,
+ 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
+ 0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8,
+ 0xF837889A, 0x97E32D77, 0x11ED935F, 0x16681281,
+ 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99,
+ 0x57F584A5, 0x1B227263, 0x9B83C3FF, 0x1AC24696,
+ 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128,
+ 0x58EBF2EF, 0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73,
+ 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
+ 0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0,
+ 0xC742F442, 0xEF6ABBB5, 0x654F3B1D, 0x41CD2105,
+ 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250,
+ 0xCF62A1F2, 0x5B8D2646, 0xFC8883A0, 0xC1C7B6A3,
+ 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285,
+ 0x095BBF00, 0xAD19489D, 0x1462B174, 0x23820E00,
+ 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
+ 0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB,
+ 0x7CDE3759, 0xCBEE7460, 0x4085F2A7, 0xCE77326E,
+ 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735,
+ 0xA969A7AA, 0xC50C06C2, 0x5A04ABFC, 0x800BCADC,
+ 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9,
+ 0xDB73DBD3, 0x105588CD, 0x675FDA79, 0xE3674340,
+ 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
+ 0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7
+ },
+
+ KS2 = {
+ 0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934,
+ 0x411520F7, 0x7602D4F7, 0xBCF46B2E, 0xD4A20068,
+ 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF,
+ 0x1E39F62E, 0x97244546, 0x14214F74, 0xBF8B8840,
+ 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45,
+ 0xBFBC09EC, 0x03BD9785, 0x7FAC6DD0, 0x31CB8504,
+ 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
+ 0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB,
+ 0x68DC1462, 0xD7486900, 0x680EC0A4, 0x27A18DEE,
+ 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6,
+ 0xAACE1E7C, 0xD3375FEC, 0xCE78A399, 0x406B2A42,
+ 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B,
+ 0x1DC9FAF7, 0x4B6D1856, 0x26A36631, 0xEAE397B2,
+ 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
+ 0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527,
+ 0x55533A3A, 0x20838D87, 0xFE6BA9B7, 0xD096954B,
+ 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33,
+ 0xA62A4A56, 0x3F3125F9, 0x5EF47E1C, 0x9029317C,
+ 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3,
+ 0x95C11548, 0xE4C66D22, 0x48C1133F, 0xC70F86DC,
+ 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
+ 0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564,
+ 0x257B7834, 0x602A9C60, 0xDFF8E8A3, 0x1F636C1B,
+ 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115,
+ 0x6B2395E0, 0x333E92E1, 0x3B240B62, 0xEEBEB922,
+ 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728,
+ 0xD0127845, 0x95B794FD, 0x647D0862, 0xE7CCF5F0,
+ 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
+ 0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37,
+ 0xA812DC60, 0xA1EBDDF8, 0x991BE14C, 0xDB6E6B0D,
+ 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804,
+ 0xF1290DC7, 0xCC00FFA3, 0xB5390F92, 0x690FED0B,
+ 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3,
+ 0xBB132F88, 0x515BAD24, 0x7B9479BF, 0x763BD6EB,
+ 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
+ 0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C,
+ 0x6A124237, 0xB79251E7, 0x06A1BBE6, 0x4BFB6350,
+ 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9,
+ 0x44421659, 0x0A121386, 0xD90CEC6E, 0xD5ABEA2A,
+ 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE,
+ 0x9DBC8057, 0xF0F7C086, 0x60787BF8, 0x6003604D,
+ 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
+ 0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F,
+ 0x77A057BE, 0xBDE8AE24, 0x55464299, 0xBF582E61,
+ 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2,
+ 0x5366F9C3, 0xC8B38E74, 0xB475F255, 0x46FCD9B9,
+ 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2,
+ 0x466E598E, 0x20B45770, 0x8CD55591, 0xC902DE4C,
+ 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
+ 0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633,
+ 0xE85A1F02, 0x09F0BE8C, 0x4A99A025, 0x1D6EFE10,
+ 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169,
+ 0xDCB7DA83, 0x573906FE, 0xA1E2CE9B, 0x4FCD7F52,
+ 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027,
+ 0x9AF88C27, 0x773F8641, 0xC3604C06, 0x61A806B5,
+ 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
+ 0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634,
+ 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1, 0xCE591D76,
+ 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24,
+ 0x86E3725F, 0x724D9DB9, 0x1AC15BB4, 0xD39EB8FC,
+ 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4,
+ 0x1E50EF5E, 0xB161E6F8, 0xA28514D9, 0x6C51133C,
+ 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
+ 0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0
+ },
+
+ KS3 = {
+ 0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B,
+ 0x5CB0679E, 0x4FA33742, 0xD3822740, 0x99BC9BBE,
+ 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B,
+ 0xB78C1B6B, 0x21A19045, 0xB26EB1BE, 0x6A366EB4,
+ 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8,
+ 0x530FF8EE, 0x468DDE7D, 0xD5730A1D, 0x4CD04DC6,
+ 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
+ 0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22,
+ 0xC089C2B8, 0x43242EF6, 0xA51E03AA, 0x9CF2D0A4,
+ 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6,
+ 0x2826A2F9, 0xA73A3AE1, 0x4BA99586, 0xEF5562E9,
+ 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59,
+ 0x80E4A915, 0x87B08601, 0x9B09E6AD, 0x3B3EE593,
+ 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
+ 0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28,
+ 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472, 0x5A88F54C,
+ 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B,
+ 0xE8D3C48D, 0x283B57CC, 0xF8D56629, 0x79132E28,
+ 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C,
+ 0x15056DD4, 0x88F46DBA, 0x03A16125, 0x0564F0BD,
+ 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
+ 0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319,
+ 0x7533D928, 0xB155FDF5, 0x03563482, 0x8ABA3CBB,
+ 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F,
+ 0x4DE81751, 0x3830DC8E, 0x379D5862, 0x9320F991,
+ 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32,
+ 0xA8B6E37E, 0xC3293D46, 0x48DE5369, 0x6413E680,
+ 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
+ 0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE,
+ 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F, 0x6BB4E3BB,
+ 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5,
+ 0x72EACEA8, 0xFA6484BB, 0x8D6612AE, 0xBF3C6F47,
+ 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370,
+ 0x740E0D8D, 0xE75B1357, 0xF8721671, 0xAF537D5D,
+ 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
+ 0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048,
+ 0x6F3F3B82, 0x3520AB82, 0x011A1D4B, 0x277227F8,
+ 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD,
+ 0xA08839E1, 0x51CE794B, 0x2F32C9B7, 0xA01FBAC9,
+ 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7,
+ 0x1A908749, 0xD44FBD9A, 0xD0DADECB, 0xD50ADA38,
+ 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
+ 0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C,
+ 0xBF97222C, 0x15E6FC2A, 0x0F91FC71, 0x9B941525,
+ 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1,
+ 0xB6C1075E, 0xE3056A0C, 0x10D25065, 0xCB03A442,
+ 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964,
+ 0x9F1F9532, 0xE0D392DF, 0xD3A0342B, 0x8971F21E,
+ 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
+ 0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D,
+ 0xE54CDA54, 0x1EDAD891, 0xCE6279CF, 0xCD3E7E6F,
+ 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299,
+ 0xF523F357, 0xA6327623, 0x93A83531, 0x56CCCD02,
+ 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC,
+ 0xDE966292, 0x81B949D0, 0x4C50901B, 0x71C65614,
+ 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
+ 0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6,
+ 0x71126905, 0xB2040222, 0xB6CBCF7C, 0xCD769C2B,
+ 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0,
+ 0xBA38209C, 0xF746CE76, 0x77AFA1C5, 0x20756060,
+ 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E,
+ 0x1948C25C, 0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9,
+ 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
+ 0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6
+ };
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ private static final int ROUNDS = 16;
+ private static final int BLOCK_SIZE = 8; // bytes = 64 bits
+ private static final int SBOX_SK = 256;
+ private static final int P_SZ = ROUNDS+2;
+
+ private final int[] S0, S1, S2, S3; // the s-boxes
+ private final int[] P; // the p-array
+
+ private boolean encrypting = false;
+
+ private byte[] workingKey = null;
+
+ public BlowfishEngine()
+ {
+ S0 = new int[SBOX_SK];
+ S1 = new int[SBOX_SK];
+ S2 = new int[SBOX_SK];
+ S3 = new int[SBOX_SK];
+ P = new int[P_SZ];
+ }
+
+ /**
+ * initialise a Blowfish cipher.
+ *
+ * @param encrypting whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ {
+ if (params instanceof KeyParameter)
+ {
+ this.encrypting = encrypting;
+ this.workingKey = ((KeyParameter)params).getKey();
+ setKey(this.workingKey);
+
+ return;
+ }
+
+ throw new IllegalArgumentException("invalid parameter passed to Blowfish init - " + params.getClass().getName());
+ }
+
+ public String getAlgorithmName()
+ {
+ return "Blowfish";
+ }
+
+ public final int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new IllegalStateException("Blowfish not initialised");
+ }
+
+ if ((inOff + BLOCK_SIZE) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BLOCK_SIZE) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (encrypting)
+ {
+ encryptBlock(in, inOff, out, outOff);
+ }
+ else
+ {
+ decryptBlock(in, inOff, out, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void reset()
+ {
+ }
+
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ private int F(int x)
+ {
+ return (((S0[(x >>> 24)] + S1[(x >>> 16) & 0xff])
+ ^ S2[(x >>> 8) & 0xff]) + S3[x & 0xff]);
+ }
+
+ /**
+ * apply the encryption cycle to each value pair in the table.
+ */
+ private void processTable(
+ int xl,
+ int xr,
+ int[] table)
+ {
+ int size = table.length;
+
+ for (int s = 0; s < size; s += 2)
+ {
+ xl ^= P[0];
+
+ for (int i = 1; i < ROUNDS; i += 2)
+ {
+ xr ^= F(xl) ^ P[i];
+ xl ^= F(xr) ^ P[i + 1];
+ }
+
+ xr ^= P[ROUNDS + 1];
+
+ table[s] = xr;
+ table[s + 1] = xl;
+
+ xr = xl; // end of cycle swap
+ xl = table[s];
+ }
+ }
+
+ private void setKey(byte[] key)
+ {
+ /*
+ * - comments are from _Applied Crypto_, Schneier, p338
+ * please be careful comparing the two, AC numbers the
+ * arrays from 1, the enclosed code from 0.
+ *
+ * (1)
+ * Initialise the S-boxes and the P-array, with a fixed string
+ * This string contains the hexadecimal digits of pi (3.141...)
+ */
+ System.arraycopy(KS0, 0, S0, 0, SBOX_SK);
+ System.arraycopy(KS1, 0, S1, 0, SBOX_SK);
+ System.arraycopy(KS2, 0, S2, 0, SBOX_SK);
+ System.arraycopy(KS3, 0, S3, 0, SBOX_SK);
+
+ System.arraycopy(KP, 0, P, 0, P_SZ);
+
+ /*
+ * (2)
+ * Now, XOR P[0] with the first 32 bits of the key, XOR P[1] with the
+ * second 32-bits of the key, and so on for all bits of the key
+ * (up to P[17]). Repeatedly cycle through the key bits until the
+ * entire P-array has been XOR-ed with the key bits
+ */
+ int keyLength = key.length;
+ int keyIndex = 0;
+
+ for (int i=0; i < P_SZ; i++)
+ {
+ // get the 32 bits of the key, in 4 * 8 bit chunks
+ int data = 0x0000000;
+ for (int j=0; j < 4; j++)
+ {
+ // create a 32 bit block
+ data = (data << 8) | (key[keyIndex++] & 0xff);
+
+ // wrap when we get to the end of the key
+ if (keyIndex >= keyLength)
+ {
+ keyIndex = 0;
+ }
+ }
+ // XOR the newly created 32 bit chunk onto the P-array
+ P[i] ^= data;
+ }
+
+ /*
+ * (3)
+ * Encrypt the all-zero string with the Blowfish algorithm, using
+ * the subkeys described in (1) and (2)
+ *
+ * (4)
+ * Replace P1 and P2 with the output of step (3)
+ *
+ * (5)
+ * Encrypt the output of step(3) using the Blowfish algorithm,
+ * with the modified subkeys.
+ *
+ * (6)
+ * Replace P3 and P4 with the output of step (5)
+ *
+ * (7)
+ * Continue the process, replacing all elements of the P-array
+ * and then all four S-boxes in order, with the output of the
+ * continuously changing Blowfish algorithm
+ */
+
+ processTable(0, 0, P);
+ processTable(P[P_SZ - 2], P[P_SZ - 1], S0);
+ processTable(S0[SBOX_SK - 2], S0[SBOX_SK - 1], S1);
+ processTable(S1[SBOX_SK - 2], S1[SBOX_SK - 1], S2);
+ processTable(S2[SBOX_SK - 2], S2[SBOX_SK - 1], S3);
+ }
+
+ /**
+ * Encrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ * The input will be an exact multiple of our blocksize.
+ */
+ private void encryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int xl = BytesTo32bits(src, srcIndex);
+ int xr = BytesTo32bits(src, srcIndex+4);
+
+ xl ^= P[0];
+
+ for (int i = 1; i < ROUNDS; i += 2)
+ {
+ xr ^= F(xl) ^ P[i];
+ xl ^= F(xr) ^ P[i + 1];
+ }
+
+ xr ^= P[ROUNDS + 1];
+
+ Bits32ToBytes(xr, dst, dstIndex);
+ Bits32ToBytes(xl, dst, dstIndex + 4);
+ }
+
+ /**
+ * Decrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ * The input will be an exact multiple of our blocksize.
+ */
+ private void decryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int xl = BytesTo32bits(src, srcIndex);
+ int xr = BytesTo32bits(src, srcIndex + 4);
+
+ xl ^= P[ROUNDS + 1];
+
+ for (int i = ROUNDS; i > 0 ; i -= 2)
+ {
+ xr ^= F(xl) ^ P[i];
+ xl ^= F(xr) ^ P[i - 1];
+ }
+
+ xr ^= P[0];
+
+ Bits32ToBytes(xr, dst, dstIndex);
+ Bits32ToBytes(xl, dst, dstIndex+4);
+ }
+
+ private int BytesTo32bits(byte[] b, int i)
+ {
+ return ((b[i] & 0xff) << 24) |
+ ((b[i+1] & 0xff) << 16) |
+ ((b[i+2] & 0xff) << 8) |
+ ((b[i+3] & 0xff));
+ }
+
+ private void Bits32ToBytes(int in, byte[] b, int offset)
+ {
+ b[offset + 3] = (byte)in;
+ b[offset + 2] = (byte)(in >> 8);
+ b[offset + 1] = (byte)(in >> 16);
+ b[offset] = (byte)(in >> 24);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java
new file mode 100644
index 0000000..b04911c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESEngine.java
@@ -0,0 +1,494 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * a class that provides a basic DES engine.
+ */
+public class DESEngine
+ implements BlockCipher
+{
+ protected static final int BLOCK_SIZE = 8;
+
+ private int[] workingKey = null;
+
+ /**
+ * standard constructor.
+ */
+ public DESEngine()
+ {
+ }
+
+ /**
+ * initialise a DES cipher.
+ *
+ * @param encrypting whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ {
+ if (params instanceof KeyParameter)
+ {
+ if (((KeyParameter)params).getKey().length > 8)
+ {
+ throw new IllegalArgumentException("DES key too long - should be 8 bytes");
+ }
+
+ workingKey = generateWorkingKey(encrypting,
+ ((KeyParameter)params).getKey());
+
+ return;
+ }
+
+ throw new IllegalArgumentException("invalid parameter passed to DES init - " + params.getClass().getName());
+ }
+
+ public String getAlgorithmName()
+ {
+ return "DES";
+ }
+
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new IllegalStateException("DES engine not initialised");
+ }
+
+ if ((inOff + BLOCK_SIZE) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BLOCK_SIZE) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ desFunc(workingKey, in, inOff, out, outOff);
+
+ return BLOCK_SIZE;
+ }
+
+ public void reset()
+ {
+ }
+
+ /**
+ * what follows is mainly taken from "Applied Cryptography", by
+ * Bruce Schneier, however it also bears great resemblance to Richard
+ * Outerbridge's D3DES...
+ */
+
+// private static final short[] Df_Key =
+// {
+// 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
+// 0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10,
+// 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67
+// };
+
+ private static final short[] bytebit =
+ {
+ 0200, 0100, 040, 020, 010, 04, 02, 01
+ };
+
+ private static final int[] bigbyte =
+ {
+ 0x800000, 0x400000, 0x200000, 0x100000,
+ 0x80000, 0x40000, 0x20000, 0x10000,
+ 0x8000, 0x4000, 0x2000, 0x1000,
+ 0x800, 0x400, 0x200, 0x100,
+ 0x80, 0x40, 0x20, 0x10,
+ 0x8, 0x4, 0x2, 0x1
+ };
+
+ /*
+ * Use the key schedule specified in the Standard (ANSI X3.92-1981).
+ */
+
+ private static final byte[] pc1 =
+ {
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
+ };
+
+ private static final byte[] totrot =
+ {
+ 1, 2, 4, 6, 8, 10, 12, 14,
+ 15, 17, 19, 21, 23, 25, 27, 28
+ };
+
+ private static final byte[] pc2 =
+ {
+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
+ };
+
+ private static final int[] SP1 = {
+ 0x01010400, 0x00000000, 0x00010000, 0x01010404,
+ 0x01010004, 0x00010404, 0x00000004, 0x00010000,
+ 0x00000400, 0x01010400, 0x01010404, 0x00000400,
+ 0x01000404, 0x01010004, 0x01000000, 0x00000004,
+ 0x00000404, 0x01000400, 0x01000400, 0x00010400,
+ 0x00010400, 0x01010000, 0x01010000, 0x01000404,
+ 0x00010004, 0x01000004, 0x01000004, 0x00010004,
+ 0x00000000, 0x00000404, 0x00010404, 0x01000000,
+ 0x00010000, 0x01010404, 0x00000004, 0x01010000,
+ 0x01010400, 0x01000000, 0x01000000, 0x00000400,
+ 0x01010004, 0x00010000, 0x00010400, 0x01000004,
+ 0x00000400, 0x00000004, 0x01000404, 0x00010404,
+ 0x01010404, 0x00010004, 0x01010000, 0x01000404,
+ 0x01000004, 0x00000404, 0x00010404, 0x01010400,
+ 0x00000404, 0x01000400, 0x01000400, 0x00000000,
+ 0x00010004, 0x00010400, 0x00000000, 0x01010004
+ };
+
+ private static final int[] SP2 = {
+ 0x80108020, 0x80008000, 0x00008000, 0x00108020,
+ 0x00100000, 0x00000020, 0x80100020, 0x80008020,
+ 0x80000020, 0x80108020, 0x80108000, 0x80000000,
+ 0x80008000, 0x00100000, 0x00000020, 0x80100020,
+ 0x00108000, 0x00100020, 0x80008020, 0x00000000,
+ 0x80000000, 0x00008000, 0x00108020, 0x80100000,
+ 0x00100020, 0x80000020, 0x00000000, 0x00108000,
+ 0x00008020, 0x80108000, 0x80100000, 0x00008020,
+ 0x00000000, 0x00108020, 0x80100020, 0x00100000,
+ 0x80008020, 0x80100000, 0x80108000, 0x00008000,
+ 0x80100000, 0x80008000, 0x00000020, 0x80108020,
+ 0x00108020, 0x00000020, 0x00008000, 0x80000000,
+ 0x00008020, 0x80108000, 0x00100000, 0x80000020,
+ 0x00100020, 0x80008020, 0x80000020, 0x00100020,
+ 0x00108000, 0x00000000, 0x80008000, 0x00008020,
+ 0x80000000, 0x80100020, 0x80108020, 0x00108000
+ };
+
+ private static final int[] SP3 = {
+ 0x00000208, 0x08020200, 0x00000000, 0x08020008,
+ 0x08000200, 0x00000000, 0x00020208, 0x08000200,
+ 0x00020008, 0x08000008, 0x08000008, 0x00020000,
+ 0x08020208, 0x00020008, 0x08020000, 0x00000208,
+ 0x08000000, 0x00000008, 0x08020200, 0x00000200,
+ 0x00020200, 0x08020000, 0x08020008, 0x00020208,
+ 0x08000208, 0x00020200, 0x00020000, 0x08000208,
+ 0x00000008, 0x08020208, 0x00000200, 0x08000000,
+ 0x08020200, 0x08000000, 0x00020008, 0x00000208,
+ 0x00020000, 0x08020200, 0x08000200, 0x00000000,
+ 0x00000200, 0x00020008, 0x08020208, 0x08000200,
+ 0x08000008, 0x00000200, 0x00000000, 0x08020008,
+ 0x08000208, 0x00020000, 0x08000000, 0x08020208,
+ 0x00000008, 0x00020208, 0x00020200, 0x08000008,
+ 0x08020000, 0x08000208, 0x00000208, 0x08020000,
+ 0x00020208, 0x00000008, 0x08020008, 0x00020200
+ };
+
+ private static final int[] SP4 = {
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802080, 0x00800081, 0x00800001, 0x00002001,
+ 0x00000000, 0x00802000, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00800080, 0x00800001,
+ 0x00000001, 0x00002000, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002001, 0x00002080,
+ 0x00800081, 0x00000001, 0x00002080, 0x00800080,
+ 0x00002000, 0x00802080, 0x00802081, 0x00000081,
+ 0x00800080, 0x00800001, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00000000, 0x00802000,
+ 0x00002080, 0x00800080, 0x00800081, 0x00000001,
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802081, 0x00000081, 0x00000001, 0x00002000,
+ 0x00800001, 0x00002001, 0x00802080, 0x00800081,
+ 0x00002001, 0x00002080, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002000, 0x00802080
+ };
+
+ private static final int[] SP5 = {
+ 0x00000100, 0x02080100, 0x02080000, 0x42000100,
+ 0x00080000, 0x00000100, 0x40000000, 0x02080000,
+ 0x40080100, 0x00080000, 0x02000100, 0x40080100,
+ 0x42000100, 0x42080000, 0x00080100, 0x40000000,
+ 0x02000000, 0x40080000, 0x40080000, 0x00000000,
+ 0x40000100, 0x42080100, 0x42080100, 0x02000100,
+ 0x42080000, 0x40000100, 0x00000000, 0x42000000,
+ 0x02080100, 0x02000000, 0x42000000, 0x00080100,
+ 0x00080000, 0x42000100, 0x00000100, 0x02000000,
+ 0x40000000, 0x02080000, 0x42000100, 0x40080100,
+ 0x02000100, 0x40000000, 0x42080000, 0x02080100,
+ 0x40080100, 0x00000100, 0x02000000, 0x42080000,
+ 0x42080100, 0x00080100, 0x42000000, 0x42080100,
+ 0x02080000, 0x00000000, 0x40080000, 0x42000000,
+ 0x00080100, 0x02000100, 0x40000100, 0x00080000,
+ 0x00000000, 0x40080000, 0x02080100, 0x40000100
+ };
+
+ private static final int[] SP6 = {
+ 0x20000010, 0x20400000, 0x00004000, 0x20404010,
+ 0x20400000, 0x00000010, 0x20404010, 0x00400000,
+ 0x20004000, 0x00404010, 0x00400000, 0x20000010,
+ 0x00400010, 0x20004000, 0x20000000, 0x00004010,
+ 0x00000000, 0x00400010, 0x20004010, 0x00004000,
+ 0x00404000, 0x20004010, 0x00000010, 0x20400010,
+ 0x20400010, 0x00000000, 0x00404010, 0x20404000,
+ 0x00004010, 0x00404000, 0x20404000, 0x20000000,
+ 0x20004000, 0x00000010, 0x20400010, 0x00404000,
+ 0x20404010, 0x00400000, 0x00004010, 0x20000010,
+ 0x00400000, 0x20004000, 0x20000000, 0x00004010,
+ 0x20000010, 0x20404010, 0x00404000, 0x20400000,
+ 0x00404010, 0x20404000, 0x00000000, 0x20400010,
+ 0x00000010, 0x00004000, 0x20400000, 0x00404010,
+ 0x00004000, 0x00400010, 0x20004010, 0x00000000,
+ 0x20404000, 0x20000000, 0x00400010, 0x20004010
+ };
+
+ private static final int[] SP7 = {
+ 0x00200000, 0x04200002, 0x04000802, 0x00000000,
+ 0x00000800, 0x04000802, 0x00200802, 0x04200800,
+ 0x04200802, 0x00200000, 0x00000000, 0x04000002,
+ 0x00000002, 0x04000000, 0x04200002, 0x00000802,
+ 0x04000800, 0x00200802, 0x00200002, 0x04000800,
+ 0x04000002, 0x04200000, 0x04200800, 0x00200002,
+ 0x04200000, 0x00000800, 0x00000802, 0x04200802,
+ 0x00200800, 0x00000002, 0x04000000, 0x00200800,
+ 0x04000000, 0x00200800, 0x00200000, 0x04000802,
+ 0x04000802, 0x04200002, 0x04200002, 0x00000002,
+ 0x00200002, 0x04000000, 0x04000800, 0x00200000,
+ 0x04200800, 0x00000802, 0x00200802, 0x04200800,
+ 0x00000802, 0x04000002, 0x04200802, 0x04200000,
+ 0x00200800, 0x00000000, 0x00000002, 0x04200802,
+ 0x00000000, 0x00200802, 0x04200000, 0x00000800,
+ 0x04000002, 0x04000800, 0x00000800, 0x00200002
+ };
+
+ private static final int[] SP8 = {
+ 0x10001040, 0x00001000, 0x00040000, 0x10041040,
+ 0x10000000, 0x10001040, 0x00000040, 0x10000000,
+ 0x00040040, 0x10040000, 0x10041040, 0x00041000,
+ 0x10041000, 0x00041040, 0x00001000, 0x00000040,
+ 0x10040000, 0x10000040, 0x10001000, 0x00001040,
+ 0x00041000, 0x00040040, 0x10040040, 0x10041000,
+ 0x00001040, 0x00000000, 0x00000000, 0x10040040,
+ 0x10000040, 0x10001000, 0x00041040, 0x00040000,
+ 0x00041040, 0x00040000, 0x10041000, 0x00001000,
+ 0x00000040, 0x10040040, 0x00001000, 0x00041040,
+ 0x10001000, 0x00000040, 0x10000040, 0x10040000,
+ 0x10040040, 0x10000000, 0x00040000, 0x10001040,
+ 0x00000000, 0x10041040, 0x00040040, 0x10000040,
+ 0x10040000, 0x10001000, 0x10001040, 0x00000000,
+ 0x10041040, 0x00041000, 0x00041000, 0x00001040,
+ 0x00001040, 0x00040040, 0x10000000, 0x10041000
+ };
+
+ /**
+ * 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.
+ * (whoever, and wherever they are!).
+ */
+ protected int[] generateWorkingKey(
+ boolean encrypting,
+ byte[] key)
+ {
+ int[] newKey = new int[32];
+ boolean[] pc1m = new boolean[56],
+ pcr = new boolean[56];
+
+ for (int j = 0; j < 56; j++)
+ {
+ int l = pc1[j];
+
+ pc1m[j] = ((key[l >>> 3] & bytebit[l & 07]) != 0);
+ }
+
+ for (int i = 0; i < 16; i++)
+ {
+ int l, m, n;
+
+ if (encrypting)
+ {
+ m = i << 1;
+ }
+ else
+ {
+ m = (15 - i) << 1;
+ }
+
+ n = m + 1;
+ newKey[m] = newKey[n] = 0;
+
+ for (int j = 0; j < 28; j++)
+ {
+ l = j + totrot[i];
+ if (l < 28)
+ {
+ pcr[j] = pc1m[l];
+ }
+ else
+ {
+ pcr[j] = pc1m[l - 28];
+ }
+ }
+
+ for (int j = 28; j < 56; j++)
+ {
+ l = j + totrot[i];
+ if (l < 56)
+ {
+ pcr[j] = pc1m[l];
+ }
+ else
+ {
+ pcr[j] = pc1m[l - 28];
+ }
+ }
+
+ for (int j = 0; j < 24; j++)
+ {
+ if (pcr[pc2[j]])
+ {
+ newKey[m] |= bigbyte[j];
+ }
+
+ if (pcr[pc2[j + 24]])
+ {
+ newKey[n] |= bigbyte[j];
+ }
+ }
+ }
+
+ //
+ // store the processed key
+ //
+ for (int i = 0; i != 32; i += 2)
+ {
+ int i1, i2;
+
+ i1 = newKey[i];
+ i2 = newKey[i + 1];
+
+ newKey[i] = ((i1 & 0x00fc0000) << 6) | ((i1 & 0x00000fc0) << 10)
+ | ((i2 & 0x00fc0000) >>> 10) | ((i2 & 0x00000fc0) >>> 6);
+
+ newKey[i + 1] = ((i1 & 0x0003f000) << 12) | ((i1 & 0x0000003f) << 16)
+ | ((i2 & 0x0003f000) >>> 4) | (i2 & 0x0000003f);
+ }
+
+ return newKey;
+ }
+
+ /**
+ * the DES engine.
+ */
+ protected void desFunc(
+ int[] wKey,
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ int work, right, left;
+
+ left = (in[inOff + 0] & 0xff) << 24;
+ left |= (in[inOff + 1] & 0xff) << 16;
+ left |= (in[inOff + 2] & 0xff) << 8;
+ left |= (in[inOff + 3] & 0xff);
+
+ right = (in[inOff + 4] & 0xff) << 24;
+ right |= (in[inOff + 5] & 0xff) << 16;
+ right |= (in[inOff + 6] & 0xff) << 8;
+ right |= (in[inOff + 7] & 0xff);
+
+ work = ((left >>> 4) ^ right) & 0x0f0f0f0f;
+ right ^= work;
+ left ^= (work << 4);
+ work = ((left >>> 16) ^ right) & 0x0000ffff;
+ right ^= work;
+ left ^= (work << 16);
+ work = ((right >>> 2) ^ left) & 0x33333333;
+ left ^= work;
+ right ^= (work << 2);
+ work = ((right >>> 8) ^ left) & 0x00ff00ff;
+ left ^= work;
+ right ^= (work << 8);
+ right = ((right << 1) | ((right >>> 31) & 1)) & 0xffffffff;
+ work = (left ^ right) & 0xaaaaaaaa;
+ left ^= work;
+ right ^= work;
+ left = ((left << 1) | ((left >>> 31) & 1)) & 0xffffffff;
+
+ for (int round = 0; round < 8; round++)
+ {
+ int fval;
+
+ work = (right << 28) | (right >>> 4);
+ work ^= wKey[round * 4 + 0];
+ fval = SP7[ work & 0x3f];
+ fval |= SP5[(work >>> 8) & 0x3f];
+ fval |= SP3[(work >>> 16) & 0x3f];
+ fval |= SP1[(work >>> 24) & 0x3f];
+ work = right ^ wKey[round * 4 + 1];
+ fval |= SP8[ work & 0x3f];
+ fval |= SP6[(work >>> 8) & 0x3f];
+ fval |= SP4[(work >>> 16) & 0x3f];
+ fval |= SP2[(work >>> 24) & 0x3f];
+ left ^= fval;
+ work = (left << 28) | (left >>> 4);
+ work ^= wKey[round * 4 + 2];
+ fval = SP7[ work & 0x3f];
+ fval |= SP5[(work >>> 8) & 0x3f];
+ fval |= SP3[(work >>> 16) & 0x3f];
+ fval |= SP1[(work >>> 24) & 0x3f];
+ work = left ^ wKey[round * 4 + 3];
+ fval |= SP8[ work & 0x3f];
+ fval |= SP6[(work >>> 8) & 0x3f];
+ fval |= SP4[(work >>> 16) & 0x3f];
+ fval |= SP2[(work >>> 24) & 0x3f];
+ right ^= fval;
+ }
+
+ right = (right << 31) | (right >>> 1);
+ work = (left ^ right) & 0xaaaaaaaa;
+ left ^= work;
+ right ^= work;
+ left = (left << 31) | (left >>> 1);
+ work = ((left >>> 8) ^ right) & 0x00ff00ff;
+ right ^= work;
+ left ^= (work << 8);
+ work = ((left >>> 2) ^ right) & 0x33333333;
+ right ^= work;
+ left ^= (work << 2);
+ work = ((right >>> 16) ^ left) & 0x0000ffff;
+ left ^= work;
+ right ^= (work << 16);
+ work = ((right >>> 4) ^ left) & 0x0f0f0f0f;
+ left ^= work;
+ right ^= (work << 4);
+
+ out[outOff + 0] = (byte)((right >>> 24) & 0xff);
+ out[outOff + 1] = (byte)((right >>> 16) & 0xff);
+ out[outOff + 2] = (byte)((right >>> 8) & 0xff);
+ out[outOff + 3] = (byte)(right & 0xff);
+ out[outOff + 4] = (byte)((left >>> 24) & 0xff);
+ out[outOff + 5] = (byte)((left >>> 16) & 0xff);
+ out[outOff + 6] = (byte)((left >>> 8) & 0xff);
+ out[outOff + 7] = (byte)(left & 0xff);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
new file mode 100644
index 0000000..d1935ec
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeEngine.java
@@ -0,0 +1,126 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * a class that provides a basic DESede (or Triple DES) engine.
+ */
+public class DESedeEngine
+ extends DESEngine
+{
+ protected static final int BLOCK_SIZE = 8;
+
+ private int[] workingKey1 = null;
+ private int[] workingKey2 = null;
+ private int[] workingKey3 = null;
+
+ private boolean forEncryption;
+
+ /**
+ * standard constructor.
+ */
+ public DESedeEngine()
+ {
+ }
+
+ /**
+ * initialise a DESede cipher.
+ *
+ * @param encrypting whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ {
+ if (!(params instanceof KeyParameter))
+ {
+ throw new IllegalArgumentException("invalid parameter passed to DESede init - " + params.getClass().getName());
+ }
+
+ byte[] keyMaster = ((KeyParameter)params).getKey();
+
+ if (keyMaster.length != 24 && keyMaster.length != 16)
+ {
+ throw new IllegalArgumentException("key size must be 16 or 24 bytes.");
+ }
+
+ this.forEncryption = encrypting;
+
+ byte[] key1 = new byte[8];
+ System.arraycopy(keyMaster, 0, key1, 0, key1.length);
+ workingKey1 = generateWorkingKey(encrypting, key1);
+
+ byte[] key2 = new byte[8];
+ System.arraycopy(keyMaster, 8, key2, 0, key2.length);
+ workingKey2 = generateWorkingKey(!encrypting, key2);
+
+ if (keyMaster.length == 24)
+ {
+ byte[] key3 = new byte[8];
+ System.arraycopy(keyMaster, 16, key3, 0, key3.length);
+ workingKey3 = generateWorkingKey(encrypting, key3);
+ }
+ else // 16 byte key
+ {
+ workingKey3 = workingKey1;
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return "DESede";
+ }
+
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (workingKey1 == null)
+ {
+ throw new IllegalStateException("DESede engine not initialised");
+ }
+
+ if ((inOff + BLOCK_SIZE) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BLOCK_SIZE) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ byte[] temp = new byte[BLOCK_SIZE];
+
+ if (forEncryption)
+ {
+ desFunc(workingKey1, in, inOff, temp, 0);
+ desFunc(workingKey2, temp, 0, temp, 0);
+ desFunc(workingKey3, temp, 0, out, outOff);
+ }
+ else
+ {
+ desFunc(workingKey3, in, inOff, temp, 0);
+ desFunc(workingKey2, temp, 0, temp, 0);
+ desFunc(workingKey1, temp, 0, out, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void reset()
+ {
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
new file mode 100644
index 0000000..d0c04f2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/DESedeWrapEngine.java
@@ -0,0 +1,352 @@
+package org.bouncycastle.crypto.engines;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Wrapper;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-changed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * Wrap keys according to
+ * <A HREF="http://www.ietf.org/internet-drafts/draft-ietf-smime-key-wrap-01.txt">
+ * draft-ietf-smime-key-wrap-01.txt</A>.
+ * <p>
+ * Note:
+ * <ul>
+ * <li>this is based on a draft, and as such is subject to change - don't use this class for anything requiring long term storage.
+ * <li>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.
+ * </ul>
+ */
+public class DESedeWrapEngine
+ implements Wrapper
+{
+ /** Field engine */
+ private CBCBlockCipher engine;
+
+ /** Field param */
+ private KeyParameter param;
+
+ /** Field paramPlusIV */
+ private ParametersWithIV paramPlusIV;
+
+ /** Field iv */
+ private byte[] iv;
+
+ /** Field forWrapping */
+ private boolean forWrapping;
+
+ /** Field IV2 */
+ private static final byte[] IV2 = { (byte) 0x4a, (byte) 0xdd, (byte) 0xa2,
+ (byte) 0x2c, (byte) 0x79, (byte) 0xe8,
+ (byte) 0x21, (byte) 0x05 };
+
+ //
+ // checksum digest
+ //
+ // BEGIN android-changed
+ Digest sha1 = AndroidDigestFactory.getSHA1();
+ // END android-changed
+ byte[] digest = new byte[20];
+
+ /**
+ * Method init
+ *
+ * @param forWrapping
+ * @param param
+ */
+ public void init(boolean forWrapping, CipherParameters param)
+ {
+
+ this.forWrapping = forWrapping;
+ this.engine = new CBCBlockCipher(new DESedeEngine());
+
+ SecureRandom sr;
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom pr = (ParametersWithRandom) param;
+ param = pr.getParameters();
+ sr = pr.getRandom();
+ }
+ else
+ {
+ sr = new SecureRandom();
+ }
+
+ if (param instanceof KeyParameter)
+ {
+ this.param = (KeyParameter)param;
+
+ if (this.forWrapping)
+ {
+
+ // Hm, we have no IV but we want to wrap ?!?
+ // well, then we have to create our own IV.
+ this.iv = new byte[8];
+ sr.nextBytes(iv);
+
+ this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+ }
+ }
+ else if (param instanceof ParametersWithIV)
+ {
+ this.paramPlusIV = (ParametersWithIV)param;
+ this.iv = this.paramPlusIV.getIV();
+ this.param = (KeyParameter)this.paramPlusIV.getParameters();
+
+ if (this.forWrapping)
+ {
+ if ((this.iv == null) || (this.iv.length != 8))
+ {
+ throw new IllegalArgumentException("IV is not 8 octets");
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "You should not supply an IV for unwrapping");
+ }
+ }
+ }
+
+ /**
+ * Method getAlgorithmName
+ *
+ * @return the algorithm name "DESede".
+ */
+ public String getAlgorithmName()
+ {
+ return "DESede";
+ }
+
+ /**
+ * Method wrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return the wrapped bytes.
+ */
+ public byte[] wrap(byte[] in, int inOff, int inLen)
+ {
+ if (!forWrapping)
+ {
+ throw new IllegalStateException("Not initialized for wrapping");
+ }
+
+ byte keyToBeWrapped[] = new byte[inLen];
+
+ System.arraycopy(in, inOff, keyToBeWrapped, 0, inLen);
+
+ // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+ byte[] CKS = calculateCMSKeyChecksum(keyToBeWrapped);
+
+ // Let WKCKS = WK || CKS where || is concatenation.
+ byte[] WKCKS = new byte[keyToBeWrapped.length + CKS.length];
+
+ System.arraycopy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.length);
+ System.arraycopy(CKS, 0, WKCKS, keyToBeWrapped.length, CKS.length);
+
+ // Encrypt WKCKS in CBC mode using KEK as the key and IV as the
+ // initialization vector. Call the results TEMP1.
+
+ int blockSize = engine.getBlockSize();
+
+ if (WKCKS.length % blockSize != 0)
+ {
+ throw new IllegalStateException("Not multiple of block length");
+ }
+
+ engine.init(true, paramPlusIV);
+
+ byte TEMP1[] = new byte[WKCKS.length];
+
+ for (int currentBytePos = 0; currentBytePos != WKCKS.length; currentBytePos += blockSize)
+ {
+ engine.processBlock(WKCKS, currentBytePos, TEMP1, currentBytePos);
+ }
+
+ // Let TEMP2 = IV || TEMP1.
+ byte[] TEMP2 = new byte[this.iv.length + TEMP1.length];
+
+ System.arraycopy(this.iv, 0, TEMP2, 0, this.iv.length);
+ System.arraycopy(TEMP1, 0, TEMP2, this.iv.length, TEMP1.length);
+
+ // Reverse the order of the octets in TEMP2 and call the result TEMP3.
+ byte[] TEMP3 = reverse(TEMP2);
+
+ // Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+ // of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
+ // result. It is 40 octets long if a 168 bit key is being wrapped.
+ ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+
+ this.engine.init(true, param2);
+
+ for (int currentBytePos = 0; currentBytePos != TEMP3.length; currentBytePos += blockSize)
+ {
+ engine.processBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
+ }
+
+ return TEMP3;
+ }
+
+ /**
+ * Method unwrap
+ *
+ * @param in
+ * @param inOff
+ * @param inLen
+ * @return the unwrapped bytes.
+ * @throws InvalidCipherTextException
+ */
+ public byte[] unwrap(byte[] in, int inOff, int inLen)
+ throws InvalidCipherTextException
+ {
+ if (forWrapping)
+ {
+ throw new IllegalStateException("Not set for unwrapping");
+ }
+
+ if (in == null)
+ {
+ throw new InvalidCipherTextException("Null pointer as ciphertext");
+ }
+
+ final int blockSize = engine.getBlockSize();
+ if (inLen % blockSize != 0)
+ {
+ throw new InvalidCipherTextException("Ciphertext not multiple of " + blockSize);
+ }
+
+ /*
+ // Check if the length of the cipher text is reasonable given the key
+ // type. It must be 40 bytes for a 168 bit key and either 32, 40, or
+ // 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
+ // or inconsistent with the algorithm for which the key is intended,
+ // return error.
+ //
+ // we do not accept 168 bit keys. it has to be 192 bit.
+ int lengthA = (estimatedKeyLengthInBit / 8) + 16;
+ int lengthB = estimatedKeyLengthInBit % 8;
+
+ if ((lengthA != keyToBeUnwrapped.length) || (lengthB != 0)) {
+ throw new XMLSecurityException("empty");
+ }
+ */
+
+ // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+ // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
+ ParametersWithIV param2 = new ParametersWithIV(this.param, IV2);
+
+ this.engine.init(false, param2);
+
+ byte TEMP3[] = new byte[inLen];
+
+ for (int currentBytePos = 0; currentBytePos != inLen; currentBytePos += blockSize)
+ {
+ engine.processBlock(in, inOff + currentBytePos, TEMP3, currentBytePos);
+ }
+
+ // Reverse the order of the octets in TEMP3 and call the result TEMP2.
+ byte[] TEMP2 = reverse(TEMP3);
+
+ // Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
+ this.iv = new byte[8];
+
+ byte[] TEMP1 = new byte[TEMP2.length - 8];
+
+ System.arraycopy(TEMP2, 0, this.iv, 0, 8);
+ System.arraycopy(TEMP2, 8, TEMP1, 0, TEMP2.length - 8);
+
+ // Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
+ // found in the previous step. Call the result WKCKS.
+ this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
+
+ this.engine.init(false, this.paramPlusIV);
+
+ byte[] WKCKS = new byte[TEMP1.length];
+
+ for (int currentBytePos = 0; currentBytePos != WKCKS.length; currentBytePos += blockSize)
+ {
+ engine.processBlock(TEMP1, currentBytePos, WKCKS, currentBytePos);
+ }
+
+ // Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are
+ // those octets before the CKS.
+ byte[] result = new byte[WKCKS.length - 8];
+ byte[] CKStoBeVerified = new byte[8];
+
+ System.arraycopy(WKCKS, 0, result, 0, WKCKS.length - 8);
+ System.arraycopy(WKCKS, WKCKS.length - 8, CKStoBeVerified, 0, 8);
+
+ // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+ // with the CKS extracted in the above step. If they are not equal, return error.
+ if (!checkCMSKeyChecksum(result, CKStoBeVerified))
+ {
+ throw new InvalidCipherTextException(
+ "Checksum inside ciphertext is corrupted");
+ }
+
+ // WK is the wrapped key, now extracted for use in data decryption.
+ return result;
+ }
+
+ /**
+ * Some key wrap algorithms make use of the Key Checksum defined
+ * in CMS [CMS-Algorithms]. This is used to provide an integrity
+ * check value for the key being wrapped. The algorithm is
+ *
+ * - 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
+ * @return the CMS checksum.
+ * @throws RuntimeException
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private byte[] calculateCMSKeyChecksum(
+ byte[] key)
+ {
+ byte[] result = new byte[8];
+
+ sha1.update(key, 0, key.length);
+ sha1.doFinal(digest, 0);
+
+ System.arraycopy(digest, 0, result, 0, 8);
+
+ return result;
+ }
+
+ /**
+ * @param key
+ * @param checksum
+ * @return true if okay, false otherwise.
+ * @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+ */
+ private boolean checkCMSKeyChecksum(
+ byte[] key,
+ byte[] checksum)
+ {
+ return Arrays.constantTimeAreEqual(calculateCMSKeyChecksum(key), checksum);
+ }
+
+ private static byte[] reverse(byte[] bs)
+ {
+ byte[] result = new byte[bs.length];
+ for (int i = 0; i < bs.length; i++)
+ {
+ result[i] = bs[bs.length - (i + 1)];
+ }
+ return result;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC2Engine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC2Engine.java
new file mode 100644
index 0000000..62240ea
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC2Engine.java
@@ -0,0 +1,316 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.RC2Parameters;
+
+/**
+ * an implementation of RC2 as described in RFC 2268
+ * "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
+ */
+public class RC2Engine
+ implements BlockCipher
+{
+ //
+ // the values we use for key expansion (based on the digits of PI)
+ //
+ private static byte[] piTable =
+ {
+ (byte)0xd9, (byte)0x78, (byte)0xf9, (byte)0xc4, (byte)0x19, (byte)0xdd, (byte)0xb5, (byte)0xed,
+ (byte)0x28, (byte)0xe9, (byte)0xfd, (byte)0x79, (byte)0x4a, (byte)0xa0, (byte)0xd8, (byte)0x9d,
+ (byte)0xc6, (byte)0x7e, (byte)0x37, (byte)0x83, (byte)0x2b, (byte)0x76, (byte)0x53, (byte)0x8e,
+ (byte)0x62, (byte)0x4c, (byte)0x64, (byte)0x88, (byte)0x44, (byte)0x8b, (byte)0xfb, (byte)0xa2,
+ (byte)0x17, (byte)0x9a, (byte)0x59, (byte)0xf5, (byte)0x87, (byte)0xb3, (byte)0x4f, (byte)0x13,
+ (byte)0x61, (byte)0x45, (byte)0x6d, (byte)0x8d, (byte)0x9, (byte)0x81, (byte)0x7d, (byte)0x32,
+ (byte)0xbd, (byte)0x8f, (byte)0x40, (byte)0xeb, (byte)0x86, (byte)0xb7, (byte)0x7b, (byte)0xb,
+ (byte)0xf0, (byte)0x95, (byte)0x21, (byte)0x22, (byte)0x5c, (byte)0x6b, (byte)0x4e, (byte)0x82,
+ (byte)0x54, (byte)0xd6, (byte)0x65, (byte)0x93, (byte)0xce, (byte)0x60, (byte)0xb2, (byte)0x1c,
+ (byte)0x73, (byte)0x56, (byte)0xc0, (byte)0x14, (byte)0xa7, (byte)0x8c, (byte)0xf1, (byte)0xdc,
+ (byte)0x12, (byte)0x75, (byte)0xca, (byte)0x1f, (byte)0x3b, (byte)0xbe, (byte)0xe4, (byte)0xd1,
+ (byte)0x42, (byte)0x3d, (byte)0xd4, (byte)0x30, (byte)0xa3, (byte)0x3c, (byte)0xb6, (byte)0x26,
+ (byte)0x6f, (byte)0xbf, (byte)0xe, (byte)0xda, (byte)0x46, (byte)0x69, (byte)0x7, (byte)0x57,
+ (byte)0x27, (byte)0xf2, (byte)0x1d, (byte)0x9b, (byte)0xbc, (byte)0x94, (byte)0x43, (byte)0x3,
+ (byte)0xf8, (byte)0x11, (byte)0xc7, (byte)0xf6, (byte)0x90, (byte)0xef, (byte)0x3e, (byte)0xe7,
+ (byte)0x6, (byte)0xc3, (byte)0xd5, (byte)0x2f, (byte)0xc8, (byte)0x66, (byte)0x1e, (byte)0xd7,
+ (byte)0x8, (byte)0xe8, (byte)0xea, (byte)0xde, (byte)0x80, (byte)0x52, (byte)0xee, (byte)0xf7,
+ (byte)0x84, (byte)0xaa, (byte)0x72, (byte)0xac, (byte)0x35, (byte)0x4d, (byte)0x6a, (byte)0x2a,
+ (byte)0x96, (byte)0x1a, (byte)0xd2, (byte)0x71, (byte)0x5a, (byte)0x15, (byte)0x49, (byte)0x74,
+ (byte)0x4b, (byte)0x9f, (byte)0xd0, (byte)0x5e, (byte)0x4, (byte)0x18, (byte)0xa4, (byte)0xec,
+ (byte)0xc2, (byte)0xe0, (byte)0x41, (byte)0x6e, (byte)0xf, (byte)0x51, (byte)0xcb, (byte)0xcc,
+ (byte)0x24, (byte)0x91, (byte)0xaf, (byte)0x50, (byte)0xa1, (byte)0xf4, (byte)0x70, (byte)0x39,
+ (byte)0x99, (byte)0x7c, (byte)0x3a, (byte)0x85, (byte)0x23, (byte)0xb8, (byte)0xb4, (byte)0x7a,
+ (byte)0xfc, (byte)0x2, (byte)0x36, (byte)0x5b, (byte)0x25, (byte)0x55, (byte)0x97, (byte)0x31,
+ (byte)0x2d, (byte)0x5d, (byte)0xfa, (byte)0x98, (byte)0xe3, (byte)0x8a, (byte)0x92, (byte)0xae,
+ (byte)0x5, (byte)0xdf, (byte)0x29, (byte)0x10, (byte)0x67, (byte)0x6c, (byte)0xba, (byte)0xc9,
+ (byte)0xd3, (byte)0x0, (byte)0xe6, (byte)0xcf, (byte)0xe1, (byte)0x9e, (byte)0xa8, (byte)0x2c,
+ (byte)0x63, (byte)0x16, (byte)0x1, (byte)0x3f, (byte)0x58, (byte)0xe2, (byte)0x89, (byte)0xa9,
+ (byte)0xd, (byte)0x38, (byte)0x34, (byte)0x1b, (byte)0xab, (byte)0x33, (byte)0xff, (byte)0xb0,
+ (byte)0xbb, (byte)0x48, (byte)0xc, (byte)0x5f, (byte)0xb9, (byte)0xb1, (byte)0xcd, (byte)0x2e,
+ (byte)0xc5, (byte)0xf3, (byte)0xdb, (byte)0x47, (byte)0xe5, (byte)0xa5, (byte)0x9c, (byte)0x77,
+ (byte)0xa, (byte)0xa6, (byte)0x20, (byte)0x68, (byte)0xfe, (byte)0x7f, (byte)0xc1, (byte)0xad
+ };
+
+ private static final int BLOCK_SIZE = 8;
+
+ private int[] workingKey;
+ private boolean encrypting;
+
+ private int[] generateWorkingKey(
+ byte[] key,
+ int bits)
+ {
+ int x;
+ int[] xKey = new int[128];
+
+ for (int i = 0; i != key.length; i++)
+ {
+ xKey[i] = key[i] & 0xff;
+ }
+
+ // Phase 1: Expand input key to 128 bytes
+ int len = key.length;
+
+ if (len < 128)
+ {
+ int index = 0;
+
+ x = xKey[len - 1];
+
+ do
+ {
+ x = piTable[(x + xKey[index++]) & 255] & 0xff;
+ xKey[len++] = x;
+ }
+ while (len < 128);
+ }
+
+ // Phase 2 - reduce effective key size to "bits"
+ len = (bits + 7) >> 3;
+ x = piTable[xKey[128 - len] & (255 >> (7 & -bits))] & 0xff;
+ xKey[128 - len] = x;
+
+ for (int i = 128 - len - 1; i >= 0; i--)
+ {
+ x = piTable[x ^ xKey[i + len]] & 0xff;
+ xKey[i] = x;
+ }
+
+ // Phase 3 - copy to newKey in little-endian order
+ int[] newKey = new int[64];
+
+ for (int i = 0; i != newKey.length; i++)
+ {
+ newKey[i] = (xKey[2 * i] + (xKey[2 * i + 1] << 8));
+ }
+
+ return newKey;
+ }
+
+ /**
+ * initialise a RC2 cipher.
+ *
+ * @param encrypting whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ {
+ this.encrypting = encrypting;
+
+ if (params instanceof RC2Parameters)
+ {
+ RC2Parameters param = (RC2Parameters)params;
+
+ workingKey = generateWorkingKey(param.getKey(),
+ param.getEffectiveKeyBits());
+ }
+ else if (params instanceof KeyParameter)
+ {
+ byte[] key = ((KeyParameter)params).getKey();
+
+ workingKey = generateWorkingKey(key, key.length * 8);
+ }
+ else
+ {
+ throw new IllegalArgumentException("invalid parameter passed to RC2 init - " + params.getClass().getName());
+ }
+
+ }
+
+ public void reset()
+ {
+ }
+
+ public String getAlgorithmName()
+ {
+ return "RC2";
+ }
+
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ public final int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new IllegalStateException("RC2 engine not initialised");
+ }
+
+ if ((inOff + BLOCK_SIZE) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BLOCK_SIZE) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (encrypting)
+ {
+ encryptBlock(in, inOff, out, outOff);
+ }
+ else
+ {
+ decryptBlock(in, inOff, out, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ /**
+ * return the result rotating the 16 bit number in x left by y
+ */
+ private int rotateWordLeft(
+ int x,
+ int y)
+ {
+ x &= 0xffff;
+ return (x << y) | (x >> (16 - y));
+ }
+
+ private void encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((in[inOff + 7] & 0xff) << 8) + (in[inOff + 6] & 0xff);
+ x54 = ((in[inOff + 5] & 0xff) << 8) + (in[inOff + 4] & 0xff);
+ x32 = ((in[inOff + 3] & 0xff) << 8) + (in[inOff + 2] & 0xff);
+ x10 = ((in[inOff + 1] & 0xff) << 8) + (in[inOff + 0] & 0xff);
+
+ for (int i = 0; i <= 16; i += 4)
+ {
+ x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ }
+
+ x10 += workingKey[x76 & 63];
+ x32 += workingKey[x10 & 63];
+ x54 += workingKey[x32 & 63];
+ x76 += workingKey[x54 & 63];
+
+ for (int i = 20; i <= 40; i += 4)
+ {
+ x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ }
+
+ x10 += workingKey[x76 & 63];
+ x32 += workingKey[x10 & 63];
+ x54 += workingKey[x32 & 63];
+ x76 += workingKey[x54 & 63];
+
+ for (int i = 44; i < 64; i += 4)
+ {
+ x10 = rotateWordLeft(x10 + (x32 & ~x76) + (x54 & x76) + workingKey[i ], 1);
+ x32 = rotateWordLeft(x32 + (x54 & ~x10) + (x76 & x10) + workingKey[i+1], 2);
+ x54 = rotateWordLeft(x54 + (x76 & ~x32) + (x10 & x32) + workingKey[i+2], 3);
+ x76 = rotateWordLeft(x76 + (x10 & ~x54) + (x32 & x54) + workingKey[i+3], 5);
+ }
+
+ out[outOff + 0] = (byte)x10;
+ out[outOff + 1] = (byte)(x10 >> 8);
+ out[outOff + 2] = (byte)x32;
+ out[outOff + 3] = (byte)(x32 >> 8);
+ out[outOff + 4] = (byte)x54;
+ out[outOff + 5] = (byte)(x54 >> 8);
+ out[outOff + 6] = (byte)x76;
+ out[outOff + 7] = (byte)(x76 >> 8);
+ }
+
+ private void decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ int x76, x54, x32, x10;
+
+ x76 = ((in[inOff + 7] & 0xff) << 8) + (in[inOff + 6] & 0xff);
+ x54 = ((in[inOff + 5] & 0xff) << 8) + (in[inOff + 4] & 0xff);
+ x32 = ((in[inOff + 3] & 0xff) << 8) + (in[inOff + 2] & 0xff);
+ x10 = ((in[inOff + 1] & 0xff) << 8) + (in[inOff + 0] & 0xff);
+
+ for (int i = 60; i >= 44; i -= 4)
+ {
+ x76 = rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+ x54 = rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+ x32 = rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+ x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
+ }
+
+ x76 -= workingKey[x54 & 63];
+ x54 -= workingKey[x32 & 63];
+ x32 -= workingKey[x10 & 63];
+ x10 -= workingKey[x76 & 63];
+
+ for (int i = 40; i >= 20; i -= 4)
+ {
+ x76 = rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+ x54 = rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+ x32 = rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+ x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
+ }
+
+ x76 -= workingKey[x54 & 63];
+ x54 -= workingKey[x32 & 63];
+ x32 -= workingKey[x10 & 63];
+ x10 -= workingKey[x76 & 63];
+
+ for (int i = 16; i >= 0; i -= 4)
+ {
+ x76 = rotateWordLeft(x76, 11) - ((x10 & ~x54) + (x32 & x54) + workingKey[i+3]);
+ x54 = rotateWordLeft(x54, 13) - ((x76 & ~x32) + (x10 & x32) + workingKey[i+2]);
+ x32 = rotateWordLeft(x32, 14) - ((x54 & ~x10) + (x76 & x10) + workingKey[i+1]);
+ x10 = rotateWordLeft(x10, 15) - ((x32 & ~x76) + (x54 & x76) + workingKey[i ]);
+ }
+
+ out[outOff + 0] = (byte)x10;
+ out[outOff + 1] = (byte)(x10 >> 8);
+ out[outOff + 2] = (byte)x32;
+ out[outOff + 3] = (byte)(x32 >> 8);
+ out[outOff + 4] = (byte)x54;
+ out[outOff + 5] = (byte)(x54 >> 8);
+ out[outOff + 6] = (byte)x76;
+ out[outOff + 7] = (byte)(x76 >> 8);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java
new file mode 100644
index 0000000..e7a9cdd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC4Engine.java
@@ -0,0 +1,143 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.StreamCipher;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+public class RC4Engine implements StreamCipher
+{
+ private final static int STATE_LENGTH = 256;
+
+ /*
+ * variables to hold the state of the RC4 engine
+ * during encryption and decryption
+ */
+
+ private byte[] engineState = null;
+ private int x = 0;
+ private int y = 0;
+ private byte[] workingKey = null;
+
+ /**
+ * initialise a RC4 cipher.
+ *
+ * @param forEncryption whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params
+ )
+ {
+ if (params instanceof KeyParameter)
+ {
+ /*
+ * RC4 encryption and decryption is completely
+ * symmetrical, so the 'forEncryption' is
+ * irrelevant.
+ */
+ workingKey = ((KeyParameter)params).getKey();
+ setKey(workingKey);
+
+ return;
+ }
+
+ throw new IllegalArgumentException("invalid parameter passed to RC4 init - " + params.getClass().getName());
+ }
+
+ public String getAlgorithmName()
+ {
+ return "RC4";
+ }
+
+ public byte returnByte(byte in)
+ {
+ x = (x + 1) & 0xff;
+ y = (engineState[x] + y) & 0xff;
+
+ // swap
+ byte tmp = engineState[x];
+ engineState[x] = engineState[y];
+ engineState[y] = tmp;
+
+ // xor
+ return (byte)(in ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+ }
+
+ public void processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ {
+ if ((inOff + len) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + len) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ for (int i = 0; i < len ; i++)
+ {
+ x = (x + 1) & 0xff;
+ y = (engineState[x] + y) & 0xff;
+
+ // swap
+ byte tmp = engineState[x];
+ engineState[x] = engineState[y];
+ engineState[y] = tmp;
+
+ // xor
+ out[i+outOff] = (byte)(in[i + inOff]
+ ^ engineState[(engineState[x] + engineState[y]) & 0xff]);
+ }
+ }
+
+ public void reset()
+ {
+ setKey(workingKey);
+ }
+
+ // Private implementation
+
+ private void setKey(byte[] keyBytes)
+ {
+ workingKey = keyBytes;
+
+ // System.out.println("the key length is ; "+ workingKey.length);
+
+ x = 0;
+ y = 0;
+
+ if (engineState == null)
+ {
+ engineState = new byte[STATE_LENGTH];
+ }
+
+ // reset the state of the engine
+ for (int i=0; i < STATE_LENGTH; i++)
+ {
+ engineState[i] = (byte)i;
+ }
+
+ int i1 = 0;
+ int i2 = 0;
+
+ for (int i=0; i < STATE_LENGTH; i++)
+ {
+ i2 = ((keyBytes[i1] & 0xff) + engineState[i] + i2) & 0xff;
+ // do the byte-swap inline
+ byte tmp = engineState[i];
+ engineState[i] = engineState[i2];
+ engineState[i2] = tmp;
+ i1 = (i1+1) % keyBytes.length;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java
new file mode 100644
index 0000000..540bd25
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RFC3394WrapEngine.java
@@ -0,0 +1,177 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+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.util.Arrays;
+
+/**
+ * an implementation of the AES Key Wrapper from the NIST Key Wrap
+ * Specification as described in RFC 3394.
+ * <p>
+ * For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
+ * and <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
+ */
+public class RFC3394WrapEngine
+ implements Wrapper
+{
+ private BlockCipher engine;
+ private KeyParameter param;
+ private boolean forWrapping;
+
+ private byte[] iv = {
+ (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6,
+ (byte)0xa6, (byte)0xa6, (byte)0xa6, (byte)0xa6 };
+
+ public RFC3394WrapEngine(BlockCipher engine)
+ {
+ this.engine = engine;
+ }
+
+ public void init(
+ boolean forWrapping,
+ CipherParameters param)
+ {
+ this.forWrapping = forWrapping;
+
+ if (param instanceof ParametersWithRandom)
+ {
+ param = ((ParametersWithRandom) param).getParameters();
+ }
+
+ if (param instanceof KeyParameter)
+ {
+ this.param = (KeyParameter)param;
+ }
+ else if (param instanceof ParametersWithIV)
+ {
+ this.iv = ((ParametersWithIV)param).getIV();
+ this.param = (KeyParameter)((ParametersWithIV) param).getParameters();
+ if (this.iv.length != 8)
+ {
+ throw new IllegalArgumentException("IV not equal to 8");
+ }
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return engine.getAlgorithmName();
+ }
+
+ public byte[] wrap(
+ byte[] in,
+ int inOff,
+ int inLen)
+ {
+ if (!forWrapping)
+ {
+ throw new IllegalStateException("not set for wrapping");
+ }
+
+ int n = inLen / 8;
+
+ if ((n * 8) != inLen)
+ {
+ throw new DataLengthException("wrap data must be a multiple of 8 bytes");
+ }
+
+ byte[] block = new byte[inLen + iv.length];
+ byte[] buf = new byte[8 + iv.length];
+
+ System.arraycopy(iv, 0, block, 0, iv.length);
+ System.arraycopy(in, 0, block, iv.length, inLen);
+
+ engine.init(true, param);
+
+ for (int j = 0; j != 6; j++)
+ {
+ for (int i = 1; i <= n; i++)
+ {
+ System.arraycopy(block, 0, buf, 0, iv.length);
+ System.arraycopy(block, 8 * i, buf, iv.length, 8);
+ engine.processBlock(buf, 0, buf, 0);
+
+ int t = n * j + i;
+ for (int k = 1; t != 0; k++)
+ {
+ byte v = (byte)t;
+
+ buf[iv.length - k] ^= v;
+
+ t >>>= 8;
+ }
+
+ System.arraycopy(buf, 0, block, 0, 8);
+ System.arraycopy(buf, 8, block, 8 * i, 8);
+ }
+ }
+
+ return block;
+ }
+
+ public byte[] unwrap(
+ byte[] in,
+ int inOff,
+ int inLen)
+ throws InvalidCipherTextException
+ {
+ if (forWrapping)
+ {
+ throw new IllegalStateException("not set for unwrapping");
+ }
+
+ int n = inLen / 8;
+
+ if ((n * 8) != inLen)
+ {
+ throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
+ }
+
+ byte[] block = new byte[inLen - iv.length];
+ byte[] a = new byte[iv.length];
+ byte[] buf = new byte[8 + iv.length];
+
+ System.arraycopy(in, 0, a, 0, iv.length);
+ System.arraycopy(in, iv.length, block, 0, inLen - iv.length);
+
+ engine.init(false, param);
+
+ n = n - 1;
+
+ for (int j = 5; j >= 0; j--)
+ {
+ for (int i = n; i >= 1; i--)
+ {
+ System.arraycopy(a, 0, buf, 0, iv.length);
+ System.arraycopy(block, 8 * (i - 1), buf, iv.length, 8);
+
+ int t = n * j + i;
+ for (int k = 1; t != 0; k++)
+ {
+ byte v = (byte)t;
+
+ buf[iv.length - k] ^= v;
+
+ t >>>= 8;
+ }
+
+ engine.processBlock(buf, 0, buf, 0);
+ System.arraycopy(buf, 0, a, 0, 8);
+ System.arraycopy(buf, 8, block, 8 * (i - 1), 8);
+ }
+ }
+
+ if (!Arrays.constantTimeAreEqual(a, iv))
+ {
+ throw new InvalidCipherTextException("checksum failed");
+ }
+
+ return block;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java
new file mode 100644
index 0000000..e7fb943
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java
@@ -0,0 +1,126 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.util.BigIntegers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * this does your basic RSA algorithm with blinding
+ */
+public class RSABlindedEngine
+ implements AsymmetricBlockCipher
+{
+ private static BigInteger ONE = BigInteger.valueOf(1);
+
+ private RSACoreEngine core = new RSACoreEngine();
+ private RSAKeyParameters key;
+ private SecureRandom random;
+
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters param)
+ {
+ core.init(forEncryption, param);
+
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ key = (RSAKeyParameters)rParam.getParameters();
+ random = rParam.getRandom();
+ }
+ else
+ {
+ key = (RSAKeyParameters)param;
+ random = new SecureRandom();
+ }
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public int getInputBlockSize()
+ {
+ return core.getInputBlockSize();
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public int getOutputBlockSize()
+ {
+ return core.getOutputBlockSize();
+ }
+
+ /**
+ * Process a single block using the basic RSA algorithm.
+ *
+ * @param in the input array.
+ * @param inOff the offset into the input buffer where the data starts.
+ * @param inLen the length of the data to be processed.
+ * @return the result of the RSA process.
+ * @exception DataLengthException the input block is too large.
+ */
+ public byte[] processBlock(
+ byte[] in,
+ int inOff,
+ int inLen)
+ {
+ if (key == null)
+ {
+ throw new IllegalStateException("RSA engine not initialised");
+ }
+
+ BigInteger input = core.convertInput(in, inOff, inLen);
+
+ BigInteger result;
+ if (key instanceof RSAPrivateCrtKeyParameters)
+ {
+ RSAPrivateCrtKeyParameters k = (RSAPrivateCrtKeyParameters)key;
+
+ BigInteger e = k.getPublicExponent();
+ if (e != null) // can't do blinding without a public exponent
+ {
+ BigInteger m = k.getModulus();
+ BigInteger r = BigIntegers.createRandomInRange(ONE, m.subtract(ONE), random);
+
+ BigInteger blindedInput = r.modPow(e, m).multiply(input).mod(m);
+ BigInteger blindedResult = core.processBlock(blindedInput);
+
+ BigInteger rInv = r.modInverse(m);
+ result = blindedResult.multiply(rInv).mod(m);
+ }
+ else
+ {
+ result = core.processBlock(input);
+ }
+ }
+ else
+ {
+ result = core.processBlock(input);
+ }
+
+ return core.convertOutput(result);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java
new file mode 100644
index 0000000..510cd5a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java
@@ -0,0 +1,203 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+import java.math.BigInteger;
+
+/**
+ * this does your basic RSA algorithm.
+ */
+class RSACoreEngine
+{
+ private RSAKeyParameters key;
+ private boolean forEncryption;
+
+ /**
+ * initialise the RSA engine.
+ *
+ * @param forEncryption true if we are encrypting, false otherwise.
+ * @param param the necessary RSA key parameters.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters param)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ key = (RSAKeyParameters)rParam.getParameters();
+ }
+ else
+ {
+ key = (RSAKeyParameters)param;
+ }
+
+ this.forEncryption = forEncryption;
+ }
+
+ /**
+ * Return the maximum size for an input block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * encryption, and the same length as the key size on decryption.
+ *
+ * @return maximum size for an input block.
+ */
+ public int getInputBlockSize()
+ {
+ int bitSize = key.getModulus().bitLength();
+
+ if (forEncryption)
+ {
+ return (bitSize + 7) / 8 - 1;
+ }
+ else
+ {
+ return (bitSize + 7) / 8;
+ }
+ }
+
+ /**
+ * Return the maximum size for an output block to this engine.
+ * For RSA this is always one byte less than the key size on
+ * decryption, and the same length as the key size on encryption.
+ *
+ * @return maximum size for an output block.
+ */
+ public int getOutputBlockSize()
+ {
+ int bitSize = key.getModulus().bitLength();
+
+ if (forEncryption)
+ {
+ return (bitSize + 7) / 8;
+ }
+ else
+ {
+ return (bitSize + 7) / 8 - 1;
+ }
+ }
+
+ public BigInteger convertInput(
+ byte[] in,
+ int inOff,
+ int inLen)
+ {
+ if (inLen > (getInputBlockSize() + 1))
+ {
+ throw new DataLengthException("input too large for RSA cipher.");
+ }
+ else if (inLen == (getInputBlockSize() + 1) && !forEncryption)
+ {
+ throw new DataLengthException("input too large for RSA cipher.");
+ }
+
+ byte[] block;
+
+ if (inOff != 0 || inLen != in.length)
+ {
+ block = new byte[inLen];
+
+ System.arraycopy(in, inOff, block, 0, inLen);
+ }
+ else
+ {
+ block = in;
+ }
+
+ BigInteger res = new BigInteger(1, block);
+ if (res.compareTo(key.getModulus()) >= 0)
+ {
+ throw new DataLengthException("input too large for RSA cipher.");
+ }
+
+ return res;
+ }
+
+ public byte[] convertOutput(
+ BigInteger result)
+ {
+ byte[] output = result.toByteArray();
+
+ if (forEncryption)
+ {
+ if (output[0] == 0 && output.length > getOutputBlockSize()) // have ended up with an extra zero byte, copy down.
+ {
+ byte[] tmp = new byte[output.length - 1];
+
+ System.arraycopy(output, 1, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ if (output.length < getOutputBlockSize()) // have ended up with less bytes than normal, lengthen
+ {
+ byte[] tmp = new byte[getOutputBlockSize()];
+
+ System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length);
+
+ return tmp;
+ }
+ }
+ else
+ {
+ if (output[0] == 0) // have ended up with an extra zero byte, copy down.
+ {
+ byte[] tmp = new byte[output.length - 1];
+
+ System.arraycopy(output, 1, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+ }
+
+ return output;
+ }
+
+ public BigInteger processBlock(BigInteger input)
+ {
+ if (key instanceof RSAPrivateCrtKeyParameters)
+ {
+ //
+ // we have the extra factors, use the Chinese Remainder Theorem - the author
+ // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
+ // advice regarding the expression of this.
+ //
+ RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key;
+
+ BigInteger p = crtKey.getP();
+ BigInteger q = crtKey.getQ();
+ BigInteger dP = crtKey.getDP();
+ BigInteger dQ = crtKey.getDQ();
+ BigInteger qInv = crtKey.getQInv();
+
+ BigInteger mP, mQ, h, m;
+
+ // mP = ((input mod p) ^ dP)) mod p
+ mP = (input.remainder(p)).modPow(dP, p);
+
+ // mQ = ((input mod q) ^ dQ)) mod q
+ mQ = (input.remainder(q)).modPow(dQ, q);
+
+ // h = qInv * (mP - mQ) mod p
+ h = mP.subtract(mQ);
+ h = h.multiply(qInv);
+ h = h.mod(p); // mod (in Java) returns the positive residual
+
+ // m = h * q + mQ
+ m = h.multiply(q);
+ m = m.add(mQ);
+
+ return m;
+ }
+ else
+ {
+ return input.modPow(
+ key.getExponent(), key.getModulus());
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/TwofishEngine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/TwofishEngine.java
new file mode 100644
index 0000000..bf43ff2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/TwofishEngine.java
@@ -0,0 +1,679 @@
+package org.bouncycastle.crypto.engines;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * A class that provides Twofish encryption operations.
+ *
+ * This Java implementation is based on the Java reference
+ * implementation provided by Bruce Schneier and developed
+ * by Raif S. Naffah.
+ */
+public final class TwofishEngine
+ implements BlockCipher
+{
+ private static final byte[][] P = {
+ { // p0
+ (byte) 0xA9, (byte) 0x67, (byte) 0xB3, (byte) 0xE8,
+ (byte) 0x04, (byte) 0xFD, (byte) 0xA3, (byte) 0x76,
+ (byte) 0x9A, (byte) 0x92, (byte) 0x80, (byte) 0x78,
+ (byte) 0xE4, (byte) 0xDD, (byte) 0xD1, (byte) 0x38,
+ (byte) 0x0D, (byte) 0xC6, (byte) 0x35, (byte) 0x98,
+ (byte) 0x18, (byte) 0xF7, (byte) 0xEC, (byte) 0x6C,
+ (byte) 0x43, (byte) 0x75, (byte) 0x37, (byte) 0x26,
+ (byte) 0xFA, (byte) 0x13, (byte) 0x94, (byte) 0x48,
+ (byte) 0xF2, (byte) 0xD0, (byte) 0x8B, (byte) 0x30,
+ (byte) 0x84, (byte) 0x54, (byte) 0xDF, (byte) 0x23,
+ (byte) 0x19, (byte) 0x5B, (byte) 0x3D, (byte) 0x59,
+ (byte) 0xF3, (byte) 0xAE, (byte) 0xA2, (byte) 0x82,
+ (byte) 0x63, (byte) 0x01, (byte) 0x83, (byte) 0x2E,
+ (byte) 0xD9, (byte) 0x51, (byte) 0x9B, (byte) 0x7C,
+ (byte) 0xA6, (byte) 0xEB, (byte) 0xA5, (byte) 0xBE,
+ (byte) 0x16, (byte) 0x0C, (byte) 0xE3, (byte) 0x61,
+ (byte) 0xC0, (byte) 0x8C, (byte) 0x3A, (byte) 0xF5,
+ (byte) 0x73, (byte) 0x2C, (byte) 0x25, (byte) 0x0B,
+ (byte) 0xBB, (byte) 0x4E, (byte) 0x89, (byte) 0x6B,
+ (byte) 0x53, (byte) 0x6A, (byte) 0xB4, (byte) 0xF1,
+ (byte) 0xE1, (byte) 0xE6, (byte) 0xBD, (byte) 0x45,
+ (byte) 0xE2, (byte) 0xF4, (byte) 0xB6, (byte) 0x66,
+ (byte) 0xCC, (byte) 0x95, (byte) 0x03, (byte) 0x56,
+ (byte) 0xD4, (byte) 0x1C, (byte) 0x1E, (byte) 0xD7,
+ (byte) 0xFB, (byte) 0xC3, (byte) 0x8E, (byte) 0xB5,
+ (byte) 0xE9, (byte) 0xCF, (byte) 0xBF, (byte) 0xBA,
+ (byte) 0xEA, (byte) 0x77, (byte) 0x39, (byte) 0xAF,
+ (byte) 0x33, (byte) 0xC9, (byte) 0x62, (byte) 0x71,
+ (byte) 0x81, (byte) 0x79, (byte) 0x09, (byte) 0xAD,
+ (byte) 0x24, (byte) 0xCD, (byte) 0xF9, (byte) 0xD8,
+ (byte) 0xE5, (byte) 0xC5, (byte) 0xB9, (byte) 0x4D,
+ (byte) 0x44, (byte) 0x08, (byte) 0x86, (byte) 0xE7,
+ (byte) 0xA1, (byte) 0x1D, (byte) 0xAA, (byte) 0xED,
+ (byte) 0x06, (byte) 0x70, (byte) 0xB2, (byte) 0xD2,
+ (byte) 0x41, (byte) 0x7B, (byte) 0xA0, (byte) 0x11,
+ (byte) 0x31, (byte) 0xC2, (byte) 0x27, (byte) 0x90,
+ (byte) 0x20, (byte) 0xF6, (byte) 0x60, (byte) 0xFF,
+ (byte) 0x96, (byte) 0x5C, (byte) 0xB1, (byte) 0xAB,
+ (byte) 0x9E, (byte) 0x9C, (byte) 0x52, (byte) 0x1B,
+ (byte) 0x5F, (byte) 0x93, (byte) 0x0A, (byte) 0xEF,
+ (byte) 0x91, (byte) 0x85, (byte) 0x49, (byte) 0xEE,
+ (byte) 0x2D, (byte) 0x4F, (byte) 0x8F, (byte) 0x3B,
+ (byte) 0x47, (byte) 0x87, (byte) 0x6D, (byte) 0x46,
+ (byte) 0xD6, (byte) 0x3E, (byte) 0x69, (byte) 0x64,
+ (byte) 0x2A, (byte) 0xCE, (byte) 0xCB, (byte) 0x2F,
+ (byte) 0xFC, (byte) 0x97, (byte) 0x05, (byte) 0x7A,
+ (byte) 0xAC, (byte) 0x7F, (byte) 0xD5, (byte) 0x1A,
+ (byte) 0x4B, (byte) 0x0E, (byte) 0xA7, (byte) 0x5A,
+ (byte) 0x28, (byte) 0x14, (byte) 0x3F, (byte) 0x29,
+ (byte) 0x88, (byte) 0x3C, (byte) 0x4C, (byte) 0x02,
+ (byte) 0xB8, (byte) 0xDA, (byte) 0xB0, (byte) 0x17,
+ (byte) 0x55, (byte) 0x1F, (byte) 0x8A, (byte) 0x7D,
+ (byte) 0x57, (byte) 0xC7, (byte) 0x8D, (byte) 0x74,
+ (byte) 0xB7, (byte) 0xC4, (byte) 0x9F, (byte) 0x72,
+ (byte) 0x7E, (byte) 0x15, (byte) 0x22, (byte) 0x12,
+ (byte) 0x58, (byte) 0x07, (byte) 0x99, (byte) 0x34,
+ (byte) 0x6E, (byte) 0x50, (byte) 0xDE, (byte) 0x68,
+ (byte) 0x65, (byte) 0xBC, (byte) 0xDB, (byte) 0xF8,
+ (byte) 0xC8, (byte) 0xA8, (byte) 0x2B, (byte) 0x40,
+ (byte) 0xDC, (byte) 0xFE, (byte) 0x32, (byte) 0xA4,
+ (byte) 0xCA, (byte) 0x10, (byte) 0x21, (byte) 0xF0,
+ (byte) 0xD3, (byte) 0x5D, (byte) 0x0F, (byte) 0x00,
+ (byte) 0x6F, (byte) 0x9D, (byte) 0x36, (byte) 0x42,
+ (byte) 0x4A, (byte) 0x5E, (byte) 0xC1, (byte) 0xE0 },
+ { // p1
+ (byte) 0x75, (byte) 0xF3, (byte) 0xC6, (byte) 0xF4,
+ (byte) 0xDB, (byte) 0x7B, (byte) 0xFB, (byte) 0xC8,
+ (byte) 0x4A, (byte) 0xD3, (byte) 0xE6, (byte) 0x6B,
+ (byte) 0x45, (byte) 0x7D, (byte) 0xE8, (byte) 0x4B,
+ (byte) 0xD6, (byte) 0x32, (byte) 0xD8, (byte) 0xFD,
+ (byte) 0x37, (byte) 0x71, (byte) 0xF1, (byte) 0xE1,
+ (byte) 0x30, (byte) 0x0F, (byte) 0xF8, (byte) 0x1B,
+ (byte) 0x87, (byte) 0xFA, (byte) 0x06, (byte) 0x3F,
+ (byte) 0x5E, (byte) 0xBA, (byte) 0xAE, (byte) 0x5B,
+ (byte) 0x8A, (byte) 0x00, (byte) 0xBC, (byte) 0x9D,
+ (byte) 0x6D, (byte) 0xC1, (byte) 0xB1, (byte) 0x0E,
+ (byte) 0x80, (byte) 0x5D, (byte) 0xD2, (byte) 0xD5,
+ (byte) 0xA0, (byte) 0x84, (byte) 0x07, (byte) 0x14,
+ (byte) 0xB5, (byte) 0x90, (byte) 0x2C, (byte) 0xA3,
+ (byte) 0xB2, (byte) 0x73, (byte) 0x4C, (byte) 0x54,
+ (byte) 0x92, (byte) 0x74, (byte) 0x36, (byte) 0x51,
+ (byte) 0x38, (byte) 0xB0, (byte) 0xBD, (byte) 0x5A,
+ (byte) 0xFC, (byte) 0x60, (byte) 0x62, (byte) 0x96,
+ (byte) 0x6C, (byte) 0x42, (byte) 0xF7, (byte) 0x10,
+ (byte) 0x7C, (byte) 0x28, (byte) 0x27, (byte) 0x8C,
+ (byte) 0x13, (byte) 0x95, (byte) 0x9C, (byte) 0xC7,
+ (byte) 0x24, (byte) 0x46, (byte) 0x3B, (byte) 0x70,
+ (byte) 0xCA, (byte) 0xE3, (byte) 0x85, (byte) 0xCB,
+ (byte) 0x11, (byte) 0xD0, (byte) 0x93, (byte) 0xB8,
+ (byte) 0xA6, (byte) 0x83, (byte) 0x20, (byte) 0xFF,
+ (byte) 0x9F, (byte) 0x77, (byte) 0xC3, (byte) 0xCC,
+ (byte) 0x03, (byte) 0x6F, (byte) 0x08, (byte) 0xBF,
+ (byte) 0x40, (byte) 0xE7, (byte) 0x2B, (byte) 0xE2,
+ (byte) 0x79, (byte) 0x0C, (byte) 0xAA, (byte) 0x82,
+ (byte) 0x41, (byte) 0x3A, (byte) 0xEA, (byte) 0xB9,
+ (byte) 0xE4, (byte) 0x9A, (byte) 0xA4, (byte) 0x97,
+ (byte) 0x7E, (byte) 0xDA, (byte) 0x7A, (byte) 0x17,
+ (byte) 0x66, (byte) 0x94, (byte) 0xA1, (byte) 0x1D,
+ (byte) 0x3D, (byte) 0xF0, (byte) 0xDE, (byte) 0xB3,
+ (byte) 0x0B, (byte) 0x72, (byte) 0xA7, (byte) 0x1C,
+ (byte) 0xEF, (byte) 0xD1, (byte) 0x53, (byte) 0x3E,
+ (byte) 0x8F, (byte) 0x33, (byte) 0x26, (byte) 0x5F,
+ (byte) 0xEC, (byte) 0x76, (byte) 0x2A, (byte) 0x49,
+ (byte) 0x81, (byte) 0x88, (byte) 0xEE, (byte) 0x21,
+ (byte) 0xC4, (byte) 0x1A, (byte) 0xEB, (byte) 0xD9,
+ (byte) 0xC5, (byte) 0x39, (byte) 0x99, (byte) 0xCD,
+ (byte) 0xAD, (byte) 0x31, (byte) 0x8B, (byte) 0x01,
+ (byte) 0x18, (byte) 0x23, (byte) 0xDD, (byte) 0x1F,
+ (byte) 0x4E, (byte) 0x2D, (byte) 0xF9, (byte) 0x48,
+ (byte) 0x4F, (byte) 0xF2, (byte) 0x65, (byte) 0x8E,
+ (byte) 0x78, (byte) 0x5C, (byte) 0x58, (byte) 0x19,
+ (byte) 0x8D, (byte) 0xE5, (byte) 0x98, (byte) 0x57,
+ (byte) 0x67, (byte) 0x7F, (byte) 0x05, (byte) 0x64,
+ (byte) 0xAF, (byte) 0x63, (byte) 0xB6, (byte) 0xFE,
+ (byte) 0xF5, (byte) 0xB7, (byte) 0x3C, (byte) 0xA5,
+ (byte) 0xCE, (byte) 0xE9, (byte) 0x68, (byte) 0x44,
+ (byte) 0xE0, (byte) 0x4D, (byte) 0x43, (byte) 0x69,
+ (byte) 0x29, (byte) 0x2E, (byte) 0xAC, (byte) 0x15,
+ (byte) 0x59, (byte) 0xA8, (byte) 0x0A, (byte) 0x9E,
+ (byte) 0x6E, (byte) 0x47, (byte) 0xDF, (byte) 0x34,
+ (byte) 0x35, (byte) 0x6A, (byte) 0xCF, (byte) 0xDC,
+ (byte) 0x22, (byte) 0xC9, (byte) 0xC0, (byte) 0x9B,
+ (byte) 0x89, (byte) 0xD4, (byte) 0xED, (byte) 0xAB,
+ (byte) 0x12, (byte) 0xA2, (byte) 0x0D, (byte) 0x52,
+ (byte) 0xBB, (byte) 0x02, (byte) 0x2F, (byte) 0xA9,
+ (byte) 0xD7, (byte) 0x61, (byte) 0x1E, (byte) 0xB4,
+ (byte) 0x50, (byte) 0x04, (byte) 0xF6, (byte) 0xC2,
+ (byte) 0x16, (byte) 0x25, (byte) 0x86, (byte) 0x56,
+ (byte) 0x55, (byte) 0x09, (byte) 0xBE, (byte) 0x91 }
+ };
+
+ /**
+ * Define the fixed p0/p1 permutations used in keyed S-box lookup.
+ * By changing the following constant definitions, the S-boxes will
+ * automatically get changed in the Twofish engine.
+ */
+ private static final int P_00 = 1;
+ private static final int P_01 = 0;
+ private static final int P_02 = 0;
+ private static final int P_03 = P_01 ^ 1;
+ private static final int P_04 = 1;
+
+ private static final int P_10 = 0;
+ private static final int P_11 = 0;
+ private static final int P_12 = 1;
+ private static final int P_13 = P_11 ^ 1;
+ private static final int P_14 = 0;
+
+ private static final int P_20 = 1;
+ private static final int P_21 = 1;
+ private static final int P_22 = 0;
+ private static final int P_23 = P_21 ^ 1;
+ private static final int P_24 = 0;
+
+ private static final int P_30 = 0;
+ private static final int P_31 = 1;
+ private static final int P_32 = 1;
+ private static final int P_33 = P_31 ^ 1;
+ private static final int P_34 = 1;
+
+ /* Primitive polynomial for GF(256) */
+ private static final int GF256_FDBK = 0x169;
+ private static final int GF256_FDBK_2 = GF256_FDBK / 2;
+ private static final int GF256_FDBK_4 = GF256_FDBK / 4;
+
+ private static final int RS_GF_FDBK = 0x14D; // field generator
+
+ //====================================
+ // Useful constants
+ //====================================
+
+ private static final int ROUNDS = 16;
+ private static final int MAX_ROUNDS = 16; // bytes = 128 bits
+ private static final int BLOCK_SIZE = 16; // bytes = 128 bits
+ private static final int MAX_KEY_BITS = 256;
+
+ private static final int INPUT_WHITEN=0;
+ private static final int OUTPUT_WHITEN=INPUT_WHITEN+BLOCK_SIZE/4; // 4
+ private static final int ROUND_SUBKEYS=OUTPUT_WHITEN+BLOCK_SIZE/4;// 8
+
+ private static final int TOTAL_SUBKEYS=ROUND_SUBKEYS+2*MAX_ROUNDS;// 40
+
+ private static final int SK_STEP = 0x02020202;
+ private static final int SK_BUMP = 0x01010101;
+ private static final int SK_ROTL = 9;
+
+ private boolean encrypting = false;
+
+ private int[] gMDS0 = new int[MAX_KEY_BITS];
+ private int[] gMDS1 = new int[MAX_KEY_BITS];
+ private int[] gMDS2 = new int[MAX_KEY_BITS];
+ private int[] gMDS3 = new int[MAX_KEY_BITS];
+
+ /**
+ * gSubKeys[] and gSBox[] are eventually used in the
+ * encryption and decryption methods.
+ */
+ private int[] gSubKeys;
+ private int[] gSBox;
+
+ private int k64Cnt = 0;
+
+ private byte[] workingKey = null;
+
+ public TwofishEngine()
+ {
+ // calculate the MDS matrix
+ int[] m1 = new int[2];
+ int[] mX = new int[2];
+ int[] mY = new int[2];
+ int j;
+
+ for (int i=0; i< MAX_KEY_BITS ; i++)
+ {
+ j = P[0][i] & 0xff;
+ m1[0] = j;
+ mX[0] = Mx_X(j) & 0xff;
+ mY[0] = Mx_Y(j) & 0xff;
+
+ j = P[1][i] & 0xff;
+ m1[1] = j;
+ mX[1] = Mx_X(j) & 0xff;
+ mY[1] = Mx_Y(j) & 0xff;
+
+ gMDS0[i] = m1[P_00] | mX[P_00] << 8 |
+ mY[P_00] << 16 | mY[P_00] << 24;
+
+ gMDS1[i] = mY[P_10] | mY[P_10] << 8 |
+ mX[P_10] << 16 | m1[P_10] << 24;
+
+ gMDS2[i] = mX[P_20] | mY[P_20] << 8 |
+ m1[P_20] << 16 | mY[P_20] << 24;
+
+ gMDS3[i] = mX[P_30] | m1[P_30] << 8 |
+ mY[P_30] << 16 | mX[P_30] << 24;
+ }
+ }
+
+ /**
+ * initialise a Twofish cipher.
+ *
+ * @param encrypting whether or not we are for encryption.
+ * @param params the parameters required to set up the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ {
+ if (params instanceof KeyParameter)
+ {
+ this.encrypting = encrypting;
+ this.workingKey = ((KeyParameter)params).getKey();
+ this.k64Cnt = (this.workingKey.length / 8); // pre-padded ?
+ setKey(this.workingKey);
+
+ return;
+ }
+
+ throw new IllegalArgumentException("invalid parameter passed to Twofish init - " + params.getClass().getName());
+ }
+
+ public String getAlgorithmName()
+ {
+ return "Twofish";
+ }
+
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ {
+ if (workingKey == null)
+ {
+ throw new IllegalStateException("Twofish not initialised");
+ }
+
+ if ((inOff + BLOCK_SIZE) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ if ((outOff + BLOCK_SIZE) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+
+ if (encrypting)
+ {
+ encryptBlock(in, inOff, out, outOff);
+ }
+ else
+ {
+ decryptBlock(in, inOff, out, outOff);
+ }
+
+ return BLOCK_SIZE;
+ }
+
+ public void reset()
+ {
+ if (this.workingKey != null)
+ {
+ setKey(this.workingKey);
+ }
+ }
+
+ public int getBlockSize()
+ {
+ return BLOCK_SIZE;
+ }
+
+ //==================================
+ // Private Implementation
+ //==================================
+
+ private void setKey(byte[] key)
+ {
+ int[] k32e = new int[MAX_KEY_BITS/64]; // 4
+ int[] k32o = new int[MAX_KEY_BITS/64]; // 4
+
+ int[] sBoxKeys = new int[MAX_KEY_BITS/64]; // 4
+ gSubKeys = new int[TOTAL_SUBKEYS];
+
+ if (k64Cnt < 1)
+ {
+ throw new IllegalArgumentException("Key size less than 64 bits");
+ }
+
+ if (k64Cnt > 4)
+ {
+ throw new IllegalArgumentException("Key size larger than 256 bits");
+ }
+
+ /*
+ * k64Cnt is the number of 8 byte blocks (64 chunks)
+ * that are in the input key. The input key is a
+ * maximum of 32 bytes (256 bits), so the range
+ * for k64Cnt is 1..4
+ */
+ for (int i=0; i<k64Cnt ; i++)
+ {
+ int p = i* 8;
+
+ k32e[i] = BytesTo32Bits(key, p);
+ k32o[i] = BytesTo32Bits(key, p+4);
+
+ sBoxKeys[k64Cnt-1-i] = RS_MDS_Encode(k32e[i], k32o[i]);
+ }
+
+ int q,A,B;
+ for (int i=0; i < TOTAL_SUBKEYS / 2 ; i++)
+ {
+ q = i*SK_STEP;
+ A = F32(q, k32e);
+ B = F32(q+SK_BUMP, k32o);
+ B = B << 8 | B >>> 24;
+ A += B;
+ gSubKeys[i*2] = A;
+ A += B;
+ gSubKeys[i*2 + 1] = A << SK_ROTL | A >>> (32-SK_ROTL);
+ }
+
+ /*
+ * fully expand the table for speed
+ */
+ int k0 = sBoxKeys[0];
+ int k1 = sBoxKeys[1];
+ int k2 = sBoxKeys[2];
+ int k3 = sBoxKeys[3];
+ int b0, b1, b2, b3;
+ gSBox = new int[4*MAX_KEY_BITS];
+ for (int i=0; i<MAX_KEY_BITS; i++)
+ {
+ b0 = b1 = b2 = b3 = i;
+ switch (k64Cnt & 3)
+ {
+ case 1:
+ gSBox[i*2] = gMDS0[(P[P_01][b0] & 0xff) ^ b0(k0)];
+ gSBox[i*2+1] = gMDS1[(P[P_11][b1] & 0xff) ^ b1(k0)];
+ gSBox[i*2+0x200] = gMDS2[(P[P_21][b2] & 0xff) ^ b2(k0)];
+ gSBox[i*2+0x201] = gMDS3[(P[P_31][b3] & 0xff) ^ b3(k0)];
+ break;
+ case 0: // 256 bits of key
+ b0 = (P[P_04][b0] & 0xff) ^ b0(k3);
+ b1 = (P[P_14][b1] & 0xff) ^ b1(k3);
+ b2 = (P[P_24][b2] & 0xff) ^ b2(k3);
+ b3 = (P[P_34][b3] & 0xff) ^ b3(k3);
+ // fall through, having pre-processed b[0]..b[3] with k32[3]
+ case 3: // 192 bits of key
+ b0 = (P[P_03][b0] & 0xff) ^ b0(k2);
+ b1 = (P[P_13][b1] & 0xff) ^ b1(k2);
+ b2 = (P[P_23][b2] & 0xff) ^ b2(k2);
+ b3 = (P[P_33][b3] & 0xff) ^ b3(k2);
+ // fall through, having pre-processed b[0]..b[3] with k32[2]
+ case 2: // 128 bits of key
+ gSBox[i*2] = gMDS0[(P[P_01]
+ [(P[P_02][b0] & 0xff) ^ b0(k1)] & 0xff) ^ b0(k0)];
+ gSBox[i*2+1] = gMDS1[(P[P_11]
+ [(P[P_12][b1] & 0xff) ^ b1(k1)] & 0xff) ^ b1(k0)];
+ gSBox[i*2+0x200] = gMDS2[(P[P_21]
+ [(P[P_22][b2] & 0xff) ^ b2(k1)] & 0xff) ^ b2(k0)];
+ gSBox[i*2+0x201] = gMDS3[(P[P_31]
+ [(P[P_32][b3] & 0xff) ^ b3(k1)] & 0xff) ^ b3(k0)];
+ break;
+ }
+ }
+
+ /*
+ * the function exits having setup the gSBox with the
+ * input key material.
+ */
+ }
+
+ /**
+ * Encrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ * The input will be an exact multiple of our blocksize.
+ *
+ * encryptBlock uses the pre-calculated gSBox[] and subKey[]
+ * arrays.
+ */
+ private void encryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int x0 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[INPUT_WHITEN];
+ int x1 = BytesTo32Bits(src, srcIndex + 4) ^ gSubKeys[INPUT_WHITEN + 1];
+ int x2 = BytesTo32Bits(src, srcIndex + 8) ^ gSubKeys[INPUT_WHITEN + 2];
+ int x3 = BytesTo32Bits(src, srcIndex + 12) ^ gSubKeys[INPUT_WHITEN + 3];
+
+ int k = ROUND_SUBKEYS;
+ int t0, t1;
+ for (int r = 0; r < ROUNDS; r +=2)
+ {
+ t0 = Fe32_0(x0);
+ t1 = Fe32_3(x1);
+ x2 ^= t0 + t1 + gSubKeys[k++];
+ x2 = x2 >>>1 | x2 << 31;
+ x3 = (x3 << 1 | x3 >>> 31) ^ (t0 + 2*t1 + gSubKeys[k++]);
+
+ t0 = Fe32_0(x2);
+ t1 = Fe32_3(x3);
+ x0 ^= t0 + t1 + gSubKeys[k++];
+ x0 = x0 >>>1 | x0 << 31;
+ x1 = (x1 << 1 | x1 >>> 31) ^ (t0 + 2*t1 + gSubKeys[k++]);
+ }
+
+ Bits32ToBytes(x2 ^ gSubKeys[OUTPUT_WHITEN], dst, dstIndex);
+ Bits32ToBytes(x3 ^ gSubKeys[OUTPUT_WHITEN + 1], dst, dstIndex + 4);
+ Bits32ToBytes(x0 ^ gSubKeys[OUTPUT_WHITEN + 2], dst, dstIndex + 8);
+ Bits32ToBytes(x1 ^ gSubKeys[OUTPUT_WHITEN + 3], dst, dstIndex + 12);
+ }
+
+ /**
+ * Decrypt the given input starting at the given offset and place
+ * the result in the provided buffer starting at the given offset.
+ * The input will be an exact multiple of our blocksize.
+ */
+ private void decryptBlock(
+ byte[] src,
+ int srcIndex,
+ byte[] dst,
+ int dstIndex)
+ {
+ int x2 = BytesTo32Bits(src, srcIndex) ^ gSubKeys[OUTPUT_WHITEN];
+ int x3 = BytesTo32Bits(src, srcIndex+4) ^ gSubKeys[OUTPUT_WHITEN + 1];
+ int x0 = BytesTo32Bits(src, srcIndex+8) ^ gSubKeys[OUTPUT_WHITEN + 2];
+ int x1 = BytesTo32Bits(src, srcIndex+12) ^ gSubKeys[OUTPUT_WHITEN + 3];
+
+ int k = ROUND_SUBKEYS + 2 * ROUNDS -1 ;
+ int t0, t1;
+ for (int r = 0; r< ROUNDS ; r +=2)
+ {
+ t0 = Fe32_0(x2);
+ t1 = Fe32_3(x3);
+ x1 ^= t0 + 2*t1 + gSubKeys[k--];
+ x0 = (x0 << 1 | x0 >>> 31) ^ (t0 + t1 + gSubKeys[k--]);
+ x1 = x1 >>>1 | x1 << 31;
+
+ t0 = Fe32_0(x0);
+ t1 = Fe32_3(x1);
+ x3 ^= t0 + 2*t1 + gSubKeys[k--];
+ x2 = (x2 << 1 | x2 >>> 31) ^ (t0 + t1 + gSubKeys[k--]);
+ x3 = x3 >>>1 | x3 << 31;
+ }
+
+ Bits32ToBytes(x0 ^ gSubKeys[INPUT_WHITEN], dst, dstIndex);
+ Bits32ToBytes(x1 ^ gSubKeys[INPUT_WHITEN + 1], dst, dstIndex + 4);
+ Bits32ToBytes(x2 ^ gSubKeys[INPUT_WHITEN + 2], dst, dstIndex + 8);
+ Bits32ToBytes(x3 ^ gSubKeys[INPUT_WHITEN + 3], dst, dstIndex + 12);
+ }
+
+ /*
+ * TODO: This can be optimised and made cleaner by combining
+ * the functionality in this function and applying it appropriately
+ * to the creation of the subkeys during key setup.
+ */
+ private int F32(int x, int[] k32)
+ {
+ int b0 = b0(x);
+ int b1 = b1(x);
+ int b2 = b2(x);
+ int b3 = b3(x);
+ int k0 = k32[0];
+ int k1 = k32[1];
+ int k2 = k32[2];
+ int k3 = k32[3];
+
+ int result = 0;
+ switch (k64Cnt & 3)
+ {
+ case 1:
+ result = gMDS0[(P[P_01][b0] & 0xff) ^ b0(k0)] ^
+ gMDS1[(P[P_11][b1] & 0xff) ^ b1(k0)] ^
+ gMDS2[(P[P_21][b2] & 0xff) ^ b2(k0)] ^
+ gMDS3[(P[P_31][b3] & 0xff) ^ b3(k0)];
+ break;
+ case 0: /* 256 bits of key */
+ b0 = (P[P_04][b0] & 0xff) ^ b0(k3);
+ b1 = (P[P_14][b1] & 0xff) ^ b1(k3);
+ b2 = (P[P_24][b2] & 0xff) ^ b2(k3);
+ b3 = (P[P_34][b3] & 0xff) ^ b3(k3);
+ case 3:
+ b0 = (P[P_03][b0] & 0xff) ^ b0(k2);
+ b1 = (P[P_13][b1] & 0xff) ^ b1(k2);
+ b2 = (P[P_23][b2] & 0xff) ^ b2(k2);
+ b3 = (P[P_33][b3] & 0xff) ^ b3(k2);
+ case 2:
+ result =
+ gMDS0[(P[P_01][(P[P_02][b0]&0xff)^b0(k1)]&0xff)^b0(k0)] ^
+ gMDS1[(P[P_11][(P[P_12][b1]&0xff)^b1(k1)]&0xff)^b1(k0)] ^
+ gMDS2[(P[P_21][(P[P_22][b2]&0xff)^b2(k1)]&0xff)^b2(k0)] ^
+ gMDS3[(P[P_31][(P[P_32][b3]&0xff)^b3(k1)]&0xff)^b3(k0)];
+ break;
+ }
+ return result;
+ }
+
+ /**
+ * Use (12, 8) Reed-Solomon code over GF(256) to produce
+ * a key S-box 32-bit entity from 2 key material 32-bit
+ * entities.
+ *
+ * @param k0 first 32-bit entity
+ * @param k1 second 32-bit entity
+ * @return Remainder polynomial generated using RS code
+ */
+ private int RS_MDS_Encode(int k0, int k1)
+ {
+ int r = k1;
+ for (int i = 0 ; i < 4 ; i++) // shift 1 byte at a time
+ {
+ r = RS_rem(r);
+ }
+ r ^= k0;
+ for (int i=0 ; i < 4 ; i++)
+ {
+ r = RS_rem(r);
+ }
+
+ return r;
+ }
+
+ /**
+ * Reed-Solomon code parameters: (12,8) reversible code:<p>
+ * <pre>
+ * g(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
+ * </pre>
+ * where a = primitive root of field generator 0x14D
+ */
+ private int RS_rem(int x)
+ {
+ int b = (x >>> 24) & 0xff;
+ int g2 = ((b << 1) ^
+ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff;
+ int g3 = ((b >>> 1) ^
+ ((b & 0x01) != 0 ? (RS_GF_FDBK >>> 1) : 0)) ^ g2 ;
+ return ((x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b);
+ }
+
+ private int LFSR1(int x)
+ {
+ return (x >> 1) ^
+ (((x & 0x01) != 0) ? GF256_FDBK_2 : 0);
+ }
+
+ private int LFSR2(int x)
+ {
+ return (x >> 2) ^
+ (((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^
+ (((x & 0x01) != 0) ? GF256_FDBK_4 : 0);
+ }
+
+ private int Mx_X(int x)
+ {
+ return x ^ LFSR2(x);
+ } // 5B
+
+ private int Mx_Y(int x)
+ {
+ return x ^ LFSR1(x) ^ LFSR2(x);
+ } // EF
+
+ private int b0(int x)
+ {
+ return x & 0xff;
+ }
+
+ private int b1(int x)
+ {
+ return (x >>> 8) & 0xff;
+ }
+
+ private int b2(int x)
+ {
+ return (x >>> 16) & 0xff;
+ }
+
+ private int b3(int x)
+ {
+ return (x >>> 24) & 0xff;
+ }
+
+ private int Fe32_0(int x)
+ {
+ return gSBox[ 0x000 + 2*(x & 0xff) ] ^
+ gSBox[ 0x001 + 2*((x >>> 8) & 0xff) ] ^
+ gSBox[ 0x200 + 2*((x >>> 16) & 0xff) ] ^
+ gSBox[ 0x201 + 2*((x >>> 24) & 0xff) ];
+ }
+
+ private int Fe32_3(int x)
+ {
+ return gSBox[ 0x000 + 2*((x >>> 24) & 0xff) ] ^
+ gSBox[ 0x001 + 2*(x & 0xff) ] ^
+ gSBox[ 0x200 + 2*((x >>> 8) & 0xff) ] ^
+ gSBox[ 0x201 + 2*((x >>> 16) & 0xff) ];
+ }
+
+ private int BytesTo32Bits(byte[] b, int p)
+ {
+ return ((b[p] & 0xff)) |
+ ((b[p+1] & 0xff) << 8) |
+ ((b[p+2] & 0xff) << 16) |
+ ((b[p+3] & 0xff) << 24);
+ }
+
+ private void Bits32ToBytes(int in, byte[] b, int offset)
+ {
+ b[offset] = (byte)in;
+ b[offset + 1] = (byte)(in >> 8);
+ b[offset + 2] = (byte)(in >> 16);
+ b[offset + 3] = (byte)(in >> 24);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESKeyGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESKeyGenerator.java
new file mode 100644
index 0000000..7111118
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESKeyGenerator.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.params.DESParameters;
+
+public class DESKeyGenerator
+ extends CipherKeyGenerator
+{
+ /**
+ * initialise the key generator - if strength is set to zero
+ * the key generated will be 64 bits in size, otherwise
+ * strength can be 64 or 56 bits (if you don't count the parity bits).
+ *
+ * @param param the parameters to be used for key generation
+ */
+ public void init(
+ KeyGenerationParameters param)
+ {
+ super.init(param);
+
+ if (strength == 0 || strength == (56 / 8))
+ {
+ strength = DESParameters.DES_KEY_LENGTH;
+ }
+ else if (strength != DESParameters.DES_KEY_LENGTH)
+ {
+ throw new IllegalArgumentException("DES key must be "
+ + (DESParameters.DES_KEY_LENGTH * 8)
+ + " bits long.");
+ }
+ }
+
+ public byte[] generateKey()
+ {
+ byte[] newKey = new byte[DESParameters.DES_KEY_LENGTH];
+
+ do
+ {
+ random.nextBytes(newKey);
+
+ DESParameters.setOddParity(newKey);
+ }
+ while (DESParameters.isWeakKey(newKey, 0));
+
+ return newKey;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java
new file mode 100644
index 0000000..3cab983
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DESedeKeyGenerator.java
@@ -0,0 +1,56 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.params.DESedeParameters;
+
+public class DESedeKeyGenerator
+ extends DESKeyGenerator
+{
+ /**
+ * initialise the key generator - if strength is set to zero
+ * the key generated will be 192 bits in size, otherwise
+ * strength can be 128 or 192 (or 112 or 168 if you don't count
+ * parity bits), depending on whether you wish to do 2-key or 3-key
+ * triple DES.
+ *
+ * @param param the parameters to be used for key generation
+ */
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.random = param.getRandom();
+ this.strength = (param.getStrength() + 7) / 8;
+
+ if (strength == 0 || strength == (168 / 8))
+ {
+ strength = DESedeParameters.DES_EDE_KEY_LENGTH;
+ }
+ else if (strength == (112 / 8))
+ {
+ strength = 2 * DESedeParameters.DES_KEY_LENGTH;
+ }
+ else if (strength != DESedeParameters.DES_EDE_KEY_LENGTH
+ && strength != (2 * DESedeParameters.DES_KEY_LENGTH))
+ {
+ throw new IllegalArgumentException("DESede key must be "
+ + (DESedeParameters.DES_EDE_KEY_LENGTH * 8) + " or "
+ + (2 * 8 * DESedeParameters.DES_KEY_LENGTH)
+ + " bits long.");
+ }
+ }
+
+ public byte[] generateKey()
+ {
+ byte[] newKey = new byte[strength];
+
+ do
+ {
+ random.nextBytes(newKey);
+
+ DESedeParameters.setOddParity(newKey);
+ }
+ while (DESedeParameters.isWeakKey(newKey, 0, newKey.length));
+
+ return newKey;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java
new file mode 100644
index 0000000..f93428e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHBasicKeyPairGenerator.java
@@ -0,0 +1,42 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+import java.math.BigInteger;
+
+/**
+ * a basic Diffie-Hellman key pair generator.
+ *
+ * This generates keys consistent for use with the basic algorithm for
+ * Diffie-Hellman.
+ */
+public class DHBasicKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private DHKeyGenerationParameters param;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.param = (DHKeyGenerationParameters)param;
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ DHKeyGeneratorHelper helper = DHKeyGeneratorHelper.INSTANCE;
+ DHParameters dhp = param.getParameters();
+
+ BigInteger x = helper.calculatePrivate(dhp, param.getRandom());
+ BigInteger y = helper.calculatePublic(dhp, x);
+
+ return new AsymmetricCipherKeyPair(
+ new DHPublicKeyParameters(y, dhp),
+ new DHPrivateKeyParameters(x, dhp));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
new file mode 100644
index 0000000..e0d86fc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java
@@ -0,0 +1,51 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.util.BigIntegers;
+
+class DHKeyGeneratorHelper
+{
+ static final DHKeyGeneratorHelper INSTANCE = new DHKeyGeneratorHelper();
+
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ private 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);
+ }
+
+ BigInteger min = TWO;
+ int m = dhParams.getM();
+ if (m != 0)
+ {
+ min = ONE.shiftLeft(m - 1);
+ }
+
+ BigInteger max = p.subtract(TWO);
+ BigInteger q = dhParams.getQ();
+ if (q != null)
+ {
+ max = q.subtract(TWO);
+ }
+
+ return BigIntegers.createRandomInRange(min, max, random);
+ }
+
+ BigInteger calculatePublic(DHParameters dhParams, BigInteger x)
+ {
+ return dhParams.getG().modPow(x, dhParams.getP());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java
new file mode 100644
index 0000000..f5d4264
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersGenerator.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.params.DHParameters;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+public class DHParametersGenerator
+{
+ private int size;
+ private int certainty;
+ private SecureRandom random;
+
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ /**
+ * Initialise the parameters generator.
+ *
+ * @param size bit length for the prime p
+ * @param certainty level of certainty for the prime number tests
+ * @param random a source of randomness
+ */
+ public void init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ this.size = size;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which generates the p and g values from the given parameters,
+ * returning the DHParameters object.
+ * <p>
+ * Note: can take a while...
+ */
+ public DHParameters generateParameters()
+ {
+ //
+ // find a safe prime p where p = 2*q + 1, where p and q are prime.
+ //
+ BigInteger[] safePrimes = DHParametersHelper.generateSafePrimes(size, certainty, random);
+
+ BigInteger p = safePrimes[0];
+ BigInteger q = safePrimes[1];
+ BigInteger g = DHParametersHelper.selectGenerator(p, q, random);
+
+ return new DHParameters(p, g, q, TWO, null);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java
new file mode 100644
index 0000000..05c7839
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DHParametersHelper.java
@@ -0,0 +1,93 @@
+package org.bouncycastle.crypto.generators;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+// BEGIN android-added
+import java.util.logging.Logger;
+// END android-added
+import org.bouncycastle.util.BigIntegers;
+
+class DHParametersHelper
+{
+ // BEGIN android-added
+ private static final Logger logger = Logger.getLogger(DHParametersHelper.class.getName());
+ // END android-added
+
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+ private static final BigInteger TWO = BigInteger.valueOf(2);
+
+ /*
+ * Finds a pair of prime BigInteger's {p, q: p = 2q + 1}
+ *
+ * (see: Handbook of Applied Cryptography 4.86)
+ */
+ static BigInteger[] generateSafePrimes(int size, int certainty, SecureRandom random)
+ {
+ // BEGIN android-added
+ logger.info("Generating safe primes. This may take a long time.");
+ long start = System.currentTimeMillis();
+ int tries = 0;
+ // END android-added
+ BigInteger p, q;
+ int qLength = size - 1;
+
+ for (;;)
+ {
+ // BEGIN android-added
+ tries++;
+ // END android-added
+ q = new BigInteger(qLength, 2, random);
+
+ // p <- 2q + 1
+ p = q.shiftLeft(1).add(ONE);
+
+ if (p.isProbablePrime(certainty) && (certainty <= 2 || q.isProbablePrime(certainty)))
+ {
+ break;
+ }
+ }
+ // BEGIN android-added
+ long end = System.currentTimeMillis();
+ long duration = end - start;
+ logger.info("Generated safe primes: " + tries + " tries took " + duration + "ms");
+ // END android-added
+
+ return new BigInteger[] { p, q };
+ }
+
+ /*
+ * Select a high order element of the multiplicative group Zp*
+ *
+ * p and q must be s.t. p = 2*q + 1, where p and q are prime (see generateSafePrimes)
+ */
+ static BigInteger selectGenerator(BigInteger p, BigInteger q, SecureRandom random)
+ {
+ BigInteger pMinusTwo = p.subtract(TWO);
+ BigInteger g;
+
+ /*
+ * (see: Handbook of Applied Cryptography 4.80)
+ */
+// do
+// {
+// g = BigIntegers.createRandomInRange(TWO, pMinusTwo, random);
+// }
+// while (g.modPow(TWO, p).equals(ONE) || g.modPow(q, p).equals(ONE));
+
+
+ /*
+ * RFC 2631 2.2.1.2 (and see: Handbook of Applied Cryptography 4.81)
+ */
+ do
+ {
+ BigInteger h = BigIntegers.createRandomInRange(TWO, pMinusTwo, random);
+
+ g = h.modPow(TWO, p);
+ }
+ while (g.equals(ONE));
+
+
+ return g;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java
new file mode 100644
index 0000000..93f49cf
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAKeyPairGenerator.java
@@ -0,0 +1,61 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+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.util.BigIntegers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * a DSA key pair generator.
+ *
+ * This generates DSA keys in line with the method described
+ * in <i>FIPS 186-3 B.1 FFC Key Pair Generation</i>.
+ */
+public class DSAKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
+ private DSAKeyGenerationParameters param;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.param = (DSAKeyGenerationParameters)param;
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ DSAParameters dsaParams = param.getParameters();
+
+ BigInteger x = generatePrivateKey(dsaParams.getQ(), param.getRandom());
+ BigInteger y = calculatePublicKey(dsaParams.getP(), dsaParams.getG(), x);
+
+ return new AsymmetricCipherKeyPair(
+ new DSAPublicKeyParameters(y, dsaParams),
+ new DSAPrivateKeyParameters(x, dsaParams));
+ }
+
+ 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);
+ }
+
+ private static BigInteger calculatePublicKey(BigInteger p, BigInteger g, BigInteger x)
+ {
+ return g.modPow(x, p);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
new file mode 100644
index 0000000..98dd0f7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/DSAParametersGenerator.java
@@ -0,0 +1,342 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.Digest;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-changed
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAValidationParameters;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+// TODO Update javadoc to mention FIPS 186-3 when done
+/**
+ * generate suitable parameters for DSA, in line with FIPS 186-2.
+ */
+public class DSAParametersGenerator
+{
+ 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);
+
+ /**
+ * initialise the key generator.
+ *
+ * @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.
+ */
+ public void init(
+ int size,
+ int certainty,
+ SecureRandom random)
+ {
+ init(size, getDefaultN(size), certainty, random);
+ }
+
+ // TODO Make public to enable support for DSA keys > 1024 bits
+ private void init(
+ int L,
+ int N,
+ int certainty,
+ SecureRandom random)
+ {
+ // TODO Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2)
+ // TODO Should we enforce the minimum 'certainty' values as per C.3 Table C.1?
+
+ this.L = L;
+ this.N = N;
+ this.certainty = certainty;
+ this.random = random;
+ }
+
+ /**
+ * which generates the p and g values from the given parameters,
+ * returning the DSAParameters object.
+ * <p>
+ * Note: can take a while...
+ */
+ public DSAParameters generateParameters()
+ {
+ return L > 1024
+ ? generateParameters_FIPS186_3()
+ : generateParameters_FIPS186_2();
+ }
+
+ private DSAParameters generateParameters_FIPS186_2()
+ {
+ byte[] seed = new byte[20];
+ byte[] part1 = new byte[20];
+ byte[] part2 = new byte[20];
+ byte[] u = new byte[20];
+ // BEGIN android-changed
+ Digest sha1 = AndroidDigestFactory.getSHA1();
+ // END android-changed
+ int n = (L - 1) / 160;
+ byte[] w = new byte[L / 8];
+
+ for (;;)
+ {
+ random.nextBytes(seed);
+
+ hash(sha1, seed, part1);
+ System.arraycopy(seed, 0, part2, 0, seed.length);
+ inc(part2);
+ hash(sha1, part2, part2);
+
+ for (int i = 0; i != u.length; i++)
+ {
+ u[i] = (byte)(part1[i] ^ part2[i]);
+ }
+
+ u[0] |= (byte)0x80;
+ u[19] |= (byte)0x01;
+
+ BigInteger q = new BigInteger(1, u);
+
+ if (!q.isProbablePrime(certainty))
+ {
+ continue;
+ }
+
+ byte[] offset = Arrays.clone(seed);
+ inc(offset);
+
+ for (int counter = 0; counter < 4096; ++counter)
+ {
+ for (int k = 0; k < n; k++)
+ {
+ inc(offset);
+ hash(sha1, offset, part1);
+ System.arraycopy(part1, 0, w, w.length - (k + 1) * part1.length, part1.length);
+ }
+
+ inc(offset);
+ hash(sha1, offset, part1);
+ System.arraycopy(part1, part1.length - ((w.length - (n) * part1.length)), w, 0, w.length - n * part1.length);
+
+ w[0] |= (byte)0x80;
+
+ BigInteger x = new BigInteger(1, w);
+
+ BigInteger c = x.mod(q.shiftLeft(1));
+
+ BigInteger p = x.subtract(c.subtract(ONE));
+
+ if (p.bitLength() != L)
+ {
+ continue;
+ }
+
+ if (p.isProbablePrime(certainty))
+ {
+ BigInteger g = calculateGenerator_FIPS186_2(p, q, random);
+
+ return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
+ }
+ }
+ }
+ }
+
+ private static BigInteger calculateGenerator_FIPS186_2(BigInteger p, BigInteger q, SecureRandom r)
+ {
+ BigInteger e = p.subtract(ONE).divide(q);
+ BigInteger pSub2 = p.subtract(TWO);
+
+ for (;;)
+ {
+ BigInteger h = BigIntegers.createRandomInRange(TWO, pSub2, r);
+ BigInteger g = h.modPow(e, p);
+ if (g.bitLength() > 1)
+ {
+ return g;
+ }
+ }
+ }
+
+ /**
+ * generate suitable parameters for DSA, in line with
+ * <i>FIPS 186-3 A.1 Generation of the FFC Primes p and q</i>.
+ */
+ private DSAParameters generateParameters_FIPS186_3()
+ {
+// A.1.1.2 Generation of the Probable Primes p and q Using an Approved Hash Function
+ // FIXME This should be configurable (digest size in bits must be >= N)
+ // BEGIN android-changed
+ Digest d = AndroidDigestFactory.getSHA256();
+ // END android-changed
+ int outlen = d.getDigestSize() * 8;
+
+// 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
+// the pair is not in the list, then return INVALID.
+ // Note: checked at initialisation
+
+// 2. If (seedlen < N), then return INVALID.
+ // FIXME This should be configurable (must be >= N)
+ int seedlen = N;
+ byte[] seed = new byte[seedlen / 8];
+
+// 3. n = ceiling(L ⁄ outlen) – 1.
+ int n = (L - 1) / outlen;
+
+// 4. b = L – 1 – (n ∗ outlen).
+ int b = (L - 1) % outlen;
+
+ byte[] output = new byte[d.getDigestSize()];
+ for (;;)
+ {
+// 5. Get an arbitrary sequence of seedlen bits as the domain_parameter_seed.
+ random.nextBytes(seed);
+
+// 6. U = Hash (domain_parameter_seed) mod 2^(N–1).
+ hash(d, seed, output);
+ 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));
+
+// 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))
+ {
+// 9. If q is not a prime, then go to step 5.
+ continue;
+ }
+
+// 10. offset = 1.
+ // Note: 'offset' value managed incrementally
+ byte[] offset = Arrays.clone(seed);
+
+// 11. For counter = 0 to (4L – 1) do
+ int counterLimit = 4 * L;
+ for (int counter = 0; counter < counterLimit; ++counter)
+ {
+// 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)
+ {
+ Vj = Vj.mod(ONE.shiftLeft(b));
+ }
+
+ W = W.add(Vj.shiftLeft(exp));
+ }
+
+// 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));
+
+// 11.4 c = X mod 2q.
+ BigInteger c = X.mod(q.shiftLeft(1));
+
+// 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
+ 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))
+ {
+// 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.
+ // TODO Make configurable (8-bit unsigned)?
+// int index = 1;
+// BigInteger g = calculateGenerator_FIPS186_3_Verifiable(d, p, q, seed, index);
+// if (g != null)
+// {
+// // TODO Should 'index' be a part of the validation parameters?
+// return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
+// }
+
+ BigInteger g = calculateGenerator_FIPS186_3_Unverifiable(p, q, random);
+ return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter));
+ }
+
+// 11.9 offset = offset + n + 1. Comment: Increment offset; then, as part of
+// the loop in step 11, increment counter; if
+// counter < 4L, repeat steps 11.1 through 11.8.
+ // Note: 'offset' value already incremented in inner loop
+ }
+// 12. Go to step 5.
+ }
+ }
+
+ private static BigInteger calculateGenerator_FIPS186_3_Unverifiable(BigInteger p, BigInteger q,
+ SecureRandom r)
+ {
+ return calculateGenerator_FIPS186_2(p, q, r);
+ }
+
+// private static BigInteger calculateGenerator_FIPS186_3_Verifiable(Digest d, BigInteger p, BigInteger q,
+// byte[] seed, int index)
+// {
+//// A.2.3 Verifiable Canonical Generation of the Generator g
+// BigInteger e = p.subtract(ONE).divide(q);
+// byte[] ggen = Hex.decode("6767656E");
+//
+// // 7. U = domain_parameter_seed || "ggen" || index || count.
+// byte[] U = new byte[seed.length + ggen.length + 1 + 2];
+// System.arraycopy(seed, 0, U, 0, seed.length);
+// System.arraycopy(ggen, 0, U, seed.length, ggen.length);
+// U[U.length - 3] = (byte)index;
+//
+// byte[] w = new byte[d.getDigestSize()];
+// for (int count = 1; count < (1 << 16); ++count)
+// {
+// inc(U);
+// hash(d, U, w);
+// BigInteger W = new BigInteger(1, w);
+// BigInteger g = W.modPow(e, p);
+// if (g.compareTo(TWO) >= 0)
+// {
+// return g;
+// }
+// }
+//
+// return null;
+// }
+
+ private static void hash(Digest d, byte[] input, byte[] output)
+ {
+ d.update(input, 0, input.length);
+ d.doFinal(output, 0);
+ }
+
+ private static int getDefaultN(int L)
+ {
+ return L > 1024 ? 256 : 160;
+ }
+
+ private static void inc(byte[] buf)
+ {
+ for (int i = buf.length - 1; i >= 0; --i)
+ {
+ byte b = (byte)((buf[i] + 1) & 0xff);
+ buf[i] = b;
+
+ if (b != 0)
+ {
+ break;
+ }
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
new file mode 100644
index 0000000..d77bd74
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java
@@ -0,0 +1,53 @@
+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;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+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.ECPoint;
+
+public class ECKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator, ECConstants
+{
+ ECDomainParameters params;
+ SecureRandom random;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ ECKeyGenerationParameters ecP = (ECKeyGenerationParameters)param;
+
+ this.random = ecP.getRandom();
+ this.params = ecP.getDomainParameters();
+ }
+
+ /**
+ * Given the domain parameters this routine generates an EC key
+ * pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+ */
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ BigInteger n = params.getN();
+ int nBitLength = n.bitLength();
+ BigInteger d;
+
+ do
+ {
+ d = new BigInteger(nBitLength, random);
+ }
+ while (d.equals(ZERO) || (d.compareTo(n) >= 0));
+
+ ECPoint Q = params.getG().multiply(d);
+
+ return new AsymmetricCipherKeyPair(
+ new ECPublicKeyParameters(Q, params),
+ new ECPrivateKeyParameters(d, params));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
new file mode 100644
index 0000000..79ec0f2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/OpenSSLPBEParametersGenerator.java
@@ -0,0 +1,135 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-changed
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as usd by OpenSSL.
+ * <p>
+ * The scheme is a simple extension of PKCS 5 V2.0 Scheme 1 using MD5 with an
+ * iteration count of 1.
+ * <p>
+ */
+public class OpenSSLPBEParametersGenerator
+ extends PBEParametersGenerator
+{
+ // BEGIN android-changed
+ private Digest digest = AndroidDigestFactory.getMD5();
+ // END android-changed
+
+ /**
+ * Construct a OpenSSL Parameters generator.
+ */
+ public OpenSSLPBEParametersGenerator()
+ {
+ }
+
+ /**
+ * Initialise - note the iteration count for this algorithm is fixed at 1.
+ *
+ * @param password password to use.
+ * @param salt salt to use.
+ */
+ public void init(
+ byte[] password,
+ byte[] salt)
+ {
+ super.init(password, salt, 1);
+ }
+
+ /**
+ * the derived key function, the ith hash of the password and the salt.
+ */
+ private byte[] generateDerivedKey(
+ int bytesNeeded)
+ {
+ byte[] buf = new byte[digest.getDigestSize()];
+ byte[] key = new byte[bytesNeeded];
+ int offset = 0;
+
+ for (;;)
+ {
+ digest.update(password, 0, password.length);
+ digest.update(salt, 0, salt.length);
+
+ digest.doFinal(buf, 0);
+
+ int len = (bytesNeeded > buf.length) ? buf.length : bytesNeeded;
+ System.arraycopy(buf, 0, key, offset, len);
+ offset += len;
+
+ // check if we need any more
+ bytesNeeded -= len;
+ if (bytesNeeded == 0)
+ {
+ break;
+ }
+
+ // do another round
+ digest.reset();
+ digest.update(buf, 0, buf.length);
+ }
+
+ return key;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception IllegalArgumentException if the key length larger than the base hash size.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = generateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception IllegalArgumentException if the key length larger than the base hash size.
+ */
+ public CipherParameters generateDerivedMacParameters(
+ int keySize)
+ {
+ return generateDerivedParameters(keySize);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java
new file mode 100644
index 0000000..8fb1cc8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS12ParametersGenerator.java
@@ -0,0 +1,221 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 12 V1.0.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-12/index.html>
+ * RSA's PKCS12 Page</a>
+ */
+public class PKCS12ParametersGenerator
+ extends PBEParametersGenerator
+{
+ public static final int KEY_MATERIAL = 1;
+ public static final int IV_MATERIAL = 2;
+ public static final int MAC_MATERIAL = 3;
+
+ private Digest digest;
+
+ private int u;
+ private int v;
+
+ /**
+ * Construct a PKCS 12 Parameters generator. This constructor will
+ * accept any digest which also implements ExtendedDigest.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ * @exception IllegalArgumentException if an unknown digest is passed in.
+ */
+ public PKCS12ParametersGenerator(
+ Digest digest)
+ {
+ this.digest = digest;
+ if (digest instanceof ExtendedDigest)
+ {
+ u = digest.getDigestSize();
+ v = ((ExtendedDigest)digest).getByteLength();
+ }
+ else
+ {
+ throw new IllegalArgumentException("Digest " + digest.getAlgorithmName() + " unsupported");
+ }
+ }
+
+ /**
+ * add a + b + 1, returning the result in a. The a value is treated
+ * as a BigInteger of length (b.length * 8) bits. The result is
+ * modulo 2^b.length in case of overflow.
+ */
+ private void adjust(
+ byte[] a,
+ int aOff,
+ byte[] b)
+ {
+ int x = (b[b.length - 1] & 0xff) + (a[aOff + b.length - 1] & 0xff) + 1;
+
+ a[aOff + b.length - 1] = (byte)x;
+ x >>>= 8;
+
+ for (int i = b.length - 2; i >= 0; i--)
+ {
+ x += (b[i] & 0xff) + (a[aOff + i] & 0xff);
+ a[aOff + i] = (byte)x;
+ x >>>= 8;
+ }
+ }
+
+ /**
+ * generation of a derived key ala PKCS12 V1.0.
+ */
+ private byte[] generateDerivedKey(
+ int idByte,
+ int n)
+ {
+ byte[] D = new byte[v];
+ byte[] dKey = new byte[n];
+
+ for (int i = 0; i != D.length; i++)
+ {
+ D[i] = (byte)idByte;
+ }
+
+ byte[] S;
+
+ if ((salt != null) && (salt.length != 0))
+ {
+ S = new byte[v * ((salt.length + v - 1) / v)];
+
+ for (int i = 0; i != S.length; i++)
+ {
+ S[i] = salt[i % salt.length];
+ }
+ }
+ else
+ {
+ S = new byte[0];
+ }
+
+ byte[] P;
+
+ if ((password != null) && (password.length != 0))
+ {
+ P = new byte[v * ((password.length + v - 1) / v)];
+
+ for (int i = 0; i != P.length; i++)
+ {
+ P[i] = password[i % password.length];
+ }
+ }
+ else
+ {
+ P = new byte[0];
+ }
+
+ byte[] I = new byte[S.length + P.length];
+
+ System.arraycopy(S, 0, I, 0, S.length);
+ System.arraycopy(P, 0, I, S.length, P.length);
+
+ byte[] B = new byte[v];
+ int c = (n + u - 1) / u;
+
+ for (int i = 1; i <= c; i++)
+ {
+ byte[] A = new byte[u];
+
+ digest.update(D, 0, D.length);
+ digest.update(I, 0, I.length);
+ digest.doFinal(A, 0);
+ for (int j = 1; j < iterationCount; j++)
+ {
+ digest.update(A, 0, A.length);
+ digest.doFinal(A, 0);
+ }
+
+ for (int j = 0; j != B.length; j++)
+ {
+ B[j] = A[j % A.length];
+ }
+
+ for (int j = 0; j != I.length / v; j++)
+ {
+ adjust(I, j * v, B);
+ }
+
+ if (i == c)
+ {
+ System.arraycopy(A, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
+ }
+ else
+ {
+ System.arraycopy(A, 0, dKey, (i - 1) * u, A.length);
+ }
+ }
+
+ return dKey;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = generateDerivedKey(KEY_MATERIAL, keySize);
+
+ byte[] iv = generateDerivedKey(IV_MATERIAL, ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), iv, 0, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedMacParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(MAC_MATERIAL, keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java
new file mode 100644
index 0000000..1c62ecc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S1ParametersGenerator.java
@@ -0,0 +1,119 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 1.
+ * Note this generator is limited to the size of the hash produced by the
+ * digest used to drive it.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
+ * RSA's PKCS5 Page</a>
+ */
+public class PKCS5S1ParametersGenerator
+ extends PBEParametersGenerator
+{
+ private Digest digest;
+
+ /**
+ * Construct a PKCS 5 Scheme 1 Parameters generator.
+ *
+ * @param digest the digest to be used as the source of derived keys.
+ */
+ public PKCS5S1ParametersGenerator(
+ Digest digest)
+ {
+ this.digest = digest;
+ }
+
+ /**
+ * the derived key function, the ith hash of the password and the salt.
+ */
+ private byte[] generateDerivedKey()
+ {
+ byte[] digestBytes = new byte[digest.getDigestSize()];
+
+ digest.update(password, 0, password.length);
+ digest.update(salt, 0, salt.length);
+
+ digest.doFinal(digestBytes, 0);
+ for (int i = 1; i < iterationCount; i++)
+ {
+ digest.update(digestBytes, 0, digestBytes.length);
+ digest.doFinal(digestBytes, 0);
+ }
+
+ return digestBytes;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception IllegalArgumentException if the key length larger than the base hash size.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ if (keySize > digest.getDigestSize())
+ {
+ throw new IllegalArgumentException(
+ "Can't generate a derived key " + keySize + " bytes long.");
+ }
+
+ byte[] dKey = generateDerivedKey();
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ * @exception IllegalArgumentException if keySize + ivSize is larger than the base hash size.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ if ((keySize + ivSize) > digest.getDigestSize())
+ {
+ throw new IllegalArgumentException(
+ "Can't generate a derived key " + (keySize + ivSize) + " bytes long.");
+ }
+
+ byte[] dKey = generateDerivedKey();
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ * @exception IllegalArgumentException if the key length larger than the base hash size.
+ */
+ public CipherParameters generateDerivedMacParameters(
+ int keySize)
+ {
+ return generateDerivedParameters(keySize);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
new file mode 100644
index 0000000..a6d87b9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java
@@ -0,0 +1,162 @@
+package org.bouncycastle.crypto.generators;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+// BEGIN android-changed
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-changed
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2.
+ * This generator uses a SHA-1 HMac as the calculation function.
+ * <p>
+ * The document this implementation is based on can be found at
+ * <a href=http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html>
+ * RSA's PKCS5 Page</a>
+ */
+public class PKCS5S2ParametersGenerator
+ extends PBEParametersGenerator
+{
+ private Mac hMac;
+
+ /**
+ * construct a PKCS5 Scheme 2 Parameters generator.
+ */
+ public PKCS5S2ParametersGenerator()
+ {
+ // BEGIN android-changed
+ this(AndroidDigestFactory.getSHA1());
+ // END android-changed
+ }
+
+ public PKCS5S2ParametersGenerator(Digest digest)
+ {
+ hMac = new HMac(digest);
+ }
+
+ private void F(
+ byte[] P,
+ byte[] S,
+ int c,
+ byte[] iBuf,
+ byte[] out,
+ int outOff)
+ {
+ byte[] state = new byte[hMac.getMacSize()];
+ CipherParameters param = new KeyParameter(P);
+
+ hMac.init(param);
+
+ if (S != null)
+ {
+ hMac.update(S, 0, S.length);
+ }
+
+ hMac.update(iBuf, 0, iBuf.length);
+
+ hMac.doFinal(state, 0);
+
+ System.arraycopy(state, 0, out, outOff, state.length);
+
+ if (c == 0)
+ {
+ throw new IllegalArgumentException("iteration count must be at least 1.");
+ }
+
+ for (int count = 1; count < c; count++)
+ {
+ hMac.init(param);
+ hMac.update(state, 0, state.length);
+ hMac.doFinal(state, 0);
+
+ for (int j = 0; j != state.length; j++)
+ {
+ out[outOff + j] ^= state[j];
+ }
+ }
+ }
+
+ private void intToOctet(
+ byte[] buf,
+ int i)
+ {
+ buf[0] = (byte)(i >>> 24);
+ buf[1] = (byte)(i >>> 16);
+ buf[2] = (byte)(i >>> 8);
+ buf[3] = (byte)i;
+ }
+
+ private byte[] generateDerivedKey(
+ int dkLen)
+ {
+ int hLen = hMac.getMacSize();
+ int l = (dkLen + hLen - 1) / hLen;
+ byte[] iBuf = new byte[4];
+ byte[] out = new byte[l * hLen];
+
+ for (int i = 1; i <= l; i++)
+ {
+ intToOctet(iBuf, i);
+
+ F(password, salt, iterationCount, iBuf, out, (i - 1) * hLen);
+ }
+
+ return out;
+ }
+
+ /**
+ * Generate a key parameter derived from the password, salt, and iteration
+ * count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize)
+ {
+ keySize = keySize / 8;
+
+ byte[] dKey = generateDerivedKey(keySize);
+
+ return new KeyParameter(dKey, 0, keySize);
+ }
+
+ /**
+ * Generate a key with initialisation vector parameter derived from
+ * the password, salt, and iteration count we are currently initialised
+ * with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @param ivSize the size of the iv we want (in bits)
+ * @return a ParametersWithIV object.
+ */
+ public CipherParameters generateDerivedParameters(
+ int keySize,
+ int ivSize)
+ {
+ keySize = keySize / 8;
+ ivSize = ivSize / 8;
+
+ byte[] dKey = generateDerivedKey(keySize + ivSize);
+
+ return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize);
+ }
+
+ /**
+ * Generate a key parameter for use with a MAC derived from the password,
+ * salt, and iteration count we are currently initialised with.
+ *
+ * @param keySize the size of the key we want (in bits)
+ * @return a KeyParameter object.
+ */
+ public CipherParameters generateDerivedMacParameters(
+ int keySize)
+ {
+ return generateDerivedParameters(keySize);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java b/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
new file mode 100644
index 0000000..f58069d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java
@@ -0,0 +1,147 @@
+package org.bouncycastle.crypto.generators;
+
+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;
+
+/**
+ * an RSA key pair generator.
+ */
+public class RSAKeyPairGenerator
+ implements AsymmetricCipherKeyPairGenerator
+{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
+ private RSAKeyGenerationParameters param;
+
+ public void init(
+ KeyGenerationParameters param)
+ {
+ this.param = (RSAKeyGenerationParameters)param;
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ BigInteger p, q, n, d, e, pSub1, qSub1, phi;
+
+ //
+ // p and q values should have a length of half the strength in bits
+ //
+ 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")
+
+ //
+ // generate p, prime and (p-1) relatively prime to e
+ //
+ for (;;)
+ {
+ 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;
+ }
+ }
+
+ //
+ // generate a modulus of the required length
+ //
+ for (;;)
+ {
+ // generate q, prime and (q-1) relatively prime to e,
+ // and not equal to p
+ //
+ for (;;)
+ {
+ q = new BigInteger(qbitlength, 1, param.getRandom());
+
+ if (q.subtract(p).abs().bitLength() < mindiffbits)
+ {
+ continue;
+ }
+
+ if (q.mod(e).equals(ONE))
+ {
+ continue;
+ }
+
+ if (!q.isProbablePrime(param.getCertainty()))
+ {
+ continue;
+ }
+
+ if (e.gcd(q.subtract(ONE)).equals(ONE))
+ {
+ break;
+ }
+ }
+
+ //
+ // calculate the modulus
+ //
+ n = p.multiply(q);
+
+ if (n.bitLength() == param.getStrength())
+ {
+ break;
+ }
+
+ //
+ // if we get here our primes aren't big enough, make the largest
+ // of the two p and try again
+ //
+ p = p.max(q);
+ }
+
+ if (p.compareTo(q) < 0)
+ {
+ phi = p;
+ p = q;
+ q = phi;
+ }
+
+ pSub1 = p.subtract(ONE);
+ qSub1 = q.subtract(ONE);
+ phi = pSub1.multiply(qSub1);
+
+ //
+ // calculate the private exponent
+ //
+ d = e.modInverse(phi);
+
+ //
+ // calculate the CRT factors
+ //
+ BigInteger dP, dQ, qInv;
+
+ dP = d.remainder(pSub1);
+ dQ = d.remainder(qSub1);
+ qInv = q.modInverse(p);
+
+ return new AsymmetricCipherKeyPair(
+ new RSAKeyParameters(false, n, e),
+ new RSAPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
new file mode 100644
index 0000000..bb09a76
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java
@@ -0,0 +1,244 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.StreamCipher;
+
+/**
+ * A CipherInputStream is composed of an InputStream and a BufferedBlockCipher so
+ * that read() methods return data that are read in from the
+ * underlying InputStream but have been additionally processed by the
+ * Cipher. The Cipher must be fully initialized before being used by
+ * a CipherInputStream.
+ * <p>
+ * For example, if the Cipher is initialized for decryption, the
+ * CipherInputStream will attempt to read in data and decrypt them,
+ * before returning the decrypted data.
+ */
+public class CipherInputStream
+ extends FilterInputStream
+{
+ private BufferedBlockCipher bufferedBlockCipher;
+ private StreamCipher streamCipher;
+
+ private byte[] buf;
+ private byte[] inBuf;
+
+ private int bufOff;
+ private int maxBuf;
+ private boolean finalized;
+
+ private static final int INPUT_BUF_SIZE = 2048;
+
+ /**
+ * Constructs a CipherInputStream from an InputStream and a
+ * BufferedBlockCipher.
+ */
+ public CipherInputStream(
+ InputStream is,
+ BufferedBlockCipher cipher)
+ {
+ super(is);
+
+ this.bufferedBlockCipher = cipher;
+
+ buf = new byte[cipher.getOutputSize(INPUT_BUF_SIZE)];
+ inBuf = new byte[INPUT_BUF_SIZE];
+ }
+
+ public CipherInputStream(
+ InputStream is,
+ StreamCipher cipher)
+ {
+ super(is);
+
+ this.streamCipher = cipher;
+
+ buf = new byte[INPUT_BUF_SIZE];
+ inBuf = new byte[INPUT_BUF_SIZE];
+ }
+
+ /**
+ * grab the next chunk of input from the underlying input stream
+ */
+ private int nextChunk()
+ throws IOException
+ {
+ int available = super.available();
+
+ // must always try to read 1 byte!
+ // some buggy InputStreams return < 0!
+ if (available <= 0)
+ {
+ available = 1;
+ }
+
+ if (available > inBuf.length)
+ {
+ available = super.read(inBuf, 0, inBuf.length);
+ }
+ else
+ {
+ available = super.read(inBuf, 0, available);
+ }
+
+ if (available < 0)
+ {
+ if (finalized)
+ {
+ return -1;
+ }
+
+ try
+ {
+ if (bufferedBlockCipher != null)
+ {
+ maxBuf = bufferedBlockCipher.doFinal(buf, 0);
+ }
+ else
+ {
+ maxBuf = 0; // a stream cipher
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error processing stream: " + e.toString());
+ }
+
+ bufOff = 0;
+
+ finalized = true;
+
+ if (bufOff == maxBuf)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ bufOff = 0;
+
+ try
+ {
+ if (bufferedBlockCipher != null)
+ {
+ maxBuf = bufferedBlockCipher.processBytes(inBuf, 0, available, buf, 0);
+ }
+ else
+ {
+ streamCipher.processBytes(inBuf, 0, available, buf, 0);
+ maxBuf = available;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error processing stream: " + e.toString());
+ }
+
+ if (maxBuf == 0) // not enough bytes read for first block...
+ {
+ return nextChunk();
+ }
+ }
+
+ return maxBuf;
+ }
+
+ public int read()
+ throws IOException
+ {
+ if (bufOff == maxBuf)
+ {
+ if (nextChunk() < 0)
+ {
+ return -1;
+ }
+ }
+
+ return buf[bufOff++] & 0xff;
+ }
+
+ public int read(
+ byte[] b)
+ throws IOException
+ {
+ return read(b, 0, b.length);
+ }
+
+ public int read(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ if (bufOff == maxBuf)
+ {
+ if (nextChunk() < 0)
+ {
+ return -1;
+ }
+ }
+
+ int available = maxBuf - bufOff;
+
+ if (len > available)
+ {
+ System.arraycopy(buf, bufOff, b, off, available);
+ bufOff = maxBuf;
+
+ return available;
+ }
+ else
+ {
+ System.arraycopy(buf, bufOff, b, off, len);
+ bufOff += len;
+
+ return len;
+ }
+ }
+
+ public long skip(
+ long n)
+ throws IOException
+ {
+ if (n <= 0)
+ {
+ return 0;
+ }
+
+ int available = maxBuf - bufOff;
+
+ if (n > available)
+ {
+ bufOff = maxBuf;
+
+ return available;
+ }
+ else
+ {
+ bufOff += (int)n;
+
+ return (int)n;
+ }
+ }
+
+ public int available()
+ throws IOException
+ {
+ return maxBuf - bufOff;
+ }
+
+ public void close()
+ throws IOException
+ {
+ super.close();
+ }
+
+ public boolean markSupported()
+ {
+ return false;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java
new file mode 100644
index 0000000..17a7b6d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java
@@ -0,0 +1,188 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.StreamCipher;
+
+public class CipherOutputStream
+ extends FilterOutputStream
+{
+ private BufferedBlockCipher bufferedBlockCipher;
+ private StreamCipher streamCipher;
+
+ private byte[] oneByte = new byte[1];
+ private byte[] buf;
+
+ /**
+ * Constructs a CipherOutputStream from an OutputStream and a
+ * BufferedBlockCipher.
+ */
+ public CipherOutputStream(
+ OutputStream os,
+ BufferedBlockCipher cipher)
+ {
+ super(os);
+ this.bufferedBlockCipher = cipher;
+ this.buf = new byte[cipher.getBlockSize()];
+ }
+
+ /**
+ * Constructs a CipherOutputStream from an OutputStream and a
+ * BufferedBlockCipher.
+ */
+ public CipherOutputStream(
+ OutputStream os,
+ StreamCipher cipher)
+ {
+ super(os);
+ this.streamCipher = cipher;
+ }
+
+ /**
+ * Writes the specified byte to this output stream.
+ *
+ * @param b the <code>byte</code>.
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public void write(
+ int b)
+ throws IOException
+ {
+ oneByte[0] = (byte)b;
+
+ if (bufferedBlockCipher != null)
+ {
+ int len = bufferedBlockCipher.processBytes(oneByte, 0, 1, buf, 0);
+
+ if (len != 0)
+ {
+ out.write(buf, 0, len);
+ }
+ }
+ else
+ {
+ out.write(streamCipher.returnByte((byte)b));
+ }
+ }
+
+ /**
+ * Writes <code>b.length</code> bytes from the specified byte array
+ * to this output stream.
+ * <p>
+ * The <code>write</code> method of
+ * <code>CipherOutputStream</code> calls the <code>write</code>
+ * method of three arguments with the three arguments
+ * <code>b</code>, <code>0</code>, and <code>b.length</code>.
+ *
+ * @param b the data.
+ * @exception java.io.IOException if an I/O error occurs.
+ * @see #write(byte[], int, int)
+ */
+ public void write(
+ byte[] b)
+ throws IOException
+ {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Writes <code>len</code> bytes from the specified byte array
+ * starting at offset <code>off</code> to this output stream.
+ *
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public void write(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ if (bufferedBlockCipher != null)
+ {
+ byte[] buf = new byte[bufferedBlockCipher.getOutputSize(len)];
+
+ int outLen = bufferedBlockCipher.processBytes(b, off, len, buf, 0);
+
+ if (outLen != 0)
+ {
+ out.write(buf, 0, outLen);
+ }
+ }
+ else
+ {
+ byte[] buf = new byte[len];
+
+ streamCipher.processBytes(b, off, len, buf, 0);
+
+ out.write(buf, 0, len);
+ }
+ }
+
+ /**
+ * Flushes this output stream by forcing any buffered output bytes
+ * that have already been processed by the encapsulated cipher object
+ * to be written out.
+ *
+ * <p>
+ * Any bytes buffered by the encapsulated cipher
+ * and waiting to be processed by it will not be written out. For example,
+ * if the encapsulated cipher is a block cipher, and the total number of
+ * bytes written using one of the <code>write</code> methods is less than
+ * the cipher's block size, no bytes will be written out.
+ *
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public void flush()
+ throws IOException
+ {
+ super.flush();
+ }
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with this stream.
+ * <p>
+ * This method invokes the <code>doFinal</code> method of the encapsulated
+ * cipher object, which causes any bytes buffered by the encapsulated
+ * cipher to be processed. The result is written out by calling the
+ * <code>flush</code> method of this output stream.
+ * <p>
+ * This method resets the encapsulated cipher object to its initial state
+ * and calls the <code>close</code> method of the underlying output
+ * stream.
+ *
+ * @exception java.io.IOException if an I/O error occurs.
+ */
+ public void close()
+ throws IOException
+ {
+ try
+ {
+ if (bufferedBlockCipher != null)
+ {
+ byte[] buf = new byte[bufferedBlockCipher.getOutputSize(0)];
+
+ int outLen = bufferedBlockCipher.doFinal(buf, 0);
+
+ if (outLen != 0)
+ {
+ out.write(buf, 0, outLen);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Error closing stream: " + e.toString());
+ }
+
+ flush();
+
+ super.close();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java
new file mode 100644
index 0000000..ef0b03e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestInputStream.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.crypto.Digest;
+
+public class DigestInputStream
+ extends FilterInputStream
+{
+ protected Digest digest;
+
+ public DigestInputStream(
+ InputStream stream,
+ Digest digest)
+ {
+ super(stream);
+ this.digest = digest;
+ }
+
+ public int read()
+ throws IOException
+ {
+ int b = in.read();
+
+ if (b >= 0)
+ {
+ digest.update((byte)b);
+ }
+ return b;
+ }
+
+ public int read(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ int n = in.read(b, off, len);
+ if (n > 0)
+ {
+ digest.update(b, off, n);
+ }
+ return n;
+ }
+
+ public Digest getDigest()
+ {
+ return digest;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java
new file mode 100644
index 0000000..23c7e53
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/DigestOutputStream.java
@@ -0,0 +1,42 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bouncycastle.crypto.Digest;
+
+public class DigestOutputStream
+ extends OutputStream
+{
+ protected Digest digest;
+
+ public DigestOutputStream(
+ Digest Digest)
+ {
+ this.digest = Digest;
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ digest.update((byte)b);
+ }
+
+ public void write(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ digest.update(b, off, len);
+ }
+
+ public byte[] getDigest()
+ {
+ byte[] res = new byte[digest.getDigestSize()];
+
+ digest.doFinal(res, 0);
+
+ return res;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java
new file mode 100644
index 0000000..b78548c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/MacInputStream.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.crypto.Mac;
+
+public class MacInputStream
+ extends FilterInputStream
+{
+ protected Mac mac;
+
+ public MacInputStream(
+ InputStream stream,
+ Mac mac)
+ {
+ super(stream);
+ this.mac = mac;
+ }
+
+ public int read()
+ throws IOException
+ {
+ int b = in.read();
+
+ if (b >= 0)
+ {
+ mac.update((byte)b);
+ }
+ return b;
+ }
+
+ public int read(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ int n = in.read(b, off, len);
+ if (n >= 0)
+ {
+ mac.update(b, off, n);
+ }
+ return n;
+ }
+
+ public Mac getMac()
+ {
+ return mac;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java b/bcprov/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java
new file mode 100644
index 0000000..0f0e7db
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/io/MacOutputStream.java
@@ -0,0 +1,42 @@
+package org.bouncycastle.crypto.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.bouncycastle.crypto.Mac;
+
+public class MacOutputStream
+ extends OutputStream
+{
+ protected Mac mac;
+
+ public MacOutputStream(
+ Mac mac)
+ {
+ this.mac = mac;
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ mac.update((byte)b);
+ }
+
+ public void write(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ mac.update(b, off, len);
+ }
+
+ public byte[] getMac()
+ {
+ byte[] res = new byte[mac.getMacSize()];
+
+ mac.doFinal(res, 0);
+
+ return res;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java
new file mode 100644
index 0000000..9bf6cb0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/CBCBlockCipherMac.java
@@ -0,0 +1,229 @@
+package org.bouncycastle.crypto.macs;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.paddings.BlockCipherPadding;
+
+/**
+ * standard CBC Block Cipher MAC - if no padding is specified the default of
+ * pad of zeroes is used.
+ */
+public class CBCBlockCipherMac
+ implements Mac
+{
+ private byte[] mac;
+
+ private byte[] buf;
+ private int bufOff;
+ private BlockCipher cipher;
+ private BlockCipherPadding padding;
+
+ private int macSize;
+
+ /**
+ * create a standard MAC based on a CBC block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ */
+ public CBCBlockCipherMac(
+ BlockCipher cipher)
+ {
+ this(cipher, (cipher.getBlockSize() * 8) / 2, null);
+ }
+
+ /**
+ * create a standard MAC based on a CBC block cipher. This will produce an
+ * authentication code half the length of the block size of the cipher.
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public CBCBlockCipherMac(
+ BlockCipher cipher,
+ BlockCipherPadding padding)
+ {
+ this(cipher, (cipher.getBlockSize() * 8) / 2, padding);
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CBC mode as the basis for the
+ * MAC generation.
+ * <p>
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ */
+ public CBCBlockCipherMac(
+ BlockCipher cipher,
+ int macSizeInBits)
+ {
+ this(cipher, macSizeInBits, null);
+ }
+
+ /**
+ * create a standard MAC based on a block cipher with the size of the
+ * MAC been given in bits. This class uses CBC mode as the basis for the
+ * MAC generation.
+ * <p>
+ * Note: the size of the MAC must be at least 24 bits (FIPS Publication 81),
+ * or 16 bits if being used as a data authenticator (FIPS Publication 113),
+ * and in general should be less than the size of the block cipher as it reduces
+ * the chance of an exhaustive attack (see Handbook of Applied Cryptography).
+ *
+ * @param cipher the cipher to be used as the basis of the MAC generation.
+ * @param macSizeInBits the size of the MAC in bits, must be a multiple of 8.
+ * @param padding the padding to be used to complete the last block.
+ */
+ public CBCBlockCipherMac(
+ BlockCipher cipher,
+ int macSizeInBits,
+ BlockCipherPadding padding)
+ {
+ if ((macSizeInBits % 8) != 0)
+ {
+ throw new IllegalArgumentException("MAC size must be multiple of 8");
+ }
+
+ this.cipher = new CBCBlockCipher(cipher);
+ this.padding = padding;
+ this.macSize = macSizeInBits / 8;
+
+ mac = new byte[cipher.getBlockSize()];
+
+ buf = new byte[cipher.getBlockSize()];
+ bufOff = 0;
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName();
+ }
+
+ public void init(
+ CipherParameters params)
+ {
+ reset();
+
+ cipher.init(true, params);
+ }
+
+ public int getMacSize()
+ {
+ return macSize;
+ }
+
+ public void update(
+ byte in)
+ {
+ if (bufOff == buf.length)
+ {
+ cipher.processBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = in;
+ }
+
+ public void update(
+ byte[] in,
+ int inOff,
+ int len)
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = cipher.getBlockSize();
+ int gapLen = blockSize - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ cipher.processBlock(buf, 0, mac, 0);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ cipher.processBlock(in, inOff, mac, 0);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ int blockSize = cipher.getBlockSize();
+
+ if (padding == null)
+ {
+ //
+ // pad with zeroes
+ //
+ while (bufOff < blockSize)
+ {
+ buf[bufOff] = 0;
+ bufOff++;
+ }
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ cipher.processBlock(buf, 0, mac, 0);
+ bufOff = 0;
+ }
+
+ padding.addPadding(buf, bufOff);
+ }
+
+ cipher.processBlock(buf, 0, mac, 0);
+
+ System.arraycopy(mac, 0, out, outOff, macSize);
+
+ reset();
+
+ return macSize;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void reset()
+ {
+ /*
+ * clean the buffer.
+ */
+ for (int i = 0; i < buf.length; i++)
+ {
+ buf[i] = 0;
+ }
+
+ bufOff = 0;
+
+ /*
+ * reset the underlying cipher.
+ */
+ cipher.reset();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java b/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java
new file mode 100644
index 0000000..c0c8333
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/macs/HMac.java
@@ -0,0 +1,207 @@
+package org.bouncycastle.crypto.macs;
+
+import java.util.Hashtable;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.params.KeyParameter;
+
+/**
+ * HMAC implementation based on RFC2104
+ *
+ * H(K XOR opad, H(K XOR ipad, text))
+ */
+public class HMac
+ implements Mac
+{
+ private final static byte IPAD = (byte)0x36;
+ private final static byte OPAD = (byte)0x5C;
+
+ private Digest digest;
+ private int digestSize;
+ private int blockLength;
+
+ private byte[] inputPad;
+ private byte[] outputPad;
+
+ private static Hashtable blockLengths;
+
+ static
+ {
+ blockLengths = new Hashtable();
+
+ // BEGIN android-removed
+ // blockLengths.put("GOST3411", Integer.valueOf(32));
+ //
+ // blockLengths.put("MD2", Integer.valueOf(16));
+ // blockLengths.put("MD4", Integer.valueOf(64));
+ // END android-removed
+ blockLengths.put("MD5", Integer.valueOf(64));
+
+ // BEGIN android-removed
+ // blockLengths.put("RIPEMD128", Integer.valueOf(64));
+ // blockLengths.put("RIPEMD160", Integer.valueOf(64));
+ // END android-removed
+
+ blockLengths.put("SHA-1", Integer.valueOf(64));
+ // BEGIN android-removed
+ // blockLengths.put("SHA-224", Integer.valueOf(64));
+ // END android-removed
+ blockLengths.put("SHA-256", Integer.valueOf(64));
+ blockLengths.put("SHA-384", Integer.valueOf(128));
+ blockLengths.put("SHA-512", Integer.valueOf(128));
+
+ // BEGIN android-removed
+ // blockLengths.put("Tiger", Integer.valueOf(64));
+ // blockLengths.put("Whirlpool", Integer.valueOf(64));
+ // END android-removed
+ }
+
+ private static int getByteLength(
+ Digest digest)
+ {
+ if (digest instanceof ExtendedDigest)
+ {
+ return ((ExtendedDigest)digest).getByteLength();
+ }
+
+ Integer b = (Integer)blockLengths.get(digest.getAlgorithmName());
+
+ if (b == null)
+ {
+ throw new IllegalArgumentException("unknown digest passed: " + digest.getAlgorithmName());
+ }
+
+ return b.intValue();
+ }
+
+ /**
+ * Base constructor for one of the standard digest algorithms that the
+ * byteLength of the algorithm is know for.
+ *
+ * @param digest the digest.
+ */
+ public HMac(
+ Digest digest)
+ {
+ this(digest, getByteLength(digest));
+ }
+
+ private HMac(
+ Digest digest,
+ int byteLength)
+ {
+ this.digest = digest;
+ digestSize = digest.getDigestSize();
+
+ this.blockLength = byteLength;
+
+ inputPad = new byte[blockLength];
+ outputPad = new byte[blockLength];
+ }
+
+ public String getAlgorithmName()
+ {
+ return digest.getAlgorithmName() + "/HMAC";
+ }
+
+ public Digest getUnderlyingDigest()
+ {
+ return digest;
+ }
+
+ public void init(
+ CipherParameters params)
+ {
+ digest.reset();
+
+ byte[] key = ((KeyParameter)params).getKey();
+
+ if (key.length > blockLength)
+ {
+ digest.update(key, 0, key.length);
+ digest.doFinal(inputPad, 0);
+ for (int i = digestSize; i < inputPad.length; i++)
+ {
+ inputPad[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(key, 0, inputPad, 0, key.length);
+ for (int i = key.length; i < inputPad.length; i++)
+ {
+ inputPad[i] = 0;
+ }
+ }
+
+ outputPad = new byte[inputPad.length];
+ System.arraycopy(inputPad, 0, outputPad, 0, inputPad.length);
+
+ for (int i = 0; i < inputPad.length; i++)
+ {
+ inputPad[i] ^= IPAD;
+ }
+
+ for (int i = 0; i < outputPad.length; i++)
+ {
+ outputPad[i] ^= OPAD;
+ }
+
+ digest.update(inputPad, 0, inputPad.length);
+ }
+
+ public int getMacSize()
+ {
+ return digestSize;
+ }
+
+ public void update(
+ byte in)
+ {
+ digest.update(in);
+ }
+
+ public void update(
+ byte[] in,
+ int inOff,
+ int len)
+ {
+ digest.update(in, inOff, len);
+ }
+
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ {
+ byte[] tmp = new byte[digestSize];
+ digest.doFinal(tmp, 0);
+
+ digest.update(outputPad, 0, outputPad.length);
+ digest.update(tmp, 0, tmp.length);
+
+ int len = digest.doFinal(out, outOff);
+
+ reset();
+
+ return len;
+ }
+
+ /**
+ * Reset the mac generator.
+ */
+ public void reset()
+ {
+ /*
+ * reset the underlying digest.
+ */
+ digest.reset();
+
+ /*
+ * reinitialize the digest.
+ */
+ digest.update(inputPad, 0, inputPad.length);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
new file mode 100644
index 0000000..3c3bf34
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data.
+ * @see org.bouncycastle.crypto.params.AEADParameters
+ */
+public interface AEADBlockCipher
+{
+ /**
+ * initialise the underlying cipher. Parameter can either be an AEADParameters or a ParametersWithIV object.
+ *
+ * @param forEncryption true if we are setting up for encryption, false otherwise.
+ * @param params the necessary parameters for the underlying cipher to be initialised.
+ * @exception IllegalArgumentException if the params argument is inappropriate.
+ */
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ /**
+ * Return the name of the algorithm.
+ *
+ * @return the algorithm name.
+ */
+ public String getAlgorithmName();
+
+ /**
+ * return the cipher this object wraps.
+ *
+ * @return the cipher this object wraps.
+ */
+ public BlockCipher getUnderlyingCipher();
+
+ /**
+ * encrypt/decrypt a single byte.
+ *
+ * @param in the byte to be processed.
+ * @param out the output buffer the processed byte goes into.
+ * @param outOff the offset into the output byte array the processed data starts at.
+ * @return the number of bytes written to out.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException;
+
+ /**
+ * 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 starts at.
+ * @return the number of bytes written to out.
+ * @exception DataLengthException if the output buffer is too small.
+ */
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException;
+
+ /**
+ * Finish the operation either appending or verifying the MAC at the end of the data.
+ *
+ * @param out space for any resulting output data.
+ * @param outOff offset into out to start copying the data at.
+ * @return number of bytes written into out.
+ * @throws IllegalStateException if the cipher is in an inappropriate state.
+ * @throws org.bouncycastle.crypto.InvalidCipherTextException if the MAC fails to match.
+ */
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException;
+
+ /**
+ * Return the value of the MAC associated with the last stream processed.
+ *
+ * @return MAC for plaintext data.
+ */
+ public byte[] getMac();
+
+ /**
+ * return the size of the output buffer required for a processBytes
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to processBytes
+ * with len bytes of input.
+ */
+ public int getUpdateOutputSize(int len);
+
+ /**
+ * return the size of the output buffer required for a processBytes plus a
+ * doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to processBytes and doFinal
+ * with len bytes of input.
+ */
+ public int getOutputSize(int len);
+
+ /**
+ * Reset the cipher. After resetting the cipher is in the same state
+ * as it was after the last init (if there was one).
+ */
+ public void reset();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java
new file mode 100644
index 0000000..1219f6d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CBCBlockCipher.java
@@ -0,0 +1,253 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
+ */
+public class CBCBlockCipher
+ implements BlockCipher
+{
+ private byte[] IV;
+ private byte[] cbcV;
+ private byte[] cbcNextV;
+
+ private int blockSize;
+ private BlockCipher cipher = null;
+ private boolean encrypting;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of chaining.
+ */
+ public CBCBlockCipher(
+ BlockCipher cipher)
+ {
+ this.cipher = cipher;
+ this.blockSize = cipher.getBlockSize();
+
+ this.IV = new byte[blockSize];
+ this.cbcV = new byte[blockSize];
+ this.cbcNextV = new byte[blockSize];
+ }
+
+ /**
+ * 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.
+ *
+ * @param encrypting if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ boolean oldEncrypting = this.encrypting;
+
+ this.encrypting = encrypting;
+
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+
+ if (iv.length != blockSize)
+ {
+ throw new IllegalArgumentException("initialisation vector must be the same length as block size");
+ }
+
+ System.arraycopy(iv, 0, IV, 0, iv.length);
+
+ reset();
+
+ // if null it's an IV changed only.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(encrypting, ivParam.getParameters());
+ }
+ else if (oldEncrypting != encrypting)
+ {
+ throw new IllegalArgumentException("cannot change encrypting state without providing key.");
+ }
+ }
+ else
+ {
+ reset();
+
+ // if it;s null key is to be reused.
+ if (params != null)
+ {
+ cipher.init(encrypting, params);
+ }
+ else if (oldEncrypting != encrypting)
+ {
+ throw new IllegalArgumentException("cannot change encrypting state without providing key.");
+ }
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CBC".
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/CBC";
+ }
+
+ /**
+ * return the block size of the underlying cipher.
+ *
+ * @return the block size of the underlying cipher.
+ */
+ public int getBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ System.arraycopy(IV, 0, cbcV, 0, IV.length);
+ Arrays.fill(cbcNextV, (byte)0);
+
+ cipher.reset();
+ }
+
+ /**
+ * Do the appropriate chaining step for CBC mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ /*
+ * XOR the cbcV and the input,
+ * then encrypt the cbcV
+ */
+ for (int i = 0; i < blockSize; i++)
+ {
+ cbcV[i] ^= in[inOff + i];
+ }
+
+ int length = cipher.processBlock(cbcV, 0, out, outOff);
+
+ /*
+ * copy ciphertext to cbcV
+ */
+ System.arraycopy(out, outOff, cbcV, 0, cbcV.length);
+
+ return length;
+ }
+
+ /**
+ * Do the appropriate chaining step for CBC mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the decrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ private int decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if ((inOff + blockSize) > in.length)
+ {
+ throw new DataLengthException("input buffer too short");
+ }
+
+ System.arraycopy(in, inOff, cbcNextV, 0, blockSize);
+
+ int length = cipher.processBlock(in, inOff, out, outOff);
+
+ /*
+ * XOR the cbcV and the output
+ */
+ for (int i = 0; i < blockSize; i++)
+ {
+ out[outOff + i] ^= cbcV[i];
+ }
+
+ /*
+ * swap the back up buffer into next position
+ */
+ byte[] tmp;
+
+ tmp = cbcV;
+ cbcV = cbcNextV;
+ cbcNextV = tmp;
+
+ return length;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
new file mode 100644
index 0000000..bedc3d1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java
@@ -0,0 +1,338 @@
+package org.bouncycastle.crypto.modes;
+
+import java.io.ByteArrayOutputStream;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+import org.bouncycastle.crypto.params.AEADParameters;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+ * NIST Special Publication 800-38C.
+ * <p>
+ * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
+ */
+public class CCMBlockCipher
+ implements AEADBlockCipher
+{
+ private BlockCipher cipher;
+ private int blockSize;
+ private boolean forEncryption;
+ private byte[] nonce;
+ private byte[] associatedText;
+ private int macSize;
+ private CipherParameters keyParam;
+ private byte[] macBlock;
+ private ByteArrayOutputStream data = new ByteArrayOutputStream();
+
+ /**
+ * Basic constructor.
+ *
+ * @param c the block cipher to be used.
+ */
+ public CCMBlockCipher(BlockCipher c)
+ {
+ 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.");
+ }
+ }
+
+ /**
+ * 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, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+
+ if (params instanceof AEADParameters)
+ {
+ AEADParameters param = (AEADParameters)params;
+
+ nonce = param.getNonce();
+ associatedText = param.getAssociatedText();
+ macSize = param.getMacSize() / 8;
+ keyParam = param.getKey();
+ }
+ else if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)params;
+
+ nonce = param.getIV();
+ associatedText = null;
+ macSize = macBlock.length / 2;
+ keyParam = param.getParameters();
+ }
+ else
+ {
+ throw new IllegalArgumentException("invalid parameters passed to CCM");
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/CCM";
+ }
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ data.write(in);
+
+ return 0;
+ }
+
+ public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ data.write(in, inOff, inLen);
+
+ return 0;
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ byte[] text = data.toByteArray();
+ byte[] enc = processPacket(text, 0, text.length);
+
+ System.arraycopy(enc, 0, out, outOff, enc.length);
+
+ reset();
+
+ return enc.length;
+ }
+
+ public void reset()
+ {
+ cipher.reset();
+ data.reset();
+ }
+
+ /**
+ * 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;
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return 0;
+ }
+
+ public int getOutputSize(int len)
+ {
+ if (forEncryption)
+ {
+ return data.size() + len + macSize;
+ }
+ else
+ {
+ return data.size() + len - macSize;
+ }
+ }
+
+ public byte[] processPacket(byte[] in, int inOff, int inLen)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ if (keyParam == null)
+ {
+ throw new IllegalStateException("CCM cipher unitialized.");
+ }
+
+ BlockCipher ctrCipher = new SICBlockCipher(cipher);
+ byte[] iv = new byte[blockSize];
+ byte[] out;
+
+ iv[0] = (byte)(((15 - nonce.length) - 1) & 0x7);
+
+ System.arraycopy(nonce, 0, iv, 1, nonce.length);
+
+ ctrCipher.init(forEncryption, new ParametersWithIV(keyParam, iv));
+
+ if (forEncryption)
+ {
+ int index = inOff;
+ int outOff = 0;
+
+ out = new byte[inLen + macSize];
+
+ calculateMac(in, inOff, inLen, macBlock);
+
+ ctrCipher.processBlock(macBlock, 0, macBlock, 0); // S0
+
+ while (index < inLen - blockSize) // S1...
+ {
+ ctrCipher.processBlock(in, index, out, outOff);
+ outOff += blockSize;
+ index += blockSize;
+ }
+
+ byte[] block = new byte[blockSize];
+
+ System.arraycopy(in, index, block, 0, inLen - index);
+
+ ctrCipher.processBlock(block, 0, block, 0);
+
+ System.arraycopy(block, 0, out, outOff, inLen - index);
+
+ outOff += inLen - index;
+
+ System.arraycopy(macBlock, 0, out, outOff, out.length - outOff);
+ }
+ else
+ {
+ int index = inOff;
+ int outOff = 0;
+
+ out = new byte[inLen - macSize];
+
+ System.arraycopy(in, inOff + inLen - macSize, macBlock, 0, macSize);
+
+ ctrCipher.processBlock(macBlock, 0, macBlock, 0);
+
+ for (int i = macSize; i != macBlock.length; i++)
+ {
+ macBlock[i] = 0;
+ }
+
+ while (outOff < out.length - blockSize)
+ {
+ ctrCipher.processBlock(in, index, out, outOff);
+ outOff += blockSize;
+ index += blockSize;
+ }
+
+ byte[] block = new byte[blockSize];
+
+ System.arraycopy(in, index, block, 0, out.length - outOff);
+
+ ctrCipher.processBlock(block, 0, block, 0);
+
+ System.arraycopy(block, 0, out, outOff, out.length - outOff);
+
+ byte[] calculatedMacBlock = new byte[blockSize];
+
+ calculateMac(out, 0, out.length, calculatedMacBlock);
+
+ if (!Arrays.constantTimeAreEqual(macBlock, calculatedMacBlock))
+ {
+ throw new InvalidCipherTextException("mac check in CCM failed");
+ }
+ }
+
+ return out;
+ }
+
+ private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+ {
+ Mac cMac = new CBCBlockCipherMac(cipher, macSize * 8);
+
+ cMac.init(keyParam);
+
+ //
+ // 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)
+ {
+ b0[b0.length - count] = (byte)(q & 0xff);
+ q >>>= 8;
+ count++;
+ }
+
+ cMac.update(b0, 0, b0.length);
+
+ //
+ // process associated text
+ //
+ if (hasAssociatedText())
+ {
+ int extra;
+
+ if (associatedText.length < ((1 << 16) - (1 << 8)))
+ {
+ cMac.update((byte)(associatedText.length >> 8));
+ cMac.update((byte)associatedText.length);
+
+ extra = 2;
+ }
+ else // can't go any higher than 2^32
+ {
+ cMac.update((byte)0xff);
+ cMac.update((byte)0xfe);
+ cMac.update((byte)(associatedText.length >> 24));
+ cMac.update((byte)(associatedText.length >> 16));
+ cMac.update((byte)(associatedText.length >> 8));
+ cMac.update((byte)associatedText.length);
+
+ extra = 6;
+ }
+
+ cMac.update(associatedText, 0, associatedText.length);
+
+ extra = (extra + associatedText.length) % 16;
+ if (extra != 0)
+ {
+ for (int i = 0; i != 16 - extra; i++)
+ {
+ cMac.update((byte)0x00);
+ }
+ }
+ }
+
+ //
+ // add the text
+ //
+ cMac.update(data, dataOff, dataLen);
+
+ return cMac.doFinal(macBlock, 0);
+ }
+
+ private boolean hasAssociatedText()
+ {
+ return associatedText != null && associatedText.length != 0;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
new file mode 100644
index 0000000..0af49f4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CFBBlockCipher.java
@@ -0,0 +1,254 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+ */
+public class CFBBlockCipher
+ implements BlockCipher
+{
+ private byte[] IV;
+ private byte[] cfbV;
+ private byte[] cfbOutV;
+
+ private int blockSize;
+ private BlockCipher cipher = null;
+ private boolean encrypting;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param bitBlockSize the block size in bits (note: a multiple of 8)
+ */
+ public CFBBlockCipher(
+ BlockCipher cipher,
+ int bitBlockSize)
+ {
+ 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;
+ }
+
+ /**
+ * 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.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param encrypting if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting,
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.encrypting = encrypting;
+
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+
+ if (iv.length < IV.length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+ for (int i = 0; i < IV.length - iv.length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(iv, 0, IV, 0, IV.length);
+ }
+
+ reset();
+
+ // if null it's an IV changed only.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(true, ivParam.getParameters());
+ }
+ }
+ else
+ {
+ reset();
+
+ cipher.init(true, params);
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/CFB"
+ * and the block size in bits.
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/CFB" + (blockSize * 8);
+ }
+
+ /**
+ * return the block size we are operating at.
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int getBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ return (encrypting) ? encryptBlock(in, inOff, out, outOff) : decryptBlock(in, inOff, out, outOff);
+ }
+
+ /**
+ * Do the appropriate processing for CFB mode encryption.
+ *
+ * @param in the array containing the data to be encrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int encryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ 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);
+
+ return blockSize;
+ }
+
+ /**
+ * Do the appropriate processing for CFB mode decryption.
+ *
+ * @param in the array containing the data to be decrypted.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the encrypted data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int decryptBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ 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]);
+ }
+
+ return blockSize;
+ }
+
+ /**
+ * reset the chaining vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ System.arraycopy(IV, 0, cfbV, 0, IV.length);
+
+ cipher.reset();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java
new file mode 100644
index 0000000..b8e5b61
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java
@@ -0,0 +1,265 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to
+ * be used to produce cipher text which is the same length as the plain text.
+ */
+public class CTSBlockCipher
+ extends BufferedBlockCipher
+{
+ private int blockSize;
+
+ /**
+ * Create a buffered block cipher that uses Cipher Text Stealing
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ */
+ public CTSBlockCipher(
+ BlockCipher cipher)
+ {
+ if ((cipher instanceof OFBBlockCipher) || (cipher instanceof CFBBlockCipher))
+ {
+ throw new IllegalArgumentException("CTSBlockCipher can only accept ECB, or CBC ciphers");
+ }
+
+ this.cipher = cipher;
+
+ blockSize = cipher.getBlockSize();
+
+ buf = new byte[blockSize * 2];
+ bufOff = 0;
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public int getUpdateOutputSize(
+ int len)
+ {
+ int total = len + bufOff;
+ int leftOver = total % buf.length;
+
+ if (leftOver == 0)
+ {
+ return total - buf.length;
+ }
+
+ return total - leftOver;
+ }
+
+ /**
+ * return the size of the output buffer required for an update plus a
+ * doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public int getOutputSize(
+ int len)
+ {
+ return len + bufOff;
+ }
+
+ /**
+ * process a single byte, producing an output block if neccessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processByte(
+ byte in,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ int resultLen = 0;
+
+ if (bufOff == buf.length)
+ {
+ resultLen = cipher.processBlock(buf, 0, out, outOff);
+ System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+ bufOff = blockSize;
+ }
+
+ buf[bufOff++] = in;
+
+ return resultLen;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = getBlockSize();
+ int length = getUpdateOutputSize(len);
+
+ if (length > 0)
+ {
+ if ((outOff + length) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.length - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.processBlock(buf, 0, out, outOff);
+ System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+ bufOff = blockSize;
+
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > blockSize)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, blockSize);
+ resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+ System.arraycopy(buf, blockSize, buf, 0, blockSize);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+
+ return resultLen;
+ }
+
+ /**
+ * Process the last block in the buffer.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output.
+ * @exception IllegalStateException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if cipher text decrypts wrongly (in
+ * case the exception will never get thrown).
+ */
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException, InvalidCipherTextException
+ {
+ if (bufOff + outOff > out.length)
+ {
+ throw new DataLengthException("output buffer to small in doFinal");
+ }
+
+ int blockSize = cipher.getBlockSize();
+ int len = bufOff - blockSize;
+ byte[] block = new byte[blockSize];
+
+ if (forEncryption)
+ {
+ cipher.processBlock(buf, 0, block, 0);
+
+ if (bufOff < blockSize)
+ {
+ throw new DataLengthException("need at least one block of input for CTS");
+ }
+
+ for (int i = bufOff; i != buf.length; i++)
+ {
+ buf[i] = block[i - blockSize];
+ }
+
+ for (int i = blockSize; i != bufOff; i++)
+ {
+ buf[i] ^= block[i - blockSize];
+ }
+
+ if (cipher instanceof CBCBlockCipher)
+ {
+ BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+
+ c.processBlock(buf, blockSize, out, outOff);
+ }
+ else
+ {
+ cipher.processBlock(buf, blockSize, out, outOff);
+ }
+
+ System.arraycopy(block, 0, out, outOff + blockSize, len);
+ }
+ else
+ {
+ byte[] lastBlock = new byte[blockSize];
+
+ if (cipher instanceof CBCBlockCipher)
+ {
+ BlockCipher c = ((CBCBlockCipher)cipher).getUnderlyingCipher();
+
+ c.processBlock(buf, 0, block, 0);
+ }
+ else
+ {
+ cipher.processBlock(buf, 0, block, 0);
+ }
+
+ for (int i = blockSize; i != bufOff; i++)
+ {
+ lastBlock[i - blockSize] = (byte)(block[i - blockSize] ^ buf[i]);
+ }
+
+ System.arraycopy(buf, blockSize, block, 0, len);
+
+ cipher.processBlock(block, 0, out, outOff);
+ System.arraycopy(lastBlock, 0, out, outOff + blockSize, len);
+ }
+
+ int offset = bufOff;
+
+ reset();
+
+ return offset;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
new file mode 100644
index 0000000..7c98efa
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java
@@ -0,0 +1,421 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.modes.gcm.GCMMultiplier;
+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;
+
+/**
+ * Implements the Galois/Counter mode (GCM) detailed in
+ * NIST Special Publication 800-38D.
+ */
+public class GCMBlockCipher
+ implements AEADBlockCipher
+{
+ private static final int BLOCK_SIZE = 16;
+ private static final byte[] ZEROES = new byte[BLOCK_SIZE];
+
+ // not final due to a compiler bug
+ private BlockCipher cipher;
+ private GCMMultiplier multiplier;
+
+ // These fields are set by init and not modified by processing
+ private boolean forEncryption;
+ private int macSize;
+ private byte[] nonce;
+ private byte[] A;
+ private byte[] H;
+ private byte[] initS;
+ private byte[] J0;
+
+ // These fields are modified during processing
+ private byte[] bufBlock;
+ private byte[] macBlock;
+ private byte[] S;
+ private byte[] counter;
+ private int bufOff;
+ private long totalLength;
+
+ public GCMBlockCipher(BlockCipher c)
+ {
+ this(c, null);
+ }
+
+ public GCMBlockCipher(BlockCipher c, GCMMultiplier m)
+ {
+ if (c.getBlockSize() != BLOCK_SIZE)
+ {
+ throw new IllegalArgumentException(
+ "cipher required with a block size of " + BLOCK_SIZE + ".");
+ }
+
+ if (m == null)
+ {
+ // TODO Consider a static property specifying default multiplier
+ m = new Tables8kGCMMultiplier();
+ }
+
+ this.cipher = c;
+ this.multiplier = m;
+ }
+
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher;
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/GCM";
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+ this.macBlock = null;
+
+ KeyParameter keyParam;
+
+ if (params instanceof AEADParameters)
+ {
+ AEADParameters param = (AEADParameters)params;
+
+ nonce = param.getNonce();
+ A = param.getAssociatedText();
+
+ int macSizeBits = param.getMacSize();
+ if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0)
+ {
+ throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits);
+ }
+
+ macSize = macSizeBits / 8;
+ keyParam = param.getKey();
+ }
+ else if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV param = (ParametersWithIV)params;
+
+ nonce = param.getIV();
+ A = null;
+ macSize = 16;
+ keyParam = (KeyParameter)param.getParameters();
+ }
+ else
+ {
+ throw new IllegalArgumentException("invalid parameters passed to GCM");
+ }
+
+ int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize);
+ this.bufBlock = new byte[bufLength];
+
+ if (nonce == null || nonce.length < 1)
+ {
+ throw new IllegalArgumentException("IV must be at least 1 byte");
+ }
+
+ if (A == null)
+ {
+ // Avoid lots of null checks
+ A = new byte[0];
+ }
+
+ // Cipher always used in forward mode
+ // if keyParam is null we're reusing the last key.
+ if (keyParam != null)
+ {
+ cipher.init(true, keyParam);
+ }
+
+ // TODO This should be configurable by init parameters
+ // (but must be 16 if nonce length not 12) (BLOCK_SIZE?)
+// this.tagLength = 16;
+
+ this.H = new byte[BLOCK_SIZE];
+ cipher.processBlock(ZEROES, 0, H, 0);
+ multiplier.init(H);
+
+ this.initS = gHASH(A);
+
+ if (nonce.length == 12)
+ {
+ this.J0 = new byte[16];
+ System.arraycopy(nonce, 0, J0, 0, nonce.length);
+ this.J0[15] = 0x01;
+ }
+ else
+ {
+ this.J0 = gHASH(nonce);
+ byte[] X = new byte[16];
+ packLength((long)nonce.length * 8, X, 8);
+ xor(this.J0, X);
+ multiplier.multiplyH(this.J0);
+ }
+
+ this.S = Arrays.clone(initS);
+ this.counter = Arrays.clone(J0);
+ this.bufOff = 0;
+ this.totalLength = 0;
+ }
+
+ public byte[] getMac()
+ {
+ return Arrays.clone(macBlock);
+ }
+
+ public int getOutputSize(int len)
+ {
+ if (forEncryption)
+ {
+ return len + bufOff + macSize;
+ }
+
+ return len + bufOff - macSize;
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return ((len + bufOff) / BLOCK_SIZE) * BLOCK_SIZE;
+ }
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException
+ {
+ return process(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException
+ {
+ int resultLen = 0;
+
+ for (int i = 0; i != len; i++)
+ {
+// resultLen += process(in[inOff + i], out, outOff + resultLen);
+ bufBlock[bufOff++] = in[inOff + i];
+
+ if (bufOff == bufBlock.length)
+ {
+ gCTRBlock(bufBlock, BLOCK_SIZE, out, outOff + resultLen);
+ if (!forEncryption)
+ {
+ System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize);
+ }
+// bufOff = 0;
+ bufOff = bufBlock.length - BLOCK_SIZE;
+// return bufBlock.Length;
+ resultLen += BLOCK_SIZE;
+ }
+ }
+
+ return resultLen;
+ }
+
+ private int process(byte in, byte[] out, int outOff)
+ throws DataLengthException
+ {
+ bufBlock[bufOff++] = in;
+
+ if (bufOff == bufBlock.length)
+ {
+ gCTRBlock(bufBlock, BLOCK_SIZE, out, outOff);
+ if (!forEncryption)
+ {
+ System.arraycopy(bufBlock, BLOCK_SIZE, bufBlock, 0, macSize);
+ }
+// bufOff = 0;
+ bufOff = bufBlock.length - BLOCK_SIZE;
+// return bufBlock.length;
+ return BLOCK_SIZE;
+ }
+
+ return 0;
+ }
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException
+ {
+ int extra = bufOff;
+ if (!forEncryption)
+ {
+ if (extra < macSize)
+ {
+ throw new InvalidCipherTextException("data too short");
+ }
+ extra -= macSize;
+ }
+
+ if (extra > 0)
+ {
+ byte[] tmp = new byte[BLOCK_SIZE];
+ System.arraycopy(bufBlock, 0, tmp, 0, extra);
+ gCTRBlock(tmp, extra, out, outOff);
+ }
+
+ // Final gHASH
+ byte[] X = new byte[16];
+ packLength((long)A.length * 8, X, 0);
+ packLength(totalLength * 8, X, 8);
+
+ xor(S, X);
+ multiplier.multiplyH(S);
+
+ // 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);
+
+ int resultLen = extra;
+
+ // We place into macBlock our calculated value for T
+ this.macBlock = new byte[macSize];
+ System.arraycopy(tag, 0, macBlock, 0, macSize);
+
+ if (forEncryption)
+ {
+ // Append T to the message
+ System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize);
+ resultLen += macSize;
+ }
+ else
+ {
+ // Retrieve the T value from the message and compare to calculated one
+ byte[] msgMac = new byte[macSize];
+ System.arraycopy(bufBlock, extra, msgMac, 0, macSize);
+ if (!Arrays.constantTimeAreEqual(this.macBlock, msgMac))
+ {
+ throw new InvalidCipherTextException("mac check in GCM failed");
+ }
+ }
+
+ reset(false);
+
+ return resultLen;
+ }
+
+ public void reset()
+ {
+ reset(true);
+ }
+
+ private void reset(
+ boolean clearMac)
+ {
+ S = Arrays.clone(initS);
+ counter = Arrays.clone(J0);
+ bufOff = 0;
+ totalLength = 0;
+
+ if (bufBlock != null)
+ {
+ Arrays.fill(bufBlock, (byte)0);
+ }
+
+ if (clearMac)
+ {
+ macBlock = null;
+ }
+
+ cipher.reset();
+ }
+
+ private void gCTRBlock(byte[] buf, int bufCount, byte[] out, int outOff)
+ {
+// inc(counter);
+ for (int i = 15; i >= 12; --i)
+ {
+ byte b = (byte)((counter[i] + 1) & 0xff);
+ counter[i] = b;
+
+ if (b != 0)
+ {
+ break;
+ }
+ }
+
+ byte[] tmp = new byte[BLOCK_SIZE];
+ cipher.processBlock(counter, 0, tmp, 0);
+
+ byte[] hashBytes;
+ if (forEncryption)
+ {
+ System.arraycopy(ZEROES, bufCount, tmp, bufCount, BLOCK_SIZE - bufCount);
+ hashBytes = tmp;
+ }
+ else
+ {
+ hashBytes = buf;
+ }
+
+ for (int i = bufCount - 1; i >= 0; --i)
+ {
+ tmp[i] ^= buf[i];
+ out[outOff + i] = tmp[i];
+ }
+
+// gHASHBlock(hashBytes);
+ xor(S, hashBytes);
+ multiplier.multiplyH(S);
+
+ totalLength += bufCount;
+ }
+
+ private byte[] gHASH(byte[] b)
+ {
+ byte[] Y = new byte[16];
+
+ for (int pos = 0; pos < b.length; pos += 16)
+ {
+ byte[] X = new byte[16];
+ int num = Math.min(b.length - pos, 16);
+ System.arraycopy(b, pos, X, 0, num);
+ xor(Y, X);
+ multiplier.multiplyH(Y);
+ }
+
+ return Y;
+ }
+
+// private void gHASHBlock(byte[] block)
+// {
+// xor(S, block);
+// multiplier.multiplyH(S);
+// }
+
+// private static void inc(byte[] block)
+// {
+// for (int i = 15; i >= 12; --i)
+// {
+// byte b = (byte)((block[i] + 1) & 0xff);
+// block[i] = b;
+//
+// if (b != 0)
+// {
+// break;
+// }
+// }
+// }
+
+ private static void xor(byte[] block, byte[] val)
+ {
+ for (int i = 15; i >= 0; --i)
+ {
+ block[i] ^= val[i];
+ }
+ }
+
+ private static void packLength(long count, byte[] bs, int off)
+ {
+ Pack.intToBigEndian((int)(count >>> 32), bs, off);
+ Pack.intToBigEndian((int)count, bs, off + 4);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
new file mode 100644
index 0000000..728a2e7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/OFBBlockCipher.java
@@ -0,0 +1,183 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
+ */
+public class OFBBlockCipher
+ implements BlockCipher
+{
+ private byte[] IV;
+ private byte[] ofbV;
+ private byte[] ofbOutV;
+
+ private final int blockSize;
+ private final BlockCipher cipher;
+
+ /**
+ * Basic constructor.
+ *
+ * @param cipher the block cipher to be used as the basis of the
+ * feedback mode.
+ * @param blockSize the block size in bits (note: a multiple of 8)
+ */
+ public OFBBlockCipher(
+ BlockCipher cipher,
+ int blockSize)
+ {
+ this.cipher = cipher;
+ this.blockSize = blockSize / 8;
+
+ this.IV = new byte[cipher.getBlockSize()];
+ this.ofbV = new byte[cipher.getBlockSize()];
+ 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.
+ * An IV which is too short is handled in FIPS compliant fashion.
+ *
+ * @param encrypting if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean encrypting, //ignored by this OFB mode
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+
+ if (iv.length < IV.length)
+ {
+ // prepend the supplied IV with zeros (per FIPS PUB 81)
+ System.arraycopy(iv, 0, IV, IV.length - iv.length, iv.length);
+ for (int i = 0; i < IV.length - iv.length; i++)
+ {
+ IV[i] = 0;
+ }
+ }
+ else
+ {
+ System.arraycopy(iv, 0, IV, 0, IV.length);
+ }
+
+ reset();
+
+ // if null it's an IV changed only.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(true, ivParam.getParameters());
+ }
+ }
+ else
+ {
+ reset();
+
+ cipher.init(true, params);
+ }
+ }
+
+ /**
+ * return the algorithm name and mode.
+ *
+ * @return the name of the underlying algorithm followed by "/OFB"
+ * and the block size in bits
+ */
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/OFB" + (blockSize * 8);
+ }
+
+
+ /**
+ * return the block size we are operating at (in bytes).
+ *
+ * @return the block size we are operating at (in bytes).
+ */
+ public int getBlockSize()
+ {
+ return blockSize;
+ }
+
+ /**
+ * Process one block of input from the array in and write it to
+ * the out array.
+ *
+ * @param in the array containing the input data.
+ * @param inOff offset into the in array the data starts at.
+ * @param out the array the output data will be copied into.
+ * @param outOff the offset into the out array the output will start at.
+ * @exception DataLengthException if there isn't enough data in in, or
+ * space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ * @return the number of bytes processed and produced.
+ */
+ public int processBlock(
+ byte[] in,
+ int inOff,
+ byte[] out,
+ 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);
+
+ return blockSize;
+ }
+
+ /**
+ * reset the feedback vector back to the IV and reset the underlying
+ * cipher.
+ */
+ public void reset()
+ {
+ System.arraycopy(IV, 0, ofbV, 0, IV.length);
+
+ cipher.reset();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
new file mode 100644
index 0000000..af9f18d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java
@@ -0,0 +1,124 @@
+package org.bouncycastle.crypto.modes;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+/**
+ * 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
+{
+ private final BlockCipher cipher;
+ private final int blockSize;
+
+ private byte[] IV;
+ private byte[] counter;
+ private byte[] counterOut;
+
+
+ /**
+ * Basic constructor.
+ *
+ * @param c the block cipher to be used.
+ */
+ public SICBlockCipher(BlockCipher c)
+ {
+ this.cipher = c;
+ this.blockSize = cipher.getBlockSize();
+ this.IV = new byte[blockSize];
+ this.counter = new byte[blockSize];
+ this.counterOut = new byte[blockSize];
+ }
+
+
+ /**
+ * 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)
+ throws IllegalArgumentException
+ {
+ if (params instanceof ParametersWithIV)
+ {
+ ParametersWithIV ivParam = (ParametersWithIV)params;
+ byte[] iv = ivParam.getIV();
+ System.arraycopy(iv, 0, IV, 0, IV.length);
+
+ reset();
+
+ // if null it's an IV changed only.
+ if (ivParam.getParameters() != null)
+ {
+ cipher.init(true, ivParam.getParameters());
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("SIC mode requires ParametersWithIV");
+ }
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getAlgorithmName() + "/SIC";
+ }
+
+ public int getBlockSize()
+ {
+ return cipher.getBlockSize();
+ }
+
+
+ public int processBlock(byte[] in, int inOff, byte[] out, int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ cipher.processBlock(counter, 0, counterOut, 0);
+
+ //
+ // XOR the counterOut with the plaintext producing the cipher text
+ //
+ for (int i = 0; i < counterOut.length; i++)
+ {
+ out[outOff + i] = (byte)(counterOut[i] ^ in[inOff + i]);
+ }
+
+ int carry = 1;
+
+ for (int i = counter.length - 1; i >= 0; i--)
+ {
+ int x = (counter[i] & 0xff) + carry;
+
+ if (x > 0xff)
+ {
+ carry = 1;
+ }
+ else
+ {
+ carry = 0;
+ }
+
+ counter[i] = (byte)x;
+ }
+
+ return counter.length;
+ }
+
+
+ public void reset()
+ {
+ System.arraycopy(IV, 0, counter, 0, counter.length);
+ cipher.reset();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java
new file mode 100644
index 0000000..f52f610
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMMultiplier.java
@@ -0,0 +1,7 @@
+package org.bouncycastle.crypto.modes.gcm;
+
+public interface GCMMultiplier
+{
+ void init(byte[] H);
+ void multiplyH(byte[] x);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
new file mode 100644
index 0000000..ce02be4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/GCMUtil.java
@@ -0,0 +1,155 @@
+package org.bouncycastle.crypto.modes.gcm;
+
+import org.bouncycastle.crypto.util.Pack;
+import org.bouncycastle.util.Arrays;
+
+abstract class GCMUtil
+{
+ static byte[] oneAsBytes()
+ {
+ byte[] tmp = new byte[16];
+ tmp[0] = (byte)0x80;
+ return tmp;
+ }
+
+ static int[] oneAsInts()
+ {
+ int[] tmp = new int[4];
+ tmp[0] = 0x80000000;
+ return tmp;
+ }
+
+ static int[] asInts(byte[] bs)
+ {
+ int[] us = new int[4];
+ us[0] = Pack.bigEndianToInt(bs, 0);
+ us[1] = Pack.bigEndianToInt(bs, 4);
+ us[2] = Pack.bigEndianToInt(bs, 8);
+ us[3] = Pack.bigEndianToInt(bs, 12);
+ return us;
+ }
+
+ 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, ... };
+// GCMUtil.xor(v, R);
+ tmp[0] ^= (byte)0xe1;
+ }
+ }
+ }
+
+ System.arraycopy(c, 0, block, 0, 16);
+ }
+
+ // P is the value with only bit i=1 set
+ static void multiplyP(int[] x)
+ {
+ boolean lsb = (x[3] & 1) != 0;
+ shiftRight(x);
+ if (lsb)
+ {
+ // R = new int[]{ 0xe1000000, 0, 0, 0 };
+// xor(v, R);
+ x[0] ^= 0xe1000000;
+ }
+ }
+
+ static void multiplyP8(int[] x)
+ {
+// for (int i = 8; i != 0; --i)
+// {
+// multiplyP(x);
+// }
+
+ int lsw = x[3];
+ shiftRightN(x, 8);
+ for (int i = 7; i >= 0; --i)
+ {
+ if ((lsw & (1 << i)) != 0)
+ {
+ x[0] ^= (0xe1000000 >>> (7 - i));
+ }
+ }
+ }
+
+ 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;
+ }
+ }
+
+ static void shiftRight(int[] block)
+ {
+ int i = 0;
+ int bit = 0;
+ for (;;)
+ {
+ int b = block[i];
+ block[i] = (b >>> 1) | bit;
+ if (++i == 4)
+ {
+ break;
+ }
+ bit = b << 31;
+ }
+ }
+
+ static void shiftRightN(int[] block, int n)
+ {
+ int i = 0;
+ int bits = 0;
+ for (;;)
+ {
+ int b = block[i];
+ block[i] = (b >>> n) | bits;
+ if (++i == 4)
+ {
+ break;
+ }
+ bits = b << (32 - n);
+ }
+ }
+
+ static void xor(byte[] block, byte[] val)
+ {
+ for (int i = 15; i >= 0; --i)
+ {
+ block[i] ^= val[i];
+ }
+ }
+
+ static void xor(int[] block, int[] val)
+ {
+ for (int i = 3; i >= 0; --i)
+ {
+ block[i] ^= val[i];
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
new file mode 100644
index 0000000..9d21cf0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/modes/gcm/Tables8kGCMMultiplier.java
@@ -0,0 +1,99 @@
+package org.bouncycastle.crypto.modes.gcm;
+
+import org.bouncycastle.crypto.util.Pack;
+
+public class Tables8kGCMMultiplier implements GCMMultiplier
+{
+ private final int[][][] M = new int[32][16][];
+
+ public void init(byte[] H)
+ {
+ M[0][0] = new int[4];
+ M[1][0] = new int[4];
+ M[1][8] = GCMUtil.asInts(H);
+
+ for (int j = 4; j >= 1; j >>= 1)
+ {
+ int[] tmp = new int[4];
+ System.arraycopy(M[1][j + j], 0, tmp, 0, 4);
+
+ GCMUtil.multiplyP(tmp);
+ M[1][j] = tmp;
+ }
+
+ {
+ int[] tmp = new int[4];
+ System.arraycopy(M[1][1], 0, tmp, 0, 4);
+
+ GCMUtil.multiplyP(tmp);
+ M[0][8] = tmp;
+ }
+
+ for (int j = 4; j >= 1; j >>= 1)
+ {
+ int[] tmp = new int[4];
+ System.arraycopy(M[0][j + j], 0, tmp, 0, 4);
+
+ GCMUtil.multiplyP(tmp);
+ M[0][j] = tmp;
+ }
+
+ int i = 0;
+ for (;;)
+ {
+ for (int j = 2; j < 16; j += j)
+ {
+ for (int k = 1; k < j; ++k)
+ {
+ int[] tmp = new int[4];
+ System.arraycopy(M[i][j], 0, tmp, 0, 4);
+
+ GCMUtil.xor(tmp, M[i][k]);
+ M[i][j + k] = tmp;
+ }
+ }
+
+ if (++i == 32)
+ {
+ return;
+ }
+
+ if (i > 1)
+ {
+ M[i][0] = new int[4];
+ for(int j = 8; j > 0; j >>= 1)
+ {
+ int[] tmp = new int[4];
+ System.arraycopy(M[i - 2][j], 0, tmp, 0, 4);
+
+ GCMUtil.multiplyP8(tmp);
+ M[i][j] = tmp;
+ }
+ }
+ }
+ }
+
+ public void multiplyH(byte[] x)
+ {
+// assert x.Length == 16;
+
+ int[] z = new int[4];
+ for (int i = 15; i >= 0; --i)
+ {
+// GCMUtil.xor(z, M[i + i][x[i] & 0x0f]);
+ int[] m = M[i + i][x[i] & 0x0f];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+// GCMUtil.xor(z, M[i + i + 1][(x[i] & 0xf0) >>> 4]);
+ m = M[i + i + 1][(x[i] & 0xf0) >>> 4];
+ z[0] ^= m[0];
+ z[1] ^= m[1];
+ z[2] ^= m[2];
+ z[3] ^= m[3];
+ }
+
+ Pack.intToBigEndian(z, x, 0);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/BlockCipherPadding.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/BlockCipherPadding.java
new file mode 100644
index 0000000..7c4f0ae
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/BlockCipherPadding.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * Block cipher padders are expected to conform to this interface
+ */
+public interface BlockCipherPadding
+{
+ /**
+ * Initialise the padder.
+ *
+ * @param random the source of randomness for the padding, if required.
+ */
+ public void init(SecureRandom random)
+ throws IllegalArgumentException;
+
+ /**
+ * Return the name of the algorithm the cipher implements.
+ *
+ * @return the name of the algorithm the cipher implements.
+ */
+ public String getPaddingName();
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ * <p>
+ * Note: this assumes that the last block of plain text is always
+ * passed to it inside in. i.e. if inOff is zero, indicating the
+ * entire block is to be overwritten with padding the value of in
+ * should be the same as the last block of plain text. The reason
+ * for this is that some modes such as "trailing bit compliment"
+ * base the padding on the last byte of plain text.
+ * </p>
+ */
+ public int addPadding(byte[] in, int inOff);
+
+ /**
+ * return the number of pad bytes present in the block.
+ * @exception InvalidCipherTextException if the padding is badly formed
+ * or invalid.
+ */
+ public int padCount(byte[] in)
+ throws InvalidCipherTextException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java
new file mode 100644
index 0000000..63e29d8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO10126d2Padding.java
@@ -0,0 +1,79 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds ISO10126-2 padding to a block.
+ */
+public class ISO10126d2Padding
+ implements BlockCipherPadding
+{
+ SecureRandom random;
+
+ /**
+ * Initialise the padder.
+ *
+ * @param random a SecureRandom if available.
+ */
+ public void init(SecureRandom random)
+ throws IllegalArgumentException
+ {
+ if (random != null)
+ {
+ this.random = random;
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ }
+ }
+
+ /**
+ * Return the name of the algorithm the padder implements.
+ *
+ * @return the name of the algorithm the padder implements.
+ */
+ public String getPaddingName()
+ {
+ return "ISO10126-2";
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int addPadding(
+ byte[] in,
+ int inOff)
+ {
+ byte code = (byte)(in.length - inOff);
+
+ while (inOff < (in.length - 1))
+ {
+ in[inOff] = (byte)random.nextInt();
+ inOff++;
+ }
+
+ in[inOff] = code;
+
+ return code;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int padCount(byte[] in)
+ throws InvalidCipherTextException
+ {
+ int count = in[in.length - 1] & 0xff;
+
+ if (count > in.length)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return count;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java
new file mode 100644
index 0000000..54c31a9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ISO7816d4Padding.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds the padding according to the scheme referenced in
+ * ISO 7814-4 - scheme 2 from ISO 9797-1. The first byte is 0x80, rest is 0x00
+ */
+public class ISO7816d4Padding
+ implements BlockCipherPadding
+{
+ /**
+ * Initialise the padder.
+ *
+ * @param random - a SecureRandom if available.
+ */
+ public void init(SecureRandom random)
+ throws IllegalArgumentException
+ {
+ // nothing to do.
+ }
+
+ /**
+ * Return the name of the algorithm the padder implements.
+ *
+ * @return the name of the algorithm the padder implements.
+ */
+ public String getPaddingName()
+ {
+ return "ISO7816-4";
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int addPadding(
+ byte[] in,
+ int inOff)
+ {
+ int added = (in.length - inOff);
+
+ in [inOff]= (byte) 0x80;
+ inOff ++;
+
+ while (inOff < in.length)
+ {
+ in[inOff] = (byte) 0;
+ inOff++;
+ }
+
+ return added;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int padCount(byte[] in)
+ throws InvalidCipherTextException
+ {
+ int count = in.length - 1;
+
+ while (count > 0 && in[count] == 0)
+ {
+ count--;
+ }
+
+ if (in[count] != (byte)0x80)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return in.length - count;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java
new file mode 100644
index 0000000..93b149f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PKCS7Padding.java
@@ -0,0 +1,76 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds PKCS7/PKCS5 padding to a block.
+ */
+public class PKCS7Padding
+ implements BlockCipherPadding
+{
+ /**
+ * Initialise the padder.
+ *
+ * @param random - a SecureRandom if available.
+ */
+ public void init(SecureRandom random)
+ throws IllegalArgumentException
+ {
+ // nothing to do.
+ }
+
+ /**
+ * Return the name of the algorithm the padder implements.
+ *
+ * @return the name of the algorithm the padder implements.
+ */
+ public String getPaddingName()
+ {
+ return "PKCS7";
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int addPadding(
+ byte[] in,
+ int inOff)
+ {
+ byte code = (byte)(in.length - inOff);
+
+ while (inOff < in.length)
+ {
+ in[inOff] = code;
+ inOff++;
+ }
+
+ return code;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int padCount(byte[] in)
+ throws InvalidCipherTextException
+ {
+ int count = in[in.length - 1] & 0xff;
+
+ if (count > in.length || count == 0)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ for (int i = 1; i <= count; i++)
+ {
+ if (in[in.length - i] != count)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+ }
+
+ return count;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
new file mode 100644
index 0000000..ec412b9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java
@@ -0,0 +1,298 @@
+package org.bouncycastle.crypto.paddings;
+
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+/**
+ * A wrapper class that allows block ciphers to be used to process data in
+ * a piecemeal fashion with padding. The PaddedBufferedBlockCipher
+ * outputs a block only when the buffer is full and more data is being added,
+ * or on a doFinal (unless the current block in the buffer is a pad block).
+ * The default padding mechanism used is the one outlined in PKCS5/PKCS7.
+ */
+public class PaddedBufferedBlockCipher
+ extends BufferedBlockCipher
+{
+ BlockCipherPadding padding;
+
+ /**
+ * Create a buffered block cipher with the desired padding.
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ * @param padding the padding type.
+ */
+ public PaddedBufferedBlockCipher(
+ BlockCipher cipher,
+ BlockCipherPadding padding)
+ {
+ this.cipher = cipher;
+ this.padding = padding;
+
+ buf = new byte[cipher.getBlockSize()];
+ bufOff = 0;
+ }
+
+ /**
+ * Create a buffered block cipher PKCS7 padding
+ *
+ * @param cipher the underlying block cipher this buffering object wraps.
+ */
+ public PaddedBufferedBlockCipher(
+ BlockCipher cipher)
+ {
+ this(cipher, new PKCS7Padding());
+ }
+
+ /**
+ * initialise the cipher.
+ *
+ * @param forEncryption if true the cipher is initialised for
+ * encryption, if false for decryption.
+ * @param params the key and other data required by the cipher.
+ * @exception IllegalArgumentException if the params argument is
+ * inappropriate.
+ */
+ public void init(
+ boolean forEncryption,
+ CipherParameters params)
+ throws IllegalArgumentException
+ {
+ this.forEncryption = forEncryption;
+
+ reset();
+
+ if (params instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom p = (ParametersWithRandom)params;
+
+ padding.init(p.getRandom());
+
+ cipher.init(forEncryption, p.getParameters());
+ }
+ else
+ {
+ padding.init(null);
+
+ cipher.init(forEncryption, params);
+ }
+ }
+
+ /**
+ * return the minimum size of the output buffer required for an update
+ * plus a doFinal with an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update and doFinal
+ * with len bytes of input.
+ */
+ public int getOutputSize(
+ int len)
+ {
+ int total = len + bufOff;
+ int leftOver = total % buf.length;
+
+ if (leftOver == 0)
+ {
+ if (forEncryption)
+ {
+ return total + buf.length;
+ }
+
+ return total;
+ }
+
+ return total - leftOver + buf.length;
+ }
+
+ /**
+ * return the size of the output buffer required for an update
+ * an input of len bytes.
+ *
+ * @param len the length of the input.
+ * @return the space required to accommodate a call to update
+ * with len bytes of input.
+ */
+ public int getUpdateOutputSize(
+ int len)
+ {
+ int total = len + bufOff;
+ int leftOver = total % buf.length;
+
+ if (leftOver == 0)
+ {
+ return total - buf.length;
+ }
+
+ return total - leftOver;
+ }
+
+ /**
+ * process a single byte, producing an output block if neccessary.
+ *
+ * @param in the input byte.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processByte(
+ byte in,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ int resultLen = 0;
+
+ if (bufOff == buf.length)
+ {
+ resultLen = cipher.processBlock(buf, 0, out, outOff);
+ bufOff = 0;
+ }
+
+ buf[bufOff++] = in;
+
+ return resultLen;
+ }
+
+ /**
+ * process an array of bytes, producing output if necessary.
+ *
+ * @param in the input byte array.
+ * @param inOff the offset at which the input data starts.
+ * @param len the number of bytes to be copied out of the input array.
+ * @param out the space for any output that might be produced.
+ * @param outOff the offset from which the output will be copied.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there isn't enough space in out.
+ * @exception IllegalStateException if the cipher isn't initialised.
+ */
+ public int processBytes(
+ byte[] in,
+ int inOff,
+ int len,
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException
+ {
+ if (len < 0)
+ {
+ throw new IllegalArgumentException("Can't have a negative input length!");
+ }
+
+ int blockSize = getBlockSize();
+ int length = getUpdateOutputSize(len);
+
+ if (length > 0)
+ {
+ if ((outOff + length) > out.length)
+ {
+ throw new DataLengthException("output buffer too short");
+ }
+ }
+
+ int resultLen = 0;
+ int gapLen = buf.length - bufOff;
+
+ if (len > gapLen)
+ {
+ System.arraycopy(in, inOff, buf, bufOff, gapLen);
+
+ resultLen += cipher.processBlock(buf, 0, out, outOff);
+
+ bufOff = 0;
+ len -= gapLen;
+ inOff += gapLen;
+
+ while (len > buf.length)
+ {
+ resultLen += cipher.processBlock(in, inOff, out, outOff + resultLen);
+
+ len -= blockSize;
+ inOff += blockSize;
+ }
+ }
+
+ System.arraycopy(in, inOff, buf, bufOff, len);
+
+ bufOff += len;
+
+ return resultLen;
+ }
+
+ /**
+ * Process the last block in the buffer. If the buffer is currently
+ * full and padding needs to be added a call to doFinal will produce
+ * 2 * getBlockSize() bytes.
+ *
+ * @param out the array the block currently being held is copied into.
+ * @param outOff the offset at which the copying starts.
+ * @return the number of output bytes copied to out.
+ * @exception DataLengthException if there is insufficient space in out for
+ * the output or we are decrypting and the input is not block size aligned.
+ * @exception IllegalStateException if the underlying cipher is not
+ * initialised.
+ * @exception InvalidCipherTextException if padding is expected and not found.
+ */
+ public int doFinal(
+ byte[] out,
+ int outOff)
+ throws DataLengthException, IllegalStateException, InvalidCipherTextException
+ {
+ int blockSize = cipher.getBlockSize();
+ int resultLen = 0;
+
+ if (forEncryption)
+ {
+ if (bufOff == blockSize)
+ {
+ if ((outOff + 2 * blockSize) > out.length)
+ {
+ reset();
+
+ throw new DataLengthException("output buffer too short");
+ }
+
+ resultLen = cipher.processBlock(buf, 0, out, outOff);
+ bufOff = 0;
+ }
+
+ padding.addPadding(buf, bufOff);
+
+ resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen);
+
+ reset();
+ }
+ else
+ {
+ if (bufOff == blockSize)
+ {
+ resultLen = cipher.processBlock(buf, 0, buf, 0);
+ bufOff = 0;
+ }
+ else
+ {
+ reset();
+
+ throw new DataLengthException("last block incomplete in decryption");
+ }
+
+ try
+ {
+ resultLen -= padding.padCount(buf);
+
+ System.arraycopy(buf, 0, out, outOff, resultLen);
+ }
+ finally
+ {
+ reset();
+ }
+ }
+
+ return resultLen;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/TBCPadding.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/TBCPadding.java
new file mode 100644
index 0000000..219912f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/TBCPadding.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds Trailing-Bit-Compliment padding to a block.
+ * <p>
+ * This padding pads the block out with the compliment of the last bit
+ * of the plain text.
+ * </p>
+ */
+public class TBCPadding
+ implements BlockCipherPadding
+{
+ /**
+ * Initialise the padder.
+ *
+ * @param random - a SecureRandom if available.
+ */
+ public void init(SecureRandom random)
+ throws IllegalArgumentException
+ {
+ // nothing to do.
+ }
+
+ /**
+ * Return the name of the algorithm the padder implements.
+ *
+ * @return the name of the algorithm the padder implements.
+ */
+ public String getPaddingName()
+ {
+ return "TBC";
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ * <p>
+ * Note: this assumes that the last block of plain text is always
+ * passed to it inside in. i.e. if inOff is zero, indicating the
+ * entire block is to be overwritten with padding the value of in
+ * should be the same as the last block of plain text.
+ * </p>
+ */
+ public int addPadding(
+ byte[] in,
+ int inOff)
+ {
+ int count = in.length - inOff;
+ byte code;
+
+ if (inOff > 0)
+ {
+ code = (byte)((in[inOff - 1] & 0x01) == 0 ? 0xff : 0x00);
+ }
+ else
+ {
+ code = (byte)((in[in.length - 1] & 0x01) == 0 ? 0xff : 0x00);
+ }
+
+ while (inOff < in.length)
+ {
+ in[inOff] = code;
+ inOff++;
+ }
+
+ return count;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int padCount(byte[] in)
+ throws InvalidCipherTextException
+ {
+ byte code = in[in.length - 1];
+
+ int index = in.length - 1;
+ while (index > 0 && in[index - 1] == code)
+ {
+ index--;
+ }
+
+ return in.length - index;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/X923Padding.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/X923Padding.java
new file mode 100644
index 0000000..d4d34aa
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/X923Padding.java
@@ -0,0 +1,80 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds X9.23 padding to a block - if a SecureRandom is
+ * passed in random padding is assumed, otherwise padding with zeros is used.
+ */
+public class X923Padding
+ implements BlockCipherPadding
+{
+ SecureRandom random = null;
+
+ /**
+ * Initialise the padder.
+ *
+ * @param random a SecureRandom if one is available.
+ */
+ public void init(SecureRandom random)
+ throws IllegalArgumentException
+ {
+ this.random = random;
+ }
+
+ /**
+ * Return the name of the algorithm the padder implements.
+ *
+ * @return the name of the algorithm the padder implements.
+ */
+ public String getPaddingName()
+ {
+ return "X9.23";
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int addPadding(
+ byte[] in,
+ int inOff)
+ {
+ byte code = (byte)(in.length - inOff);
+
+ while (inOff < in.length - 1)
+ {
+ if (random == null)
+ {
+ in[inOff] = 0;
+ }
+ else
+ {
+ in[inOff] = (byte)random.nextInt();
+ }
+ inOff++;
+ }
+
+ in[inOff] = code;
+
+ return code;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int padCount(byte[] in)
+ throws InvalidCipherTextException
+ {
+ int count = in[in.length - 1] & 0xff;
+
+ if (count > in.length)
+ {
+ throw new InvalidCipherTextException("pad block corrupted");
+ }
+
+ return count;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ZeroBytePadding.java b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ZeroBytePadding.java
new file mode 100644
index 0000000..c756028
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/paddings/ZeroBytePadding.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.crypto.paddings;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+/**
+ * A padder that adds NULL byte padding to a block.
+ */
+public class ZeroBytePadding
+ implements BlockCipherPadding
+{
+ /**
+ * Initialise the padder.
+ *
+ * @param random - a SecureRandom if available.
+ */
+ public void init(SecureRandom random)
+ throws IllegalArgumentException
+ {
+ // nothing to do.
+ }
+
+ /**
+ * Return the name of the algorithm the padder implements.
+ *
+ * @return the name of the algorithm the padder implements.
+ */
+ public String getPaddingName()
+ {
+ return "ZeroByte";
+ }
+
+ /**
+ * add the pad bytes to the passed in block, returning the
+ * number of bytes added.
+ */
+ public int addPadding(
+ byte[] in,
+ int inOff)
+ {
+ int added = (in.length - inOff);
+
+ while (inOff < in.length)
+ {
+ in[inOff] = (byte) 0;
+ inOff++;
+ }
+
+ return added;
+ }
+
+ /**
+ * return the number of pad bytes present in the block.
+ */
+ public int padCount(byte[] in)
+ throws InvalidCipherTextException
+ {
+ int count = in.length;
+
+ while (count > 0)
+ {
+ if (in[count - 1] != 0)
+ {
+ break;
+ }
+
+ count--;
+ }
+
+ return in.length - count;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java
new file mode 100644
index 0000000..b60ef40
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/AEADParameters.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class AEADParameters
+ implements CipherParameters
+{
+ private byte[] associatedText;
+ private byte[] nonce;
+ private KeyParameter key;
+ private int macSize;
+
+ /**
+ * Base constructor.
+ *
+ * @param key key to be used by underlying cipher
+ * @param macSize macSize in bits
+ * @param nonce nonce to be used
+ * @param associatedText associated text, if any
+ */
+ public AEADParameters(KeyParameter key, int macSize, byte[] nonce, byte[] associatedText)
+ {
+ this.key = key;
+ this.nonce = nonce;
+ this.macSize = macSize;
+ this.associatedText = associatedText;
+ }
+
+ public KeyParameter getKey()
+ {
+ return key;
+ }
+
+ public int getMacSize()
+ {
+ return macSize;
+ }
+
+ public byte[] getAssociatedText()
+ {
+ return associatedText;
+ }
+
+ public byte[] getNonce()
+ {
+ return nonce;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java
new file mode 100644
index 0000000..03ba725
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/AsymmetricKeyParameter.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class AsymmetricKeyParameter
+ implements CipherParameters
+{
+ boolean privateKey;
+
+ public AsymmetricKeyParameter(
+ boolean privateKey)
+ {
+ this.privateKey = privateKey;
+ }
+
+ public boolean isPrivate()
+ {
+ return privateKey;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DESParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DESParameters.java
new file mode 100644
index 0000000..5bee360
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DESParameters.java
@@ -0,0 +1,107 @@
+package org.bouncycastle.crypto.params;
+
+public class DESParameters
+ extends KeyParameter
+{
+ public DESParameters(
+ byte[] key)
+ {
+ super(key);
+
+ if (isWeakKey(key, 0))
+ {
+ throw new IllegalArgumentException("attempt to create weak DES key");
+ }
+ }
+
+ /*
+ * DES Key length in bytes.
+ */
+ static public final int DES_KEY_LENGTH = 8;
+
+ /*
+ * Table of weak and semi-weak keys taken from Schneier pp281
+ */
+ static private final int N_DES_WEAK_KEYS = 16;
+
+ static private byte[] DES_weak_keys =
+ {
+ /* weak keys */
+ (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01,
+ (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e,
+ (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1,
+ (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe,
+
+ /* semi-weak keys */
+ (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe,
+ (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1,
+ (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1,
+ (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe,
+ (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e,
+ (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe,
+ (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01,
+ (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e,
+ (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01,
+ (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e,
+ (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01,
+ (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1
+ };
+
+ /**
+ * DES has 16 weak keys. This method will check
+ * if the given DES key material is weak or semi-weak.
+ * Key material that is too short is regarded as weak.
+ * <p>
+ * See <a href="http://www.counterpane.com/applied.html">"Applied
+ * Cryptography"</a> by Bruce Schneier for more information.
+ *
+ * @return true if the given DES key material is weak or semi-weak,
+ * false otherwise.
+ */
+ public static boolean isWeakKey(
+ byte[] key,
+ int offset)
+ {
+ if (key.length - offset < DES_KEY_LENGTH)
+ {
+ throw new IllegalArgumentException("key material too short.");
+ }
+
+ nextkey: for (int i = 0; i < N_DES_WEAK_KEYS; i++)
+ {
+ for (int j = 0; j < DES_KEY_LENGTH; j++)
+ {
+ if (key[j + offset] != DES_weak_keys[i * DES_KEY_LENGTH + j])
+ {
+ continue nextkey;
+ }
+ }
+
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * DES Keys use the LSB as the odd parity bit. This can
+ * be used to check for corrupt keys.
+ *
+ * @param bytes the byte array to set the parity on.
+ */
+ public static void setOddParity(
+ byte[] bytes)
+ {
+ for (int i = 0; i < bytes.length; i++)
+ {
+ int b = bytes[i];
+ bytes[i] = (byte)((b & 0xfe) |
+ ((((b >> 1) ^
+ (b >> 2) ^
+ (b >> 3) ^
+ (b >> 4) ^
+ (b >> 5) ^
+ (b >> 6) ^
+ (b >> 7)) ^ 0x01) & 0x01));
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java
new file mode 100644
index 0000000..3a4bbfc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java
@@ -0,0 +1,57 @@
+package org.bouncycastle.crypto.params;
+
+public class DESedeParameters
+ extends DESParameters
+{
+ /*
+ * DES-EDE Key length in bytes.
+ */
+ static public final int DES_EDE_KEY_LENGTH = 24;
+
+ public DESedeParameters(
+ byte[] key)
+ {
+ super(key);
+
+ if (isWeakKey(key, 0, key.length))
+ {
+ throw new IllegalArgumentException("attempt to create weak DESede key");
+ }
+ }
+
+ /**
+ * return true if the passed in key is a DES-EDE weak key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ * @param length number of bytes making up the key
+ */
+ public static boolean isWeakKey(
+ byte[] key,
+ int offset,
+ int length)
+ {
+ for (int i = offset; i < length; i += DES_KEY_LENGTH)
+ {
+ if (DESParameters.isWeakKey(key, i))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * return true if the passed in key is a DES-EDE weak key.
+ *
+ * @param key bytes making up the key
+ * @param offset offset into the byte array the key starts at
+ */
+ public static boolean isWeakKey(
+ byte[] key,
+ int offset)
+ {
+ return isWeakKey(key, offset, key.length - offset);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java
new file mode 100644
index 0000000..34c730e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHKeyGenerationParameters.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class DHKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private DHParameters params;
+
+ public DHKeyGenerationParameters(
+ SecureRandom random,
+ DHParameters params)
+ {
+ super(random, getStrength(params));
+
+ this.params = params;
+ }
+
+ public DHParameters getParameters()
+ {
+ return params;
+ }
+
+ static int getStrength(DHParameters params)
+ {
+ return params.getL() != 0 ? params.getL() : params.getP().bitLength();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHKeyParameters.java
new file mode 100644
index 0000000..e686f35
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHKeyParameters.java
@@ -0,0 +1,54 @@
+package org.bouncycastle.crypto.params;
+
+
+public class DHKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private DHParameters params;
+
+ protected DHKeyParameters(
+ boolean isPrivate,
+ DHParameters params)
+ {
+ super(isPrivate);
+
+ this.params = params;
+ }
+
+ public DHParameters getParameters()
+ {
+ return params;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DHKeyParameters))
+ {
+ return false;
+ }
+
+ DHKeyParameters dhKey = (DHKeyParameters)obj;
+
+ if (params == null)
+ {
+ return dhKey.getParameters() == null;
+ }
+ else
+ {
+ return params.equals(dhKey.getParameters());
+ }
+ }
+
+ public int hashCode()
+ {
+ int code = isPrivate() ? 0 : 1;
+
+ if (params != null)
+ {
+ code ^= params.hashCode();
+ }
+
+ return code;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java
new file mode 100644
index 0000000..b679287
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHParameters.java
@@ -0,0 +1,189 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class DHParameters
+ implements CipherParameters
+{
+ private static final int DEFAULT_MINIMUM_LENGTH = 160;
+
+ // not final due to compiler bug in "simpler" JDKs
+ private BigInteger g;
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger j;
+ private int m;
+ private int l;
+ private DHValidationParameters validation;
+
+ private static int getDefaultMParam(
+ int lParam)
+ {
+ if (lParam == 0)
+ {
+ return DEFAULT_MINIMUM_LENGTH;
+ }
+
+ return lParam < DEFAULT_MINIMUM_LENGTH ? lParam : DEFAULT_MINIMUM_LENGTH;
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g)
+ {
+ this(p, g, null, 0);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q)
+ {
+ this(p, g, q, 0);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int l)
+ {
+ this(p, g, q, getDefaultMParam(l), l, null, null);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int m,
+ int l)
+ {
+ this(p, g, q, m, l, null, null);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ BigInteger j,
+ DHValidationParameters validation)
+ {
+ this(p, g, q, DEFAULT_MINIMUM_LENGTH, 0, j, validation);
+ }
+
+ public DHParameters(
+ BigInteger p,
+ BigInteger g,
+ BigInteger q,
+ int m,
+ int l,
+ BigInteger j,
+ DHValidationParameters validation)
+ {
+ if (l != 0)
+ {
+ BigInteger bigL = BigInteger.valueOf(2L ^ (l - 1));
+ if (bigL.compareTo(p) == 1)
+ {
+ throw new IllegalArgumentException("when l value specified, it must satisfy 2^(l-1) <= p");
+ }
+ if (l < m)
+ {
+ throw new IllegalArgumentException("when l value specified, it may not be less than m value");
+ }
+ }
+
+ this.g = g;
+ this.p = p;
+ this.q = q;
+ this.m = m;
+ this.l = l;
+ this.j = j;
+ this.validation = validation;
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ public BigInteger getG()
+ {
+ return g;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ /**
+ * Return the subgroup factor J.
+ *
+ * @return subgroup factor
+ */
+ public BigInteger getJ()
+ {
+ return j;
+ }
+
+ /**
+ * Return the minimum length of the private value.
+ *
+ * @return the minimum length of the private value in bits.
+ */
+ public int getM()
+ {
+ return m;
+ }
+
+ /**
+ * Return the private value length in bits - if set, zero otherwise
+ *
+ * @return the private value length in bits, zero otherwise.
+ */
+ public int getL()
+ {
+ return l;
+ }
+
+ public DHValidationParameters getValidationParameters()
+ {
+ return validation;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DHParameters))
+ {
+ return false;
+ }
+
+ DHParameters pm = (DHParameters)obj;
+
+ if (this.getQ() != null)
+ {
+ if (!this.getQ().equals(pm.getQ()))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (pm.getQ() != null)
+ {
+ return false;
+ }
+ }
+
+ return pm.getP().equals(p) && pm.getG().equals(g);
+ }
+
+ public int hashCode()
+ {
+ return getP().hashCode() ^ getG().hashCode() ^ (getQ() != null ? getQ().hashCode() : 0);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java
new file mode 100644
index 0000000..ee1b34f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPrivateKeyParameters.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class DHPrivateKeyParameters
+ extends DHKeyParameters
+{
+ private BigInteger x;
+
+ public DHPrivateKeyParameters(
+ BigInteger x,
+ DHParameters params)
+ {
+ super(true, params);
+
+ this.x = x;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public int hashCode()
+ {
+ return x.hashCode() ^ super.hashCode();
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DHPrivateKeyParameters))
+ {
+ return false;
+ }
+
+ DHPrivateKeyParameters other = (DHPrivateKeyParameters)obj;
+
+ return other.getX().equals(this.x) && super.equals(obj);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java
new file mode 100644
index 0000000..ed53160
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHPublicKeyParameters.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class DHPublicKeyParameters
+ extends DHKeyParameters
+{
+ private BigInteger y;
+
+ public DHPublicKeyParameters(
+ BigInteger y,
+ DHParameters params)
+ {
+ super(false, params);
+
+ this.y = y;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public int hashCode()
+ {
+ return y.hashCode() ^ super.hashCode();
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DHPublicKeyParameters))
+ {
+ return false;
+ }
+
+ DHPublicKeyParameters other = (DHPublicKeyParameters)obj;
+
+ return other.getY().equals(y) && super.equals(obj);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java
new file mode 100644
index 0000000..b22f7a0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DHValidationParameters.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.util.Arrays;
+
+public class DHValidationParameters
+{
+ private byte[] seed;
+ private int counter;
+
+ public DHValidationParameters(
+ byte[] seed,
+ int counter)
+ {
+ this.seed = seed;
+ this.counter = counter;
+ }
+
+ public int getCounter()
+ {
+ return counter;
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DHValidationParameters))
+ {
+ return false;
+ }
+
+ DHValidationParameters other = (DHValidationParameters)o;
+
+ if (other.counter != this.counter)
+ {
+ return false;
+ }
+
+ return Arrays.areEqual(this.seed, other.seed);
+ }
+
+ public int hashCode()
+ {
+ return counter ^ Arrays.hashCode(seed);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java
new file mode 100644
index 0000000..29fa91e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAKeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class DSAKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private DSAParameters params;
+
+ public DSAKeyGenerationParameters(
+ SecureRandom random,
+ DSAParameters params)
+ {
+ super(random, params.getP().bitLength() - 1);
+
+ this.params = params;
+ }
+
+ public DSAParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAKeyParameters.java
new file mode 100644
index 0000000..11bb9d9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAKeyParameters.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.crypto.params;
+
+public class DSAKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private DSAParameters params;
+
+ public DSAKeyParameters(
+ boolean isPrivate,
+ DSAParameters params)
+ {
+ super(isPrivate);
+
+ this.params = params;
+ }
+
+ public DSAParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAParameters.java
new file mode 100644
index 0000000..7f76d11
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAParameters.java
@@ -0,0 +1,74 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class DSAParameters
+ implements CipherParameters
+{
+ private BigInteger g;
+ private BigInteger q;
+ private BigInteger p;
+ private DSAValidationParameters validation;
+
+ public DSAParameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g)
+ {
+ this.g = g;
+ this.p = p;
+ this.q = q;
+ }
+
+ public DSAParameters(
+ BigInteger p,
+ BigInteger q,
+ BigInteger g,
+ DSAValidationParameters params)
+ {
+ this.g = g;
+ this.p = p;
+ this.q = q;
+ this.validation = params;
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public BigInteger getG()
+ {
+ return g;
+ }
+
+ public DSAValidationParameters getValidationParameters()
+ {
+ return validation;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (!(obj instanceof DSAParameters))
+ {
+ return false;
+ }
+
+ DSAParameters pm = (DSAParameters)obj;
+
+ return (pm.getP().equals(p) && pm.getQ().equals(q) && pm.getG().equals(g));
+ }
+
+ public int hashCode()
+ {
+ return getP().hashCode() ^ getQ().hashCode() ^ getG().hashCode();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java
new file mode 100644
index 0000000..3bef3f4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPrivateKeyParameters.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class DSAPrivateKeyParameters
+ extends DSAKeyParameters
+{
+ private BigInteger x;
+
+ public DSAPrivateKeyParameters(
+ BigInteger x,
+ DSAParameters params)
+ {
+ super(true, params);
+
+ this.x = x;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java
new file mode 100644
index 0000000..c006656
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAPublicKeyParameters.java
@@ -0,0 +1,23 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class DSAPublicKeyParameters
+ extends DSAKeyParameters
+{
+ private BigInteger y;
+
+ public DSAPublicKeyParameters(
+ BigInteger y,
+ DSAParameters params)
+ {
+ super(false, params);
+
+ this.y = y;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java
new file mode 100644
index 0000000..1cc4b93
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/DSAValidationParameters.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.util.Arrays;
+
+public class DSAValidationParameters
+{
+ private byte[] seed;
+ private int counter;
+
+ public DSAValidationParameters(
+ byte[] seed,
+ int counter)
+ {
+ this.seed = seed;
+ this.counter = counter;
+ }
+
+ public int getCounter()
+ {
+ return counter;
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+
+ public int hashCode()
+ {
+ return counter ^ Arrays.hashCode(seed);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAValidationParameters))
+ {
+ return false;
+ }
+
+ DSAValidationParameters other = (DSAValidationParameters)o;
+
+ if (other.counter != this.counter)
+ {
+ return false;
+ }
+
+ return Arrays.areEqual(this.seed, other.seed);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
new file mode 100644
index 0000000..95a3ec9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECDomainParameters.java
@@ -0,0 +1,81 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECConstants;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+public class ECDomainParameters
+ implements ECConstants
+{
+ ECCurve curve;
+ byte[] seed;
+ ECPoint G;
+ BigInteger n;
+ BigInteger h;
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n)
+ {
+ this.curve = curve;
+ this.G = G;
+ this.n = n;
+ this.h = ONE;
+ this.seed = null;
+ }
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h)
+ {
+ this.curve = curve;
+ this.G = G;
+ this.n = n;
+ this.h = h;
+ this.seed = null;
+ }
+
+ public ECDomainParameters(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ this.curve = curve;
+ this.G = G;
+ this.n = n;
+ this.h = h;
+ this.seed = seed;
+ }
+
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ public ECPoint getG()
+ {
+ return G;
+ }
+
+ public BigInteger getN()
+ {
+ return n;
+ }
+
+ public BigInteger getH()
+ {
+ return h;
+ }
+
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java
new file mode 100644
index 0000000..be3f20f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECKeyGenerationParameters.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.crypto.params;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class ECKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private ECDomainParameters domainParams;
+
+ public ECKeyGenerationParameters(
+ ECDomainParameters domainParams,
+ SecureRandom random)
+ {
+ super(random, domainParams.getN().bitLength());
+
+ this.domainParams = domainParams;
+ }
+
+ public ECDomainParameters getDomainParameters()
+ {
+ return domainParams;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECKeyParameters.java
new file mode 100644
index 0000000..19825c5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECKeyParameters.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.crypto.params;
+
+public class ECKeyParameters
+ extends AsymmetricKeyParameter
+{
+ ECDomainParameters params;
+
+ protected ECKeyParameters(
+ boolean isPrivate,
+ ECDomainParameters params)
+ {
+ super(isPrivate);
+
+ this.params = params;
+ }
+
+ public ECDomainParameters getParameters()
+ {
+ return params;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java
new file mode 100644
index 0000000..3e49983
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class ECPrivateKeyParameters
+ extends ECKeyParameters
+{
+ BigInteger d;
+
+ public ECPrivateKeyParameters(
+ BigInteger d,
+ ECDomainParameters params)
+ {
+ super(true, params);
+ this.d = d;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
new file mode 100644
index 0000000..5fbea19
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ECPublicKeyParameters.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+public class ECPublicKeyParameters
+ extends ECKeyParameters
+{
+ ECPoint Q;
+
+ public ECPublicKeyParameters(
+ ECPoint Q,
+ ECDomainParameters params)
+ {
+ super(false, params);
+ this.Q = Q;
+ }
+
+ public ECPoint getQ()
+ {
+ return Q;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/KeyParameter.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/KeyParameter.java
new file mode 100644
index 0000000..5c4fe0e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/KeyParameter.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class KeyParameter
+ implements CipherParameters
+{
+ private byte[] key;
+
+ public KeyParameter(
+ byte[] key)
+ {
+ this(key, 0, key.length);
+ }
+
+ public KeyParameter(
+ byte[] key,
+ int keyOff,
+ int keyLen)
+ {
+ this.key = new byte[keyLen];
+
+ System.arraycopy(key, keyOff, this.key, 0, keyLen);
+ }
+
+ public byte[] getKey()
+ {
+ return key;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithIV.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithIV.java
new file mode 100644
index 0000000..4a1e6e9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithIV.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class ParametersWithIV
+ implements CipherParameters
+{
+ private byte[] iv;
+ private CipherParameters parameters;
+
+ public ParametersWithIV(
+ CipherParameters parameters,
+ byte[] iv)
+ {
+ this(parameters, iv, 0, iv.length);
+ }
+
+ public ParametersWithIV(
+ CipherParameters parameters,
+ byte[] iv,
+ int ivOff,
+ int ivLen)
+ {
+ this.iv = new byte[ivLen];
+ this.parameters = parameters;
+
+ System.arraycopy(iv, ivOff, this.iv, 0, ivLen);
+ }
+
+ public byte[] getIV()
+ {
+ return iv;
+ }
+
+ public CipherParameters getParameters()
+ {
+ return parameters;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java
new file mode 100644
index 0000000..a7b18e5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/ParametersWithRandom.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+import java.security.SecureRandom;
+
+public class ParametersWithRandom
+ implements CipherParameters
+{
+ private SecureRandom random;
+ private CipherParameters parameters;
+
+ public ParametersWithRandom(
+ CipherParameters parameters,
+ SecureRandom random)
+ {
+ this.random = random;
+ this.parameters = parameters;
+ }
+
+ public ParametersWithRandom(
+ CipherParameters parameters)
+ {
+ this(parameters, new SecureRandom());
+ }
+
+ public SecureRandom getRandom()
+ {
+ return random;
+ }
+
+ public CipherParameters getParameters()
+ {
+ return parameters;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java
new file mode 100644
index 0000000..dc33ec5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/RC2Parameters.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.crypto.params;
+
+import org.bouncycastle.crypto.CipherParameters;
+
+public class RC2Parameters
+ implements CipherParameters
+{
+ private byte[] key;
+ private int bits;
+
+ public RC2Parameters(
+ byte[] key)
+ {
+ this(key, (key.length > 128) ? 1024 : (key.length * 8));
+ }
+
+ public RC2Parameters(
+ byte[] key,
+ int bits)
+ {
+ this.key = new byte[key.length];
+ this.bits = bits;
+
+ System.arraycopy(key, 0, this.key, 0, key.length);
+ }
+
+ public byte[] getKey()
+ {
+ return key;
+ }
+
+ public int getEffectiveKeyBits()
+ {
+ return bits;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java
new file mode 100644
index 0000000..38b55fc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyGenerationParameters.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class RSAKeyGenerationParameters
+ extends KeyGenerationParameters
+{
+ private BigInteger publicExponent;
+ private int certainty;
+
+ public RSAKeyGenerationParameters(
+ BigInteger publicExponent,
+ SecureRandom random,
+ int strength,
+ int certainty)
+ {
+ super(random, strength);
+
+ if (strength < 12)
+ {
+ throw new IllegalArgumentException("key strength too small");
+ }
+
+ //
+ // public exponent cannot be even
+ //
+ if (!publicExponent.testBit(0))
+ {
+ throw new IllegalArgumentException("public exponent cannot be even");
+ }
+
+ this.publicExponent = publicExponent;
+ this.certainty = certainty;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ public int getCertainty()
+ {
+ return certainty;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java
new file mode 100644
index 0000000..4a2d935
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAKeyParameters.java
@@ -0,0 +1,31 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class RSAKeyParameters
+ extends AsymmetricKeyParameter
+{
+ private BigInteger modulus;
+ private BigInteger exponent;
+
+ public RSAKeyParameters(
+ boolean isPrivate,
+ BigInteger modulus,
+ BigInteger exponent)
+ {
+ super(isPrivate);
+
+ this.modulus = modulus;
+ this.exponent = exponent;
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getExponent()
+ {
+ return exponent;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java b/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java
new file mode 100644
index 0000000..b61cb5c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/params/RSAPrivateCrtKeyParameters.java
@@ -0,0 +1,67 @@
+package org.bouncycastle.crypto.params;
+
+import java.math.BigInteger;
+
+public class RSAPrivateCrtKeyParameters
+ extends RSAKeyParameters
+{
+ private BigInteger e;
+ private BigInteger p;
+ private BigInteger q;
+ private BigInteger dP;
+ private BigInteger dQ;
+ private BigInteger qInv;
+
+ /**
+ *
+ */
+ public RSAPrivateCrtKeyParameters(
+ BigInteger modulus,
+ BigInteger publicExponent,
+ BigInteger privateExponent,
+ BigInteger p,
+ BigInteger q,
+ BigInteger dP,
+ BigInteger dQ,
+ BigInteger qInv)
+ {
+ super(true, modulus, privateExponent);
+
+ this.e = publicExponent;
+ this.p = p;
+ this.q = q;
+ this.dP = dP;
+ this.dQ = dQ;
+ this.qInv = qInv;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return e;
+ }
+
+ public BigInteger getP()
+ {
+ return p;
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public BigInteger getDP()
+ {
+ return dP;
+ }
+
+ public BigInteger getDQ()
+ {
+ return dQ;
+ }
+
+ public BigInteger getQInv()
+ {
+ return qInv;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
new file mode 100644
index 0000000..a96cef0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/DSASigner.java
@@ -0,0 +1,138 @@
+package org.bouncycastle.crypto.signers;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.params.DSAKeyParameters;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * The Digital Signature Algorithm - as described in "Handbook of Applied
+ * Cryptography", pages 452 - 453.
+ */
+public class DSASigner
+ implements DSA
+{
+ DSAKeyParameters key;
+
+ SecureRandom random;
+
+ public void init(
+ boolean forSigning,
+ CipherParameters param)
+ {
+ if (forSigning)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.random = rParam.getRandom();
+ this.key = (DSAPrivateKeyParameters)rParam.getParameters();
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ this.key = (DSAPrivateKeyParameters)param;
+ }
+ }
+ else
+ {
+ this.key = (DSAPublicKeyParameters)param;
+ }
+ }
+
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. For conventional DSA the message should be a SHA-1
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public BigInteger[] generateSignature(
+ byte[] message)
+ {
+ DSAParameters params = key.getParameters();
+ BigInteger m = calculateE(params.getQ(), message);
+ BigInteger k;
+ int qBitLength = params.getQ().bitLength();
+
+ do
+ {
+ k = new BigInteger(qBitLength, random);
+ }
+ while (k.compareTo(params.getQ()) >= 0);
+
+ 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[] res = new BigInteger[2];
+
+ res[0] = r;
+ res[1] = s;
+
+ return res;
+ }
+
+ /**
+ * return true if the value r and s represent a DSA signature for
+ * the passed in message for standard DSA the message should be a
+ * SHA-1 hash of the real message to be verified.
+ */
+ public boolean verifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ DSAParameters params = key.getParameters();
+ BigInteger m = calculateE(params.getQ(), message);
+ BigInteger zero = BigInteger.valueOf(0);
+
+ if (zero.compareTo(r) >= 0 || params.getQ().compareTo(r) <= 0)
+ {
+ return false;
+ }
+
+ if (zero.compareTo(s) >= 0 || params.getQ().compareTo(s) <= 0)
+ {
+ return false;
+ }
+
+ BigInteger w = s.modInverse(params.getQ());
+
+ BigInteger u1 = m.multiply(w).mod(params.getQ());
+ BigInteger u2 = r.multiply(w).mod(params.getQ());
+
+ u1 = params.getG().modPow(u1, params.getP());
+ u2 = ((DSAPublicKeyParameters)key).getY().modPow(u2, params.getP());
+
+ BigInteger v = u1.multiply(u2).mod(params.getP()).mod(params.getQ());
+
+ return v.equals(r);
+ }
+
+ private BigInteger calculateE(BigInteger n, byte[] message)
+ {
+ if (n.bitLength() >= message.length * 8)
+ {
+ return new BigInteger(1, message);
+ }
+ else
+ {
+ byte[] trunc = new byte[n.bitLength() / 8];
+
+ System.arraycopy(message, 0, trunc, 0, trunc.length);
+
+ return new BigInteger(1, trunc);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
new file mode 100644
index 0000000..dac6efe
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java
@@ -0,0 +1,163 @@
+package org.bouncycastle.crypto.signers;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DSA;
+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.ECPoint;
+
+/**
+ * EC-DSA as described in X9.62
+ */
+public class ECDSASigner
+ implements ECConstants, DSA
+{
+ ECKeyParameters key;
+
+ SecureRandom random;
+
+ public void init(
+ boolean forSigning,
+ CipherParameters param)
+ {
+ if (forSigning)
+ {
+ if (param instanceof ParametersWithRandom)
+ {
+ ParametersWithRandom rParam = (ParametersWithRandom)param;
+
+ this.random = rParam.getRandom();
+ this.key = (ECPrivateKeyParameters)rParam.getParameters();
+ }
+ else
+ {
+ this.random = new SecureRandom();
+ this.key = (ECPrivateKeyParameters)param;
+ }
+ }
+ else
+ {
+ this.key = (ECPublicKeyParameters)param;
+ }
+ }
+
+ // 5.3 pg 28
+ /**
+ * generate a signature for the given message using the key we were
+ * initialised with. For conventional DSA the message should be a SHA-1
+ * hash of the message of interest.
+ *
+ * @param message the message that will be verified later.
+ */
+ public BigInteger[] generateSignature(
+ byte[] message)
+ {
+ BigInteger n = key.getParameters().getN();
+ BigInteger e = calculateE(n, message);
+ BigInteger r = null;
+ BigInteger s = null;
+
+ // 5.3.2
+ do // generate s
+ {
+ BigInteger k = null;
+ int nBitLength = n.bitLength();
+
+ do // generate r
+ {
+ do
+ {
+ k = new BigInteger(nBitLength, random);
+ }
+ while (k.equals(ZERO) || k.compareTo(n) >= 0);
+
+ ECPoint p = key.getParameters().getG().multiply(k);
+
+ // 5.3.3
+ BigInteger x = p.getX().toBigInteger();
+
+ r = x.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;
+ }
+
+ // 5.4 pg 29
+ /**
+ * return true if the value r and s represent a DSA signature for
+ * the passed in message (for standard DSA the message should be
+ * a SHA-1 hash of the real message to be verified).
+ */
+ public boolean verifySignature(
+ byte[] message,
+ BigInteger r,
+ BigInteger s)
+ {
+ BigInteger n = key.getParameters().getN();
+ BigInteger e = calculateE(n, message);
+
+ // r in the range [1,n-1]
+ if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ // s in the range [1,n-1]
+ if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0)
+ {
+ return false;
+ }
+
+ BigInteger c = s.modInverse(n);
+
+ BigInteger u1 = e.multiply(c).mod(n);
+ BigInteger u2 = r.multiply(c).mod(n);
+
+ ECPoint G = key.getParameters().getG();
+ ECPoint Q = ((ECPublicKeyParameters)key).getQ();
+
+ ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, u1, Q, u2);
+
+ BigInteger v = point.getX().toBigInteger().mod(n);
+
+ return v.equals(r);
+ }
+
+ private BigInteger calculateE(BigInteger n, byte[] message)
+ {
+ int log2n = n.bitLength();
+ int messageBitLength = message.length * 8;
+
+ if (log2n >= messageBitLength)
+ {
+ return new BigInteger(1, message);
+ }
+ else
+ {
+ BigInteger trunc = new BigInteger(1, message);
+
+ trunc = trunc.shiftRight(messageBitLength - log2n);
+
+ return trunc;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
new file mode 100644
index 0000000..a975d27
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java
@@ -0,0 +1,238 @@
+package org.bouncycastle.crypto.signers;
+
+import java.io.IOException;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DigestInfo;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.CryptoException;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.Signer;
+import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import org.bouncycastle.crypto.engines.RSABlindedEngine;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.util.Arrays;
+
+public class RSADigestSigner
+ implements Signer
+{
+ private final AsymmetricBlockCipher rsaEngine = new PKCS1Encoding(new RSABlindedEngine());
+ private final AlgorithmIdentifier algId;
+ private final Digest digest;
+ private boolean forSigning;
+
+ private static final Hashtable oidMap = new Hashtable();
+
+ /*
+ * Load OID table.
+ */
+ static
+ {
+ // BEGIN android-removed
+ // oidMap.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128);
+ // oidMap.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160);
+ // oidMap.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256);
+ // END android-removed
+
+ oidMap.put("SHA-1", X509ObjectIdentifiers.id_SHA1);
+ // BEGIN android-removed
+ // oidMap.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+ // END android-removed
+ oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+ oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+ oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+
+ // BEGIN android-removed
+ // oidMap.put("MD2", PKCSObjectIdentifiers.md2);
+ // oidMap.put("MD4", PKCSObjectIdentifiers.md4);
+ // END android-removed
+ oidMap.put("MD5", PKCSObjectIdentifiers.md5);
+ }
+
+ public RSADigestSigner(
+ Digest digest)
+ {
+ this.digest = digest;
+
+ algId = new AlgorithmIdentifier((ASN1ObjectIdentifier)oidMap.get(digest.getAlgorithmName()), DERNull.INSTANCE);
+ }
+
+ /**
+ * @deprecated
+ */
+ public String getAlgorithmName()
+ {
+ return digest.getAlgorithmName() + "withRSA";
+ }
+
+ /**
+ * initialise the signer for signing or verification.
+ *
+ * @param forSigning
+ * true if for signing, false otherwise
+ * @param parameters
+ * necessary parameters.
+ */
+ public void init(
+ boolean forSigning,
+ CipherParameters parameters)
+ {
+ this.forSigning = forSigning;
+ AsymmetricKeyParameter k;
+
+ if (parameters instanceof ParametersWithRandom)
+ {
+ k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).getParameters();
+ }
+ else
+ {
+ k = (AsymmetricKeyParameter)parameters;
+ }
+
+ if (forSigning && !k.isPrivate())
+ {
+ throw new IllegalArgumentException("signing requires private key");
+ }
+
+ if (!forSigning && k.isPrivate())
+ {
+ throw new IllegalArgumentException("verification requires public key");
+ }
+
+ reset();
+
+ rsaEngine.init(forSigning, parameters);
+ }
+
+ /**
+ * update the internal digest with the byte b
+ */
+ public void update(
+ byte input)
+ {
+ digest.update(input);
+ }
+
+ /**
+ * update the internal digest with the byte array in
+ */
+ public void update(
+ byte[] input,
+ int inOff,
+ int length)
+ {
+ digest.update(input, inOff, length);
+ }
+
+ /**
+ * Generate a signature for the message we've been loaded with using the key
+ * we were initialised with.
+ */
+ public byte[] generateSignature()
+ throws CryptoException, DataLengthException
+ {
+ if (!forSigning)
+ {
+ throw new IllegalStateException("RSADigestSigner not initialised for signature generation.");
+ }
+
+ byte[] hash = new byte[digest.getDigestSize()];
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] data = derEncode(hash);
+ return rsaEngine.processBlock(data, 0, data.length);
+ }
+ catch (IOException e)
+ {
+ throw new CryptoException("unable to encode signature: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * return true if the internal state represents the signature described in
+ * the passed in array.
+ */
+ public boolean verifySignature(
+ byte[] signature)
+ {
+ if (forSigning)
+ {
+ throw new IllegalStateException("RSADigestSigner not initialised for verification");
+ }
+
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = rsaEngine.processBlock(signature, 0, signature.length);
+ expected = derEncode(hash);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ if (sig.length == expected.length)
+ {
+ return Arrays.constantTimeAreEqual(sig, expected);
+ }
+ else if (sig.length == expected.length - 2) // NULL left out
+ {
+ int sigOffset = sig.length - hash.length - 2;
+ int expectedOffset = expected.length - hash.length - 2;
+
+ expected[1] -= 2; // adjust lengths
+ expected[3] -= 2;
+
+ int nonEqual = 0;
+
+ for (int i = 0; i < hash.length; i++)
+ {
+ nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ nonEqual |= (sig[i] ^ expected[i]); // check header less NULL
+ }
+
+ return nonEqual == 0;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public void reset()
+ {
+ digest.reset();
+ }
+
+ private byte[] derEncode(
+ byte[] hash)
+ throws IOException
+ {
+ DigestInfo dInfo = new DigestInfo(algId, hash);
+
+ return dInfo.getEncoded(ASN1Encoding.DER);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java
new file mode 100644
index 0000000..857b765
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/Pack.java
@@ -0,0 +1,100 @@
+package org.bouncycastle.crypto.util;
+
+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 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 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 longToBigEndian(long n, byte[] bs, int off)
+ {
+ intToBigEndian((int)(n >>> 32), bs, off);
+ intToBigEndian((int)(n & 0xffffffffL), bs, off + 4);
+ }
+
+ 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 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 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 longToLittleEndian(long n, byte[] bs, int off)
+ {
+ intToLittleEndian((int)(n & 0xffffffffL), bs, off);
+ intToLittleEndian((int)(n >>> 32), bs, off + 4);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
new file mode 100644
index 0000000..8ddfac8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -0,0 +1,180 @@
+package org.bouncycastle.crypto.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.oiw.ElGamalParameter;
+// END android-removed
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import org.bouncycastle.asn1.sec.ECPrivateKey;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+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.ECPrivateKeyParameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.ElGamalParameters;
+// import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
+// END android-removed
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * Factory for creating private key objects from PKCS8 PrivateKeyInfo objects.
+ */
+public class PrivateKeyFactory
+{
+ /**
+ * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding.
+ *
+ * @param privateKeyInfoData the PrivateKeyInfo encoding
+ * @return a suitable private key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) throws IOException
+ {
+ return createKey(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(privateKeyInfoData)));
+ }
+
+ /**
+ * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a
+ * stream.
+ *
+ * @param inStr the stream to read the PrivateKeyInfo encoding from
+ * @return a suitable private key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException
+ {
+ return createKey(PrivateKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
+ }
+
+ /**
+ * Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object.
+ *
+ * @param keyInfo the PrivateKeyInfo object containing the key material
+ * @return a suitable private key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) throws IOException
+ {
+ AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm();
+
+ if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption))
+ {
+ RSAPrivateKey keyStructure = RSAPrivateKey.getInstance(keyInfo.parsePrivateKey());
+
+ return new RSAPrivateCrtKeyParameters(keyStructure.getModulus(),
+ keyStructure.getPublicExponent(), keyStructure.getPrivateExponent(),
+ keyStructure.getPrime1(), keyStructure.getPrime2(), keyStructure.getExponent1(),
+ keyStructure.getExponent2(), keyStructure.getCoefficient());
+ }
+ // TODO?
+// else if (algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber))
+ else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ DHParameter params = DHParameter.getInstance(algId.getParameters());
+ DERInteger derX = (DERInteger)keyInfo.parsePrivateKey();
+
+ BigInteger lVal = params.getL();
+ int l = lVal == null ? 0 : lVal.intValue();
+ DHParameters dhParams = new DHParameters(params.getP(), params.getG(), null, l);
+
+ return new DHPrivateKeyParameters(derX.getValue(), dhParams);
+ }
+ // BEGIN android-removed
+ // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+ // {
+ // ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+ // DERInteger derX = (DERInteger)keyInfo.parsePrivateKey();
+ //
+ // return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters(
+ // params.getP(), params.getG()));
+ // }
+ // END android-removed
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa))
+ {
+ DERInteger derX = (DERInteger)keyInfo.parsePrivateKey();
+ ASN1Encodable de = algId.getParameters();
+
+ DSAParameters parameters = null;
+ if (de != null)
+ {
+ DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
+ parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
+ }
+
+ return new DSAPrivateKeyParameters(derX.getValue(), parameters);
+ }
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ X962Parameters params = new X962Parameters((ASN1Primitive)algId.getParameters());
+
+ X9ECParameters x9;
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ x9 = X962NamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = SECNamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = NISTNamedCurves.getByOID(oid);
+
+ // BEGIN android-removed
+ // if (x9 == null)
+ // {
+ // x9 = TeleTrusTNamedCurves.getByOID(oid);
+ // }
+ // END android-removed
+ }
+ }
+ }
+ else
+ {
+ x9 = X9ECParameters.getInstance(params.getParameters());
+ }
+
+ 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
+ {
+ throw new RuntimeException("algorithm identifier in key not recognised");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
new file mode 100644
index 0000000..05520f0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -0,0 +1,217 @@
+package org.bouncycastle.crypto.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.oiw.ElGamalParameter;
+// END android-removed
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSAPublicKey;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+// END android-removed
+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.X962NamedCurves;
+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.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+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.ECPublicKeyParameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.ElGamalParameters;
+// import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
+// END android-removed
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+
+/**
+ * Factory to create asymmetric public key parameters for asymmetric ciphers from range of
+ * ASN.1 encoded SubjectPublicKeyInfo objects.
+ */
+public class PublicKeyFactory
+{
+ /**
+ * Create a public key from a SubjectPublicKeyInfo encoding
+ *
+ * @param keyInfoData the SubjectPublicKeyInfo encoding
+ * @return the appropriate key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(byte[] keyInfoData) throws IOException
+ {
+ return createKey(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(keyInfoData)));
+ }
+
+ /**
+ * Create a public key from a SubjectPublicKeyInfo encoding read from a stream
+ *
+ * @param inStr the stream to read the SubjectPublicKeyInfo encoding from
+ * @return the appropriate key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException
+ {
+ return createKey(SubjectPublicKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
+ }
+
+ /**
+ * Create a public key from the passed in SubjectPublicKeyInfo
+ *
+ * @param keyInfo the SubjectPublicKeyInfo containing the key data
+ * @return the appropriate key parameter
+ * @throws IOException on an error decoding the key
+ */
+ public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo) throws IOException
+ {
+ AlgorithmIdentifier algId = keyInfo.getAlgorithm();
+
+ if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)
+ || algId.getAlgorithm().equals(X509ObjectIdentifiers.id_ea_rsa))
+ {
+ RSAPublicKey pubKey = RSAPublicKey.getInstance(keyInfo.parsePublicKey());
+
+ return new RSAKeyParameters(false, pubKey.getModulus(), pubKey.getPublicExponent());
+ }
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHPublicKey dhPublicKey = DHPublicKey.getInstance(keyInfo.parsePublicKey());
+
+ BigInteger y = dhPublicKey.getY().getValue();
+
+ DHDomainParameters dhParams = DHDomainParameters.getInstance(algId.getParameters());
+
+ BigInteger p = dhParams.getP().getValue();
+ BigInteger g = dhParams.getG().getValue();
+ BigInteger q = dhParams.getQ().getValue();
+
+ BigInteger j = null;
+ if (dhParams.getJ() != null)
+ {
+ j = dhParams.getJ().getValue();
+ }
+
+ DHValidationParameters validation = null;
+ DHValidationParms dhValidationParms = dhParams.getValidationParms();
+ if (dhValidationParms != null)
+ {
+ byte[] seed = dhValidationParms.getSeed().getBytes();
+ BigInteger pgenCounter = dhValidationParms.getPgenCounter().getValue();
+
+ // TODO Check pgenCounter size?
+
+ validation = new DHValidationParameters(seed, pgenCounter.intValue());
+ }
+
+ return new DHPublicKeyParameters(y, new DHParameters(p, g, q, j, validation));
+ }
+ else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ DHParameter params = DHParameter.getInstance(algId.getParameters());
+ DERInteger derY = (DERInteger)keyInfo.parsePublicKey();
+
+ BigInteger lVal = params.getL();
+ int l = lVal == null ? 0 : lVal.intValue();
+ DHParameters dhParams = new DHParameters(params.getP(), params.getG(), null, l);
+
+ return new DHPublicKeyParameters(derY.getValue(), dhParams);
+ }
+ // BEGIN android-removed
+ // else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm))
+ // {
+ // ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters());
+ // DERInteger derY = (DERInteger)keyInfo.parsePublicKey();
+ //
+ // return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters(
+ // params.getP(), params.getG()));
+ // }
+ // END android-removed
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)
+ || algId.getAlgorithm().equals(OIWObjectIdentifiers.dsaWithSHA1))
+ {
+ DERInteger derY = (DERInteger)keyInfo.parsePublicKey();
+ ASN1Encodable de = algId.getParameters();
+
+ DSAParameters parameters = null;
+ if (de != null)
+ {
+ DSAParameter params = DSAParameter.getInstance(de.toASN1Primitive());
+ parameters = new DSAParameters(params.getP(), params.getQ(), params.getG());
+ }
+
+ return new DSAPublicKeyParameters(derY.getValue(), parameters);
+ }
+ else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ X962Parameters params = new X962Parameters(
+ (ASN1Primitive)algId.getParameters());
+
+ X9ECParameters x9;
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)params.getParameters();
+ x9 = X962NamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = SECNamedCurves.getByOID(oid);
+
+ if (x9 == null)
+ {
+ x9 = NISTNamedCurves.getByOID(oid);
+
+ // BEGIN android-removed
+ // if (x9 == null)
+ // {
+ // x9 = TeleTrusTNamedCurves.getByOID(oid);
+ // }
+ // END android-removed
+ }
+ }
+ }
+ else
+ {
+ x9 = X9ECParameters.getInstance(params.getParameters());
+ }
+
+ 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
+ {
+ throw new RuntimeException("algorithm identifier in key not recognised");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java
new file mode 100644
index 0000000..807bdfd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/DefaultJcaJceHelper.java
@@ -0,0 +1,88 @@
+package org.bouncycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+
+public class DefaultJcaJceHelper
+ implements JcaJceHelper
+{
+ public Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException
+ {
+ return Cipher.getInstance(algorithm);
+ }
+
+ public Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Mac.getInstance(algorithm);
+ }
+
+ public KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyAgreement.getInstance(algorithm);
+ }
+
+ public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return AlgorithmParameterGenerator.getInstance(algorithm);
+ }
+
+ public AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return AlgorithmParameters.getInstance(algorithm);
+ }
+
+ public KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyGenerator.getInstance(algorithm);
+ }
+
+ public KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyFactory.getInstance(algorithm);
+ }
+
+ public KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyPairGenerator.getInstance(algorithm);
+ }
+
+ public MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return MessageDigest.getInstance(algorithm);
+ }
+
+ public Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(algorithm);
+ }
+
+ public CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, CertificateException
+ {
+ return CertificateFactory.getInstance(algorithm);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java
new file mode 100644
index 0000000..d8a4900
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/JcaJceHelper.java
@@ -0,0 +1,55 @@
+package org.bouncycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+
+public interface JcaJceHelper
+{
+ Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException;
+
+ Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException;
+
+ CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CertificateException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java
new file mode 100644
index 0000000..9abf52d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/NamedJcaJceHelper.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+
+public class NamedJcaJceHelper
+ implements JcaJceHelper
+{
+ protected final String providerName;
+
+ public NamedJcaJceHelper(String providerName)
+ {
+ this.providerName = providerName;
+ }
+
+ public Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException
+ {
+ return Cipher.getInstance(algorithm, providerName);
+ }
+
+ public Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return Mac.getInstance(algorithm, providerName);
+ }
+
+ public KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyAgreement.getInstance(algorithm, providerName);
+ }
+
+ public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return AlgorithmParameterGenerator.getInstance(algorithm, providerName);
+ }
+
+ public AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return AlgorithmParameters.getInstance(algorithm, providerName);
+ }
+
+ public KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyGenerator.getInstance(algorithm, providerName);
+ }
+
+ public KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyFactory.getInstance(algorithm, providerName);
+ }
+
+ public KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return KeyPairGenerator.getInstance(algorithm, providerName);
+ }
+
+ public MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return MessageDigest.getInstance(algorithm, providerName);
+ }
+
+ public Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ return Signature.getInstance(algorithm, providerName);
+ }
+
+ public CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, CertificateException, NoSuchProviderException
+ {
+ return CertificateFactory.getInstance(algorithm, providerName);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java b/bcprov/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java
new file mode 100644
index 0000000..83ff765
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/ProviderJcaJceHelper.java
@@ -0,0 +1,96 @@
+package org.bouncycastle.jcajce;
+
+import java.security.AlgorithmParameterGenerator;
+import java.security.AlgorithmParameters;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Signature;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+
+public class ProviderJcaJceHelper
+ implements JcaJceHelper
+{
+ protected final Provider provider;
+
+ public ProviderJcaJceHelper(Provider provider)
+ {
+ this.provider = provider;
+ }
+
+ public Cipher createCipher(
+ String algorithm)
+ throws NoSuchAlgorithmException, NoSuchPaddingException
+ {
+ return Cipher.getInstance(algorithm, provider);
+ }
+
+ public Mac createMac(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Mac.getInstance(algorithm, provider);
+ }
+
+ public KeyAgreement createKeyAgreement(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyAgreement.getInstance(algorithm, provider);
+ }
+
+ public AlgorithmParameterGenerator createAlgorithmParameterGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return AlgorithmParameterGenerator.getInstance(algorithm, provider);
+ }
+
+ public AlgorithmParameters createAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return AlgorithmParameters.getInstance(algorithm, provider);
+ }
+
+ public KeyGenerator createKeyGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyGenerator.getInstance(algorithm, provider);
+ }
+
+ public KeyFactory createKeyFactory(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyFactory.getInstance(algorithm, provider);
+ }
+
+ public KeyPairGenerator createKeyPairGenerator(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return KeyPairGenerator.getInstance(algorithm, provider);
+ }
+
+ public MessageDigest createDigest(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return MessageDigest.getInstance(algorithm, provider);
+ }
+
+ public Signature createSignature(String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(algorithm, provider);
+ }
+
+ public CertificateFactory createCertificateFactory(String algorithm)
+ throws NoSuchAlgorithmException, CertificateException
+ {
+ return CertificateFactory.getInstance(algorithm, provider);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java b/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java
new file mode 100644
index 0000000..235bfe5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/io/MacOutputStream.java
@@ -0,0 +1,38 @@
+package org.bouncycastle.jcajce.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.crypto.Mac;
+
+public class MacOutputStream
+ extends OutputStream
+{
+ protected Mac mac;
+
+ public MacOutputStream(
+ Mac mac)
+ {
+ this.mac = mac;
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ mac.update((byte)b);
+ }
+
+ public void write(
+ byte[] b,
+ int off,
+ int len)
+ throws IOException
+ {
+ mac.update(b, off, len);
+ }
+
+ public byte[] getMac()
+ {
+ return mac.doFinal();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java
new file mode 100644
index 0000000..8055576
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DH.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+public class DH
+{
+ private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".dh.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyPairGenerator.DH", PREFIX + "KeyPairGeneratorSpi");
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("KeyAgreement.DH", PREFIX + "KeyAgreementSpi");
+ provider.addAlgorithm("Alg.Alias.KeyAgreement.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("KeyFactory.DH", PREFIX + "KeyFactorySpi");
+ provider.addAlgorithm("Alg.Alias.KeyFactory.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("AlgorithmParameters.DH", PREFIX + "AlgorithmParametersSpi");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator.DIFFIEHELLMAN", "DH");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.DH", PREFIX + "AlgorithmParameterGeneratorSpi");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
new file mode 100644
index 0000000..830334b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/DSA.java
@@ -0,0 +1,68 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.dsa.DSAUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.dsa.KeyFactorySpi;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class DSA
+{
+ private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".dsa.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameters.DSA", PREFIX + "AlgorithmParametersSpi");
+
+ provider.addAlgorithm("AlgorithmParameterGenerator.DSA", PREFIX + "AlgorithmParameterGeneratorSpi");
+
+ provider.addAlgorithm("KeyPairGenerator.DSA", PREFIX + "KeyPairGeneratorSpi");
+ provider.addAlgorithm("KeyFactory.DSA", PREFIX + "KeyFactorySpi");
+
+ // BEGIN android-changed
+ provider.addAlgorithm("Signature.SHA1withDSA", PREFIX + "DSASigner$stdDSA");
+ // END android-changed
+ provider.addAlgorithm("Signature.NONEWITHDSA", PREFIX + "DSASigner$noneDSA");
+
+ provider.addAlgorithm("Alg.Alias.Signature.RAWDSA", "NONEWITHDSA");
+
+ // BEGIN android-removed
+ // addSignatureAlgorithm(provider, "SHA224", "DSA", PREFIX + "DSASigner$dsa224", NISTObjectIdentifiers.dsa_with_sha224);
+ // addSignatureAlgorithm(provider, "SHA256", "DSA", PREFIX + "DSASigner$dsa256", NISTObjectIdentifiers.dsa_with_sha256);
+ // addSignatureAlgorithm(provider, "SHA384", "DSA", PREFIX + "DSASigner$dsa384", NISTObjectIdentifiers.dsa_with_sha384);
+ // addSignatureAlgorithm(provider, "SHA512", "DSA", PREFIX + "DSASigner$dsa512", NISTObjectIdentifiers.dsa_with_sha512);
+ // END android-removed
+
+ // BEGIN android-added
+ provider.addAlgorithm("Alg.Alias.Signature.DSA", "SHA1withDSA");
+ // END android-added
+ // BEGIN android-changed
+ provider.addAlgorithm("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.SHA1WITHDSA", "SHA1withDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.1", "SHA1withDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10040.4.3", "SHA1withDSA");
+ provider.addAlgorithm("Alg.Alias.Signature.DSAwithSHA1", "SHA1withDSA");
+ 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
+
+ AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+
+ for (int i = 0; i != DSAUtil.dsaOids.length; i++)
+ {
+ registerOid(provider, DSAUtil.dsaOids[i], "DSA", keyFact);
+ registerOidAlgorithmParameters(provider, DSAUtil.dsaOids[i], "DSA");
+ }
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
new file mode 100644
index 0000000..bacb6d6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
@@ -0,0 +1,99 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+// BEGIN android-removed
+// import org.bouncycastle.asn1.eac.EACObjectIdentifiers;
+// 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;
+
+public class EC
+{
+ private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".ec.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ 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");
+ // END android-removed
+
+ registerOid(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC", new KeyFactorySpi.EC());
+ // TODO Should this be an alias for ECDH?
+ registerOid(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC());
+ // BEGIN android-removed
+ // registerOid(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
+ // END android-removed
+
+ // BEGIN android-removed
+ // 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
+
+ provider.addAlgorithm("KeyFactory.EC", PREFIX + "KeyFactorySpi$EC");
+ // BEGIN android-removed
+ // 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.ECDHC", PREFIX + "KeyPairGeneratorSpi$ECDHC");
+ // provider.addAlgorithm("KeyPairGenerator.ECIES", PREFIX + "KeyPairGeneratorSpi$ECDH");
+ // provider.addAlgorithm("KeyPairGenerator.ECMQV", PREFIX + "KeyPairGeneratorSpi$ECMQV");
+ // END android-removed
+
+ provider.addAlgorithm("Signature.ECDSA", 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");
+ // BEGIN android-removed
+ // provider.addAlgorithm("Alg.Alias.Signature." + TeleTrusTObjectIdentifiers.ecSignWithSha1, "ECDSA");
+ // END android-removed
+
+ // BEGIN android-removed
+ // addSignatureAlgorithm(provider, "SHA224", "ECDSA", PREFIX + "SignatureSpi$ecDSA224", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ // END android-removed
+ addSignatureAlgorithm(provider, "SHA256", "ECDSA", PREFIX + "SignatureSpi$ecDSA256", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ addSignatureAlgorithm(provider, "SHA384", "ECDSA", PREFIX + "SignatureSpi$ecDSA384", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ addSignatureAlgorithm(provider, "SHA512", "ECDSA", PREFIX + "SignatureSpi$ecDSA512", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ // BEGIN android-removed
+ // addSignatureAlgorithm(provider, "RIPEMD160", "ECDSA", PREFIX + "SignatureSpi$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160);
+ //
+ // provider.addAlgorithm("Signature.SHA1WITHECNR", PREFIX + "SignatureSpi$ecNR");
+ // provider.addAlgorithm("Signature.SHA224WITHECNR", PREFIX + "SignatureSpi$ecNR224");
+ // provider.addAlgorithm("Signature.SHA256WITHECNR", PREFIX + "SignatureSpi$ecNR256");
+ // provider.addAlgorithm("Signature.SHA384WITHECNR", PREFIX + "SignatureSpi$ecNR384");
+ // provider.addAlgorithm("Signature.SHA512WITHECNR", PREFIX + "SignatureSpi$ecNR512");
+ //
+ // addSignatureAlgorithm(provider, "SHA1", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1);
+ // addSignatureAlgorithm(provider, "SHA224", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA224", EACObjectIdentifiers.id_TA_ECDSA_SHA_224);
+ // addSignatureAlgorithm(provider, "SHA256", "CVC-ECDSA", PREFIX + "SignatureSpi$ecCVCDSA256", EACObjectIdentifiers.id_TA_ECDSA_SHA_256);
+ // END android-removed
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
new file mode 100644
index 0000000..dcf52c8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
@@ -0,0 +1,217 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public class RSA
+{
+ private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".rsa.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameters.OAEP", PREFIX + "AlgorithmParametersSpi$OAEP");
+ // 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");
+ //
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224withRSA/PSS", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256withRSA/PSS", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384withRSA/PSS", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512withRSA/PSS", "PSS");
+ //
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA224WITHRSAANDMGF1", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA256WITHRSAANDMGF1", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA384WITHRSAANDMGF1", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.SHA512WITHRSAANDMGF1", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.RAWRSAPSS", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAPSS", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSASSA-PSS", "PSS");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameters.NONEWITHRSAANDMGF1", "PSS");
+ // END android-removed
+
+ provider.addAlgorithm("Cipher.RSA", PREFIX + "CipherSpi$NoPadding");
+ // BEGIN android-changed
+ provider.addAlgorithm("Alg.Alias.Cipher.RSA/RAW", "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.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.RSA/ISO9796-1", PREFIX + "CipherSpi$ISO9796d1Padding");
+ // END android-removed
+
+ provider.addAlgorithm("Alg.Alias.Cipher.RSA//RAW", "RSA");
+ provider.addAlgorithm("Alg.Alias.Cipher.RSA//NOPADDING", "RSA");
+ // BEGIN android-removed
+ // provider.addAlgorithm("Alg.Alias.Cipher.RSA//PKCS1PADDING", "RSA/PKCS1");
+ // provider.addAlgorithm("Alg.Alias.Cipher.RSA//OAEPPADDING", "RSA/OAEP");
+ // provider.addAlgorithm("Alg.Alias.Cipher.RSA//ISO9796-1PADDING", "RSA/ISO9796-1");
+ // END android-removed
+
+ provider.addAlgorithm("KeyFactory.RSA", PREFIX + "KeyFactorySpi");
+ provider.addAlgorithm("KeyPairGenerator.RSA", PREFIX + "KeyPairGeneratorSpi");
+
+ AsymmetricKeyInfoConverter keyFact = new KeyFactorySpi();
+
+ registerOid(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA", keyFact);
+ registerOid(provider, X509ObjectIdentifiers.id_ea_rsa, "RSA", keyFact);
+ registerOid(provider, PKCSObjectIdentifiers.id_RSAES_OAEP, "RSA", keyFact);
+ // BEGIN android-removed
+ // registerOid(provider, PKCSObjectIdentifiers.id_RSASSA_PSS, "RSA", keyFact);
+ //
+ // registerOidAlgorithmParameters(provider, PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ // registerOidAlgorithmParameters(provider, X509ObjectIdentifiers.id_ea_rsa, "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");
+ //
+ // provider.addAlgorithm("Alg.Alias.Signature.RAWRSA", "RSA");
+ // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSA", "RSA");
+ // provider.addAlgorithm("Alg.Alias.Signature.RAWRSAPSS", "RAWRSASSA-PSS");
+ // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSAPSS", "RAWRSASSA-PSS");
+ // provider.addAlgorithm("Alg.Alias.Signature.NONEWITHRSASSA-PSS", "RAWRSASSA-PSS");
+ // 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");
+ //
+ // if (provider.hasAlgorithm("MessageDigest", "MD2"))
+ // {
+ // addDigestSignature(provider, "MD2", PREFIX + "DigestSignatureSpi$MD2", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ // }
+ //
+ // if (provider.hasAlgorithm("MessageDigest", "MD2"))
+ // {
+ // addDigestSignature(provider, "MD4", PREFIX + "DigestSignatureSpi$MD4", PKCSObjectIdentifiers.md4WithRSAEncryption);
+ // }
+ //
+ // if (provider.hasAlgorithm("MessageDigest", "MD2"))
+ // {
+ // addDigestSignature(provider, "MD5", PREFIX + "DigestSignatureSpi$MD5", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ // provider.addAlgorithm("Signature.MD5withRSA/ISO9796-2", PREFIX + "ISOSignatureSpi$MD5WithRSAEncryption");
+ // provider.addAlgorithm("Alg.Alias.Signature.MD5WithRSA/ISO9796-2", "MD5withRSA/ISO9796-2");
+ // }
+ // END android-removed
+
+ if (provider.hasAlgorithm("MessageDigest", "SHA1"))
+ {
+ // 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");
+ // 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");
+ // END android-removed
+ provider.addAlgorithm("Alg.Alias.Signature." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+ provider.addAlgorithm("Alg.Alias.Signature.OID." + OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+ }
+
+ // BEGIN android-removed
+ // addDigestSignature(provider, "SHA224", PREFIX + "DigestSignatureSpi$SHA224", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ // END android-removed
+ addDigestSignature(provider, "SHA256", PREFIX + "DigestSignatureSpi$SHA256", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ addDigestSignature(provider, "SHA384", PREFIX + "DigestSignatureSpi$SHA384", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ addDigestSignature(provider, "SHA512", PREFIX + "DigestSignatureSpi$SHA512", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+
+ // BEGIN android-removed
+ // if (provider.hasAlgorithm("MessageDigest", "RIPEMD128"))
+ // {
+ // addDigestSignature(provider, "RIPEMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ // addDigestSignature(provider, "RMD128", PREFIX + "DigestSignatureSpi$RIPEMD128", null);
+ // }
+ //
+ // 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");
+ // }
+ //
+ // if (provider.hasAlgorithm("MessageDigest", "RIPEMD256"))
+ // {
+ // addDigestSignature(provider, "RIPEMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ // addDigestSignature(provider, "RMD256", PREFIX + "DigestSignatureSpi$RIPEMD256", null);
+ // }
+ // END android-removed
+ }
+
+ private void addDigestSignature(
+ ConfigurableProvider provider,
+ String digest,
+ String className,
+ ASN1ObjectIdentifier oid)
+ {
+ String mainName = digest + "WITHRSA";
+ String jdk11Variation1 = digest + "withRSA";
+ String jdk11Variation2 = digest + "WithRSA";
+ String alias = digest + "/" + "RSA";
+ String longName = digest + "WITHRSAENCRYPTION";
+ String longJdk11Variation1 = digest + "withRSAEncryption";
+ String longJdk11Variation2 = digest + "WithRSAEncryption";
+
+ provider.addAlgorithm("Signature." + mainName, className);
+ provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation1, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation2, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + longName, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + longJdk11Variation1, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + longJdk11Variation2, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + alias, mainName);
+
+ if (oid != null)
+ {
+ provider.addAlgorithm("Alg.Alias.Signature." + oid, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, mainName);
+ }
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/X509.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/X509.java
new file mode 100644
index 0000000..a9fb6b2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/X509.java
@@ -0,0 +1,33 @@
+package org.bouncycastle.jcajce.provider.asymmetric;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+
+/**
+ * For some reason the class path project thinks that such a KeyFactory will exist.
+ */
+public class X509
+{
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ // BEGIN android-removed
+ // provider.addAlgorithm("KeyFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.KeyFactory");
+ // provider.addAlgorithm("Alg.Alias.KeyFactory.X509", "X.509");
+ // END android-removed
+
+ //
+ // certificate factories.
+ //
+ provider.addAlgorithm("CertificateFactory.X.509", "org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory");
+ provider.addAlgorithm("Alg.Alias.CertificateFactory.X509", "X.509");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..8bdcc55
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.DHGenParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.crypto.generators.DHParametersGenerator;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class AlgorithmParameterGeneratorSpi
+ extends java.security.AlgorithmParameterGeneratorSpi
+{
+ protected SecureRandom random;
+ protected int strength = 1024;
+
+ private int l = 0;
+
+ protected void engineInit(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(genParamSpec instanceof DHGenParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("DH parameter generator requires a DHGenParameterSpec for initialisation");
+ }
+ DHGenParameterSpec spec = (DHGenParameterSpec)genParamSpec;
+
+ this.strength = spec.getPrimeSize();
+ this.l = spec.getExponentSize();
+ this.random = random;
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ DHParametersGenerator pGen = new DHParametersGenerator();
+
+ if (random != null)
+ {
+ pGen.init(strength, 20, random);
+ }
+ else
+ {
+ pGen.init(strength, 20, new SecureRandom());
+ }
+
+ DHParameters p = pGen.generateParameters();
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("DH", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new DHParameterSpec(p.getP(), p.getG(), l));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..c771123
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/AlgorithmParametersSpi.java
@@ -0,0 +1,142 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+
+public class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ DHParameterSpec currentSpec;
+
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+
+
+
+ /**
+ * Return the PKCS#3 ASN.1 structure DHParameter.
+ * <p>
+ * <pre>
+ * DHParameter ::= SEQUENCE {
+ * prime INTEGER, -- p
+ * base INTEGER, -- g
+ * privateValueLength INTEGER OPTIONAL}
+ * </pre>
+ */
+ protected byte[] engineGetEncoded()
+ {
+ DHParameter dhP = new DHParameter(currentSpec.getP(), currentSpec.getG(), currentSpec.getL());
+
+ try
+ {
+ return dhP.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding DHParameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == DHParameterSpec.class)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to DH parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof DHParameterSpec))
+ {
+ throw new InvalidParameterSpecException("DHParameterSpec required to initialise a Diffie-Hellman algorithm parameters object");
+ }
+
+ this.currentSpec = (DHParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ DHParameter dhP = DHParameter.getInstance(params);
+
+ if (dhP.getL() != null)
+ {
+ currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG(), dhP.getL().intValue());
+ }
+ else
+ {
+ currentSpec = new DHParameterSpec(dhP.getP(), dhP.getG());
+ }
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid DH Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid DH Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "Diffie-Hellman Parameters";
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java
new file mode 100644
index 0000000..332e2eb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java
@@ -0,0 +1,214 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+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.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.DHParameter;
+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.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+
+public class BCDHPrivateKey
+ implements DHPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 311058815616901812L;
+
+ private BigInteger x;
+
+ private transient DHParameterSpec dhSpec;
+ private transient PrivateKeyInfo info;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCDHPrivateKey()
+ {
+ }
+
+ BCDHPrivateKey(
+ DHPrivateKey key)
+ {
+ this.x = key.getX();
+ this.dhSpec = key.getParams();
+ }
+
+ BCDHPrivateKey(
+ DHPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+ }
+
+ public BCDHPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ ASN1Sequence seq = ASN1Sequence.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+ ASN1Integer derX = (ASN1Integer)info.parsePrivateKey();
+ ASN1ObjectIdentifier id = info.getPrivateKeyAlgorithm().getAlgorithm();
+
+ this.info = info;
+ this.x = derX.getValue();
+
+ if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ DHParameter params = DHParameter.getInstance(seq);
+
+ if (params.getL() != null)
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+ }
+ else
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+ }
+ }
+ else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+ this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm type: " + id);
+ }
+ }
+
+ BCDHPrivateKey(
+ DHPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DH";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ if (info != null)
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+
+ PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(getX()));
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return dhSpec;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DHPrivateKey))
+ {
+ return false;
+ }
+
+ DHPrivateKey other = (DHPrivateKey)o;
+
+ return this.getX().equals(other.getX())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getL() == other.getParams().getL();
+ }
+
+ public int hashCode()
+ {
+ return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+ this.info = null;
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(dhSpec.getP());
+ out.writeObject(dhSpec.getG());
+ out.writeInt(dhSpec.getL());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
new file mode 100644
index 0000000..0697f75
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java
@@ -0,0 +1,204 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+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.pkcs.DHParameter;
+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.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCDHPublicKey
+ implements DHPublicKey
+{
+ static final long serialVersionUID = -216691575254424324L;
+
+ private BigInteger y;
+
+ private transient DHParameterSpec dhSpec;
+ private transient SubjectPublicKeyInfo info;
+
+ BCDHPublicKey(
+ DHPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+ }
+
+ BCDHPublicKey(
+ DHPublicKey key)
+ {
+ this.y = key.getY();
+ this.dhSpec = key.getParams();
+ }
+
+ BCDHPublicKey(
+ DHPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+ }
+
+ BCDHPublicKey(
+ BigInteger y,
+ DHParameterSpec dhSpec)
+ {
+ this.y = y;
+ this.dhSpec = dhSpec;
+ }
+
+ public BCDHPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ this.info = info;
+
+ ASN1Integer derY;
+ try
+ {
+ derY = (ASN1Integer)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DH public key");
+ }
+
+ this.y = derY.getValue();
+
+ ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithm().getParameters());
+ ASN1ObjectIdentifier id = info.getAlgorithm().getAlgorithm();
+
+ // we need the PKCS check to handle older keys marked with the X9 oid.
+ if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement) || isPKCSParam(seq))
+ {
+ DHParameter params = DHParameter.getInstance(seq);
+
+ if (params.getL() != null)
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+ }
+ else
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+ }
+ }
+ else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+ this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm type: " + id);
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return "DH";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (info != null)
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(y));
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return dhSpec;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ private boolean isPKCSParam(ASN1Sequence seq)
+ {
+ if (seq.size() == 2)
+ {
+ return true;
+ }
+
+ if (seq.size() > 3)
+ {
+ return false;
+ }
+
+ ASN1Integer l = ASN1Integer.getInstance(seq.getObjectAt(2));
+ ASN1Integer p = ASN1Integer.getInstance(seq.getObjectAt(0));
+
+ if (l.getValue().compareTo(BigInteger.valueOf(p.getValue().bitLength())) > 0)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getL();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DHPublicKey))
+ {
+ return false;
+ }
+
+ DHPublicKey other = (DHPublicKey)o;
+
+ return this.getY().equals(other.getY())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getL() == other.getParams().getL();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+ this.info = null;
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(dhSpec.getP());
+ out.writeObject(dhSpec.getG());
+ out.writeInt(dhSpec.getL());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java
new file mode 100644
index 0000000..4bd7805
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DH objects
+ * objects into their org.bouncycastle.crypto counterparts.
+ */
+public class DHUtil
+{
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPublicKey)
+ {
+ DHPublicKey k = (DHPublicKey)key;
+
+ return new DHPublicKeyParameters(k.getY(),
+ new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+ }
+
+ throw new InvalidKeyException("can't identify DH public key.");
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPrivateKey)
+ {
+ DHPrivateKey k = (DHPrivateKey)key;
+
+ return new DHPrivateKeyParameters(k.getX(),
+ new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+ }
+
+ throw new InvalidKeyException("can't identify DH private key.");
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
new file mode 100644
index 0000000..5a66ffb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyAgreementSpi.java
@@ -0,0 +1,211 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.SecretKey;
+import javax.crypto.ShortBufferException;
+import javax.crypto.interfaces.DHPrivateKey;
+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.Strings;
+
+/**
+ * Diffie-Hellman key agreement. There's actually a better way of doing this
+ * if you are using long term public keys, see the light-weight version for
+ * details.
+ */
+public class KeyAgreementSpi
+ extends javax.crypto.KeyAgreementSpi
+{
+ private BigInteger x;
+ private BigInteger p;
+ private BigInteger g;
+ private BigInteger result;
+
+ private static final Hashtable algorithms = new Hashtable();
+
+ static
+ {
+ // BEGIN android-changed
+ Integer i64 = Integer.valueOf(64);
+ Integer i192 = Integer.valueOf(192);
+ Integer i128 = Integer.valueOf(128);
+ Integer i256 = Integer.valueOf(256);
+ // END android-changed
+
+ algorithms.put("DES", i64);
+ algorithms.put("DESEDE", i192);
+ algorithms.put("BLOWFISH", i128);
+ algorithms.put("AES", i256);
+ }
+
+ private byte[] bigIntToBytes(
+ BigInteger r)
+ {
+ byte[] tmp = r.toByteArray();
+
+ if (tmp[0] == 0)
+ {
+ byte[] ntmp = new byte[tmp.length - 1];
+
+ System.arraycopy(tmp, 1, ntmp, 0, ntmp.length);
+ return ntmp;
+ }
+
+ return tmp;
+ }
+
+ protected Key engineDoPhase(
+ Key key,
+ boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException
+ {
+ if (x == null)
+ {
+ throw new IllegalStateException("Diffie-Hellman not initialised.");
+ }
+
+ if (!(key instanceof DHPublicKey))
+ {
+ throw new InvalidKeyException("DHKeyAgreement doPhase requires DHPublicKey");
+ }
+ DHPublicKey pubKey = (DHPublicKey)key;
+
+ if (!pubKey.getParams().getG().equals(g) || !pubKey.getParams().getP().equals(p))
+ {
+ throw new InvalidKeyException("DHPublicKey not for this KeyAgreement!");
+ }
+
+ if (lastPhase)
+ {
+ result = ((DHPublicKey)key).getY().modPow(x, p);
+ return null;
+ }
+ else
+ {
+ result = ((DHPublicKey)key).getY().modPow(x, p);
+ }
+
+ return new BCDHPublicKey(result, pubKey.getParams());
+ }
+
+ protected byte[] engineGenerateSecret()
+ throws IllegalStateException
+ {
+ if (x == null)
+ {
+ throw new IllegalStateException("Diffie-Hellman not initialised.");
+ }
+
+ return bigIntToBytes(result);
+ }
+
+ protected int engineGenerateSecret(
+ byte[] sharedSecret,
+ int offset)
+ throws IllegalStateException, ShortBufferException
+ {
+ if (x == null)
+ {
+ 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;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ String algorithm)
+ {
+ if (x == null)
+ {
+ throw new IllegalStateException("Diffie-Hellman not initialised.");
+ }
+
+ String algKey = Strings.toUpperCase(algorithm);
+ byte[] res = bigIntToBytes(result);
+
+ if (algorithms.containsKey(algKey))
+ {
+ 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(res, algorithm);
+ }
+
+ protected void engineInit(
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ if (!(key instanceof DHPrivateKey))
+ {
+ throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey for initialisation");
+ }
+ DHPrivateKey privKey = (DHPrivateKey)key;
+
+ if (params != null)
+ {
+ if (!(params instanceof DHParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("DHKeyAgreement only accepts DHParameterSpec");
+ }
+ DHParameterSpec p = (DHParameterSpec)params;
+
+ this.p = p.getP();
+ this.g = p.getG();
+ }
+ else
+ {
+ this.p = privKey.getParams().getP();
+ this.g = privKey.getParams().getG();
+ }
+
+ this.x = this.result = privKey.getX();
+ }
+
+ protected void engineInit(
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ if (!(key instanceof DHPrivateKey))
+ {
+ throw new InvalidKeyException("DHKeyAgreement requires DHPrivateKey");
+ }
+
+ DHPrivateKey privKey = (DHPrivateKey)key;
+
+ this.p = privKey.getParams().getP();
+ this.g = privKey.getParams().getG();
+ this.x = this.result = privKey.getX();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
new file mode 100644
index 0000000..9565bd2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyFactorySpi.java
@@ -0,0 +1,128 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(DHPrivateKeySpec.class) && key instanceof DHPrivateKey)
+ {
+ DHPrivateKey k = (DHPrivateKey)key;
+
+ return new DHPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getG());
+ }
+ else if (spec.isAssignableFrom(DHPublicKeySpec.class) && key instanceof DHPublicKey)
+ {
+ DHPublicKey k = (DHPublicKey)key;
+
+ return new DHPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getG());
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPublicKey)
+ {
+ return new BCDHPublicKey((DHPublicKey)key);
+ }
+ else if (key instanceof DHPrivateKey)
+ {
+ return new BCDHPrivateKey((DHPrivateKey)key);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DHPrivateKeySpec)
+ {
+ return new BCDHPrivateKey((DHPrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DHPublicKeySpec)
+ {
+ return new BCDHPublicKey((DHPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ return new BCDHPrivateKey(keyInfo);
+ }
+ else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ return new BCDHPrivateKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ return new BCDHPublicKey(keyInfo);
+ }
+ else if (algOid.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ return new BCDHPublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..69d5703
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi.java
@@ -0,0 +1,106 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dh;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Hashtable;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.DHBasicKeyPairGenerator;
+import org.bouncycastle.crypto.generators.DHParametersGenerator;
+import org.bouncycastle.crypto.params.DHKeyGenerationParameters;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ private static Hashtable params = new Hashtable();
+
+ DHKeyGenerationParameters param;
+ DHBasicKeyPairGenerator engine = new DHBasicKeyPairGenerator();
+ int strength = 1024;
+ int certainty = 20;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("DH");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof DHParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a DHParameterSpec");
+ }
+ DHParameterSpec dhParams = (DHParameterSpec)params;
+
+ param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL()));
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ // BEGIN android-changed
+ Integer paramStrength = Integer.valueOf(strength);
+ // END android-changed
+
+ if (params.containsKey(paramStrength))
+ {
+ param = (DHKeyGenerationParameters)params.get(paramStrength);
+ }
+ else
+ {
+ DHParameterSpec dhParams = BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters();
+
+ if (dhParams != null && dhParams.getP().bitLength() == strength)
+ {
+ param = new DHKeyGenerationParameters(random, new DHParameters(dhParams.getP(), dhParams.getG(), null, dhParams.getL()));
+ }
+ else
+ {
+ DHParametersGenerator pGen = new DHParametersGenerator();
+
+ pGen.init(strength, certainty, random);
+
+ param = new DHKeyGenerationParameters(random, pGen.generateParameters());
+
+ params.put(paramStrength, param);
+ }
+ }
+
+ engine.init(param);
+
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ DHPublicKeyParameters pub = (DHPublicKeyParameters)pair.getPublic();
+ DHPrivateKeyParameters priv = (DHPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCDHPublicKey(pub),
+ new BCDHPrivateKey(priv));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
new file mode 100644
index 0000000..2e5ee56
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParameterGeneratorSpi.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+
+import org.bouncycastle.crypto.generators.DSAParametersGenerator;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+//import org.bouncycastle.jce.spec.GOST3410ParameterSpec;
+//import org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec;
+
+public class AlgorithmParameterGeneratorSpi
+ extends java.security.AlgorithmParameterGeneratorSpi
+{
+ protected SecureRandom random;
+ protected int strength = 1024;
+
+ protected void engineInit(
+ int strength,
+ SecureRandom random)
+ {
+ if (strength < 512 || strength > 1024 || strength % 64 != 0)
+ {
+ throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64");
+ }
+
+ this.strength = strength;
+ this.random = random;
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec genParamSpec,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("No supported AlgorithmParameterSpec for DSA parameter generation.");
+ }
+
+ protected AlgorithmParameters engineGenerateParameters()
+ {
+ DSAParametersGenerator pGen = new DSAParametersGenerator();
+
+ if (random != null)
+ {
+ pGen.init(strength, 20, random);
+ }
+ else
+ {
+ pGen.init(strength, 20, new SecureRandom());
+ }
+
+ DSAParameters p = pGen.generateParameters();
+
+ AlgorithmParameters params;
+
+ try
+ {
+ params = AlgorithmParameters.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
+ params.init(new DSAParameterSpec(p.getP(), p.getQ(), p.getG()));
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+
+ return params;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..6dfb8fb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/AlgorithmParametersSpi.java
@@ -0,0 +1,133 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x509.DSAParameter;
+
+public class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ DSAParameterSpec currentSpec;
+
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ /**
+ * Return the X.509 ASN.1 structure DSAParameter.
+ * <p/>
+ * <pre>
+ * DSAParameter ::= SEQUENCE {
+ * prime INTEGER, -- p
+ * subprime INTEGER, -- q
+ * base INTEGER, -- g}
+ * </pre>
+ */
+ protected byte[] engineGetEncoded()
+ {
+ DSAParameter dsaP = new DSAParameter(currentSpec.getP(), currentSpec.getQ(), currentSpec.getG());
+
+ try
+ {
+ return dsaP.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding DSAParameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == DSAParameterSpec.class)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to DSA parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof DSAParameterSpec))
+ {
+ throw new InvalidParameterSpecException("DSAParameterSpec required to initialise a DSA algorithm parameters object");
+ }
+
+ this.currentSpec = (DSAParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ DSAParameter dsaP = new DSAParameter((ASN1Sequence)ASN1Primitive.fromByteArray(params));
+
+ currentSpec = new DSAParameterSpec(dsaP.getP(), dsaP.getQ(), dsaP.getG());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid DSA Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid DSA Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "DSA Parameters";
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java
new file mode 100644
index 0000000..f67d12d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java
@@ -0,0 +1,168 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class BCDSAPrivateKey
+ implements DSAPrivateKey, PKCS12BagAttributeCarrier
+{
+ private static final long serialVersionUID = -4677259546958385734L;
+
+ private BigInteger x;
+ private transient DSAParams dsaSpec;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCDSAPrivateKey()
+ {
+ }
+
+ BCDSAPrivateKey(
+ DSAPrivateKey key)
+ {
+ this.x = key.getX();
+ this.dsaSpec = key.getParams();
+ }
+
+ BCDSAPrivateKey(
+ DSAPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+ }
+
+ public BCDSAPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ DSAParameter params = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+ ASN1Integer derX = (ASN1Integer)info.parsePrivateKey();
+
+ this.x = derX.getValue();
+ this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+ }
+
+ BCDSAPrivateKey(
+ DSAPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DSA";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).toASN1Primitive()), new ASN1Integer(getX()));
+ }
+
+ public DSAParams getParams()
+ {
+ return dsaSpec;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAPrivateKey))
+ {
+ return false;
+ }
+
+ DSAPrivateKey other = (DSAPrivateKey)o;
+
+ return this.getX().equals(other.getX())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getQ().equals(other.getParams().getQ());
+ }
+
+ public int hashCode()
+ {
+ return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(dsaSpec.getP());
+ out.writeObject(dsaSpec.getQ());
+ out.writeObject(dsaSpec.getG());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
new file mode 100644
index 0000000..e66330b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java
@@ -0,0 +1,171 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+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.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCDSAPublicKey
+ implements DSAPublicKey
+{
+ private static final long serialVersionUID = 1752452449903495175L;
+
+ private BigInteger y;
+ private transient DSAParams dsaSpec;
+
+ BCDSAPublicKey(
+ DSAPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+ }
+
+ BCDSAPublicKey(
+ DSAPublicKey key)
+ {
+ this.y = key.getY();
+ this.dsaSpec = key.getParams();
+ }
+
+ BCDSAPublicKey(
+ DSAPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+ }
+
+ BCDSAPublicKey(
+ BigInteger y,
+ DSAParameterSpec dsaSpec)
+ {
+ this.y = y;
+ this.dsaSpec = dsaSpec;
+ }
+
+ public BCDSAPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+
+ ASN1Integer derY;
+
+ try
+ {
+ derY = (ASN1Integer)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DSA public key");
+ }
+
+ this.y = derY.getValue();
+
+ if (isNotNull(info.getAlgorithm().getParameters()))
+ {
+ DSAParameter params = DSAParameter.getInstance(info.getAlgorithm().getParameters());
+
+ this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+ }
+ }
+
+ private boolean isNotNull(ASN1Encodable parameters)
+ {
+ return parameters != null && !DERNull.INSTANCE.equals(parameters.toASN1Primitive());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DSA";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (dsaSpec == null)
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(y));
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG()).toASN1Primitive()), new ASN1Integer(y));
+ }
+
+ public DSAParams getParams()
+ {
+ return dsaSpec;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("DSA Public Key").append(nl);
+ buf.append(" y: ").append(this.getY().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+
+ public int hashCode()
+ {
+ return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAPublicKey))
+ {
+ return false;
+ }
+
+ DSAPublicKey other = (DSAPublicKey)o;
+
+ return this.getY().equals(other.getY())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getQ().equals(other.getParams().getQ());
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(dsaSpec.getP());
+ out.writeObject(dsaSpec.getQ());
+ out.writeObject(dsaSpec.getG());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
new file mode 100644
index 0000000..d9d5857
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java
@@ -0,0 +1,288 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.DSAKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.NullDigest;
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-added
+// BEGIN 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;
+// END android-removed
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+
+public class DSASigner
+ extends SignatureSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ private Digest digest;
+ private DSA signer;
+ private SecureRandom random;
+
+ protected DSASigner(
+ Digest digest,
+ DSA signer)
+ {
+ this.digest = digest;
+ this.signer = signer;
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+// if (publicKey instanceof GOST3410Key)
+// {
+// param = GOST3410Util.generatePublicKeyParameter(publicKey);
+// }
+// else if (publicKey instanceof DSAKey)
+ if (publicKey instanceof DSAKey)
+ {
+ param = DSAUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = new BCDSAPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof DSAKey)
+ {
+ param = DSAUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in DSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ this.random = random;
+ engineInitSign(privateKey);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+// if (privateKey instanceof GOST3410Key)
+// {
+// param = GOST3410Util.generatePrivateKeyParameter(privateKey);
+// }
+// else
+// {
+ param = DSAUtil.generatePrivateKeyParameter(privateKey);
+// }
+
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ digest.reset();
+ signer.init(true, param);
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = signer.generateSignature(hash);
+
+ return derEncode(sig[0], sig[1]);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ sig = derDecode(sigBytes);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ private byte[] derEncode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ ASN1Integer[] rs = new ASN1Integer[]{ new ASN1Integer(r), new ASN1Integer(s) };
+ return new DERSequence(rs).getEncoded(ASN1Encoding.DER);
+ }
+
+ private BigInteger[] derDecode(
+ byte[] encoding)
+ throws IOException
+ {
+ ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+ return new BigInteger[]{
+ ((ASN1Integer)s.getObjectAt(0)).getValue(),
+ ((ASN1Integer)s.getObjectAt(1)).getValue()
+ };
+ }
+
+ static public class stdDSA
+ extends DSASigner
+ {
+ public stdDSA()
+ {
+ // BEGIN android-changed
+ super(AndroidDigestFactory.getSHA1(), new org.bouncycastle.crypto.signers.DSASigner());
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // static public class dsa224
+ // extends DSASigner
+ // {
+ // public dsa224()
+ // {
+ // super(new SHA224Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+ // }
+ // }
+ //
+ // static public class dsa256
+ // extends DSASigner
+ // {
+ // public dsa256()
+ // {
+ // super(new SHA256Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+ // }
+ // }
+ //
+ // static public class dsa384
+ // extends DSASigner
+ // {
+ // public dsa384()
+ // {
+ // super(new SHA384Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+ // }
+ // }
+ //
+ // static public class dsa512
+ // extends DSASigner
+ // {
+ // public dsa512()
+ // {
+ // super(new SHA512Digest(), new org.bouncycastle.crypto.signers.DSASigner());
+ // }
+ // }
+ // END android-removed
+
+ static public class noneDSA
+ extends DSASigner
+ {
+ public noneDSA()
+ {
+ super(new NullDigest(), new org.bouncycastle.crypto.signers.DSASigner());
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
new file mode 100644
index 0000000..5e940ec
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DSA objects
+ * objects into their org.bouncycastle.crypto counterparts.
+ */
+public class DSAUtil
+{
+ public static final ASN1ObjectIdentifier[] dsaOids =
+ {
+ X9ObjectIdentifiers.id_dsa,
+ OIWObjectIdentifiers.dsaWithSHA1
+ };
+
+ public static boolean isDsaOid(
+ ASN1ObjectIdentifier algOid)
+ {
+ for (int i = 0; i != dsaOids.length; i++)
+ {
+ if (algOid.equals(dsaOids[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DSAPublicKey)
+ {
+ DSAPublicKey k = (DSAPublicKey)key;
+
+ return new DSAPublicKeyParameters(k.getY(),
+ new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()));
+ }
+
+ throw new InvalidKeyException("can't identify DSA public key: " + key.getClass().getName());
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DSAPrivateKey)
+ {
+ DSAPrivateKey k = (DSAPrivateKey)key;
+
+ return new DSAPrivateKeyParameters(k.getX(),
+ new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()));
+ }
+
+ throw new InvalidKeyException("can't identify DSA private key.");
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
new file mode 100644
index 0000000..a36f3dd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java
@@ -0,0 +1,117 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(DSAPublicKeySpec.class) && key instanceof DSAPublicKey)
+ {
+ DSAPublicKey k = (DSAPublicKey)key;
+
+ return new DSAPublicKeySpec(k.getY(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+ }
+ else if (spec.isAssignableFrom(DSAPrivateKeySpec.class) && key instanceof java.security.interfaces.DSAPrivateKey)
+ {
+ java.security.interfaces.DSAPrivateKey k = (java.security.interfaces.DSAPrivateKey)key;
+
+ return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG());
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DSAPublicKey)
+ {
+ return new BCDSAPublicKey((DSAPublicKey)key);
+ }
+ else if (key instanceof DSAPrivateKey)
+ {
+ return new BCDSAPrivateKey((DSAPrivateKey)key);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (DSAUtil.isDsaOid(algOid))
+ {
+ return new BCDSAPrivateKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (DSAUtil.isDsaOid(algOid))
+ {
+ return new BCDSAPublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DSAPrivateKeySpec)
+ {
+ return new BCDSAPrivateKey((DSAPrivateKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DSAPublicKeySpec)
+ {
+ return new BCDSAPublicKey((DSAPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..c6ddf9b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.jcajce.provider.asymmetric.dsa;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.DSAParameterSpec;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
+import org.bouncycastle.crypto.generators.DSAParametersGenerator;
+import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ DSAKeyGenerationParameters param;
+ DSAKeyPairGenerator engine = new DSAKeyPairGenerator();
+ int strength = 1024;
+ int certainty = 20;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("DSA");
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ if (strength < 512 || strength > 1024 || strength % 64 != 0)
+ {
+ throw new InvalidParameterException("strength must be from 512 - 1024 and a multiple of 64");
+ }
+
+ this.strength = strength;
+ this.random = random;
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof DSAParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a DSAParameterSpec");
+ }
+ DSAParameterSpec dsaParams = (DSAParameterSpec)params;
+
+ param = new DSAKeyGenerationParameters(random, new DSAParameters(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()));
+
+ engine.init(param);
+ initialised = true;
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ DSAParametersGenerator pGen = new DSAParametersGenerator();
+
+ pGen.init(strength, certainty, random);
+ param = new DSAKeyGenerationParameters(random, pGen.generateParameters());
+ engine.init(param);
+ initialised = true;
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ DSAPublicKeyParameters pub = (DSAPublicKeyParameters)pair.getPublic();
+ DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCDSAPublicKey(pub),
+ new BCDSAPrivateKey(priv));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
new file mode 100644
index 0000000..d3f1675
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java
@@ -0,0 +1,500 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
+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;
+// END android-removed
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jce.interfaces.ECPointEncoder;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class BCECPrivateKey
+ implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ static final long serialVersionUID = 994553197664784084L;
+
+ private String algorithm = "EC";
+ private boolean withCompression;
+
+ private transient BigInteger d;
+ private transient ECParameterSpec ecSpec;
+ private transient ProviderConfiguration configuration;
+ private transient DERBitString publicKey;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCECPrivateKey()
+ {
+ }
+
+ public BCECPrivateKey(
+ ECPrivateKey key,
+ ProviderConfiguration configuration)
+ {
+ this.d = key.getS();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ org.bouncycastle.jce.spec.ECPrivateKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getD();
+
+ if (spec.getParams() != null) // can be null if implicitlyCA
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve;
+
+ ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ this.ecSpec = null;
+ }
+
+ this.configuration = configuration;
+ }
+
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getS();
+ this.ecSpec = spec.getParams();
+ this.configuration = configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ BCECPrivateKey key)
+ {
+ this.algorithm = algorithm;
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.attrCarrier = key.attrCarrier;
+ this.publicKey = key.publicKey;
+ this.configuration = key.configuration;
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECPublicKey pubKey,
+ ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.configuration = configuration;
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getX().toBigInteger(),
+ dp.getG().getY().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ BCECPublicKey pubKey,
+ org.bouncycastle.jce.spec.ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.configuration = configuration;
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getX().toBigInteger(),
+ dp.getG().getY().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getX().toBigInteger(),
+ spec.getG().getY().toBigInteger()),
+ spec.getN(),
+ spec.getH().intValue());
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public BCECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ this.configuration = configuration;
+ }
+
+ BCECPrivateKey(
+ String algorithm,
+ PrivateKeyInfo info,
+ ProviderConfiguration configuration)
+ throws IOException
+ {
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ populateFromPrivKeyInfo(info);
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ throws IOException
+ {
+ X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ // BEGIN android-removed
+ // if (ecP == null) // GOST Curve
+ // {
+ // ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
+ // EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
+ //
+ // ecSpec = new ECNamedCurveSpec(
+ // ECGOST3410NamedCurves.getName(oid),
+ // ellipticCurve,
+ // new ECPoint(
+ // gParam.getG().getX().toBigInteger(),
+ // gParam.getG().getY().toBigInteger()),
+ // gParam.getN(),
+ // gParam.getH());
+ // }
+ // else
+ // END android-removed
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECUtil.getCurveName(oid),
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getX().toBigInteger(),
+ ecP.getG().getY().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().getX().toBigInteger(),
+ ecP.getG().getY().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ ASN1Encodable privKey = info.parsePrivateKey();
+ if (privKey instanceof DERInteger)
+ {
+ DERInteger derD = DERInteger.getInstance(privKey);
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ org.bouncycastle.asn1.sec.ECPrivateKey ec = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(privKey);
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ X962Parameters params;
+
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null) // guess it's the OID
+ {
+ curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ org.bouncycastle.asn1.sec.ECPrivateKey keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(this.getS(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new org.bouncycastle.asn1.sec.ECPrivateKey(this.getS(), params);
+ }
+
+ try
+ {
+ // BEGIN android-removed
+ // if (algorithm.equals("ECGOST3410"))
+ // {
+ // info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+ // }
+ // else
+ // END android-removed
+ {
+
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+ }
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null)
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return configuration.getEcImplicitlyCa();
+ }
+
+ public BigInteger getS()
+ {
+ return d;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECPrivateKey))
+ {
+ return false;
+ }
+
+ BCECPrivateKey other = (BCECPrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Private Key").append(nl);
+ buf.append(" S: ").append(this.d.toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ private DERBitString getPublicKeyDetails(BCECPublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
new file mode 100644
index 0000000..14cc9dc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java
@@ -0,0 +1,443 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECPoint;
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jce.interfaces.ECPointEncoder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class BCECPublicKey
+ implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+ static final long serialVersionUID = 2422789860422731812L;
+
+ private String algorithm = "EC";
+ private boolean withCompression;
+
+ private transient org.bouncycastle.math.ec.ECPoint q;
+ private transient ECParameterSpec ecSpec;
+ private transient ProviderConfiguration configuration;
+
+ public BCECPublicKey(
+ String algorithm,
+ BCECPublicKey key)
+ {
+ this.algorithm = algorithm;
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.configuration = key.configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.ecSpec = spec.getParams();
+ this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+ this.configuration = configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ org.bouncycastle.jce.spec.ECPublicKeySpec spec,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = spec.getQ();
+
+ if (spec.getParams() != null) // can be null if implictlyCa
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.bouncycastle.jce.spec.ECParameterSpec s = configuration.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+ }
+ this.ecSpec = null;
+ }
+
+ this.configuration = configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ this.configuration = configuration;
+ }
+
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ org.bouncycastle.jce.spec.ECParameterSpec spec,
+ ProviderConfiguration configuration)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+ }
+
+ this.configuration = configuration;
+ }
+
+ /*
+ * called for implicitCA
+ */
+ public BCECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ this.configuration = configuration;
+ }
+
+ public BCECPublicKey(
+ ECPublicKey key,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+ }
+
+ BCECPublicKey(
+ String algorithm,
+ SubjectPublicKeyInfo info,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ populateFromPubKeyInfo(info);
+ }
+
+ private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+ {
+ return new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getX().toBigInteger(),
+ dp.getG().getY().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+
+ 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().getX().toBigInteger(),
+ ecP.getG().getY().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().getX().toBigInteger(),
+ ecP.getG().getY().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ DERBitString bits = info.getPublicKeyData();
+ byte[] data = bits.getBytes();
+ ASN1OctetString key = new DEROctetString(data);
+
+ //
+ // extra octet string - one of our old certs...
+ //
+ if (data[0] == 0x04 && data[1] == data.length - 2
+ && (data[2] == 0x02 || data[2] == 0x03))
+ {
+ int qLength = new X9IntegerConverter().getByteLength(curve);
+
+ if (qLength >= data.length - 3)
+ {
+ try
+ {
+ key = (ASN1OctetString) ASN1Primitive.fromByteArray(data);
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+ }
+ }
+ X9ECPoint derQ = new X9ECPoint(curve, key);
+
+ this.q = derQ.getPoint();
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ ASN1Encodable params;
+ SubjectPublicKeyInfo info;
+
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null)
+ {
+ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECCurve curve = this.engineGetQ().getCurve();
+ ASN1OctetString p = (ASN1OctetString)
+ new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive();
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
+ {
+ byte[] val = bI.toByteArray();
+ if (val.length < 32)
+ {
+ byte[] tmp = new byte[32];
+ System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
+ val = tmp;
+ }
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[offSet + i] = val[val.length - 1 - i];
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null) // implictlyCA
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ public ECPoint getW()
+ {
+ return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger());
+ }
+
+ public org.bouncycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+ }
+ else
+ {
+ return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+ }
+ }
+
+ return q;
+ }
+
+ public org.bouncycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return configuration.getEcImplicitlyCa();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof BCECPublicKey))
+ {
+ return false;
+ }
+
+ BCECPublicKey other = (BCECPublicKey)o;
+
+ return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+
+ out.writeObject(this.getEncoded());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/EC5Util.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/EC5Util.java
new file mode 100644
index 0000000..38025e7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/EC5Util.java
@@ -0,0 +1,123 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.spec.ECField;
+import java.security.spec.ECFieldF2m;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+
+import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class EC5Util
+{
+ public static EllipticCurve convertCurve(
+ ECCurve curve,
+ byte[] seed)
+ {
+ // 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)
+ {
+ return new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null);
+ }
+ else
+ {
+ 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(), null);
+ }
+ 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);
+ }
+ }
+ }
+
+ public static ECCurve convertCurve(
+ EllipticCurve ec)
+ {
+ ECField field = ec.getField();
+ BigInteger a = ec.getA();
+ BigInteger b = ec.getB();
+
+ if (field instanceof ECFieldFp)
+ {
+ return new ECCurve.Fp(((ECFieldFp)field).getP(), a, b);
+ }
+ else
+ {
+ ECFieldF2m fieldF2m = (ECFieldF2m)field;
+ int m = fieldF2m.getM();
+ int ks[] = ECUtil.convertMidTerms(fieldF2m.getMidTermsOfReductionPolynomial());
+ return new ECCurve.F2m(m, ks[0], ks[1], ks[2], a, b);
+ }
+ }
+
+ public static ECParameterSpec convertSpec(
+ EllipticCurve ellipticCurve,
+ org.bouncycastle.jce.spec.ECParameterSpec spec)
+ {
+ if (spec instanceof ECNamedCurveParameterSpec)
+ {
+ return new ECNamedCurveSpec(
+ ((ECNamedCurveParameterSpec)spec).getName(),
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getX().toBigInteger(),
+ spec.getG().getY().toBigInteger()),
+ spec.getN(),
+ spec.getH());
+ }
+ else
+ {
+ return new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getX().toBigInteger(),
+ spec.getG().getY().toBigInteger()),
+ spec.getN(),
+ spec.getH().intValue());
+ }
+ }
+
+ public static org.bouncycastle.jce.spec.ECParameterSpec convertSpec(
+ ECParameterSpec ecSpec,
+ boolean withCompression)
+ {
+ ECCurve curve = convertCurve(ecSpec.getCurve());
+
+ return new org.bouncycastle.jce.spec.ECParameterSpec(
+ curve,
+ convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+ }
+
+ public static org.bouncycastle.math.ec.ECPoint convertPoint(
+ ECParameterSpec ecSpec,
+ ECPoint point,
+ boolean withCompression)
+ {
+ return convertPoint(convertCurve(ecSpec.getCurve()), point, withCompression);
+ }
+
+ public static org.bouncycastle.math.ec.ECPoint convertPoint(
+ ECCurve curve,
+ ECPoint point,
+ boolean withCompression)
+ {
+ return curve.createPoint(point.getAffineX(), point.getAffineY(), withCompression);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java
new file mode 100644
index 0000000..80ff2af
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtil.java
@@ -0,0 +1,237 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.jce.interfaces.ECPrivateKey;
+import org.bouncycastle.jce.interfaces.ECPublicKey;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+
+/**
+ * utility class for converting jce/jca ECDSA, ECDH, and ECDHC
+ * objects into their org.bouncycastle.crypto counterparts.
+ */
+public class ECUtil
+{
+ /**
+ * Returns a sorted array of middle terms of the reduction polynomial.
+ * @param k The unsorted array of middle terms of the reduction polynomial
+ * of length 1 or 3.
+ * @return the sorted array of middle terms of the reduction polynomial.
+ * This array always has length 3.
+ */
+ static int[] convertMidTerms(
+ int[] k)
+ {
+ int[] res = new int[3];
+
+ if (k.length == 1)
+ {
+ res[0] = k[0];
+ }
+ else
+ {
+ if (k.length != 3)
+ {
+ throw new IllegalArgumentException("Only Trinomials and pentanomials supported");
+ }
+
+ if (k[0] < k[1] && k[0] < k[2])
+ {
+ res[0] = k[0];
+ if (k[1] < k[2])
+ {
+ res[1] = k[1];
+ res[2] = k[2];
+ }
+ else
+ {
+ res[1] = k[2];
+ res[2] = k[1];
+ }
+ }
+ else if (k[1] < k[2])
+ {
+ res[0] = k[1];
+ if (k[0] < k[2])
+ {
+ res[1] = k[0];
+ res[2] = k[2];
+ }
+ else
+ {
+ res[1] = k[2];
+ res[2] = k[0];
+ }
+ }
+ else
+ {
+ res[0] = k[2];
+ if (k[0] < k[1])
+ {
+ res[1] = k[0];
+ res[2] = k[1];
+ }
+ else
+ {
+ res[1] = k[1];
+ res[2] = k[0];
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public static AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ ECParameterSpec s = k.getParameters();
+
+ if (s == null)
+ {
+ s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new ECPublicKeyParameters(
+ ((BCECPublicKey)k).engineGetQ(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ else
+ {
+ return new ECPublicKeyParameters(
+ k.getQ(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+ }
+ else if (key instanceof java.security.interfaces.ECPublicKey)
+ {
+ java.security.interfaces.ECPublicKey pubKey = (java.security.interfaces.ECPublicKey)key;
+ ECParameterSpec s = EC5Util.convertSpec(pubKey.getParams(), false);
+ return new ECPublicKeyParameters(
+ EC5Util.convertPoint(pubKey.getParams(), pubKey.getW(), false),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+
+ throw new InvalidKeyException("cannot identify EC public key.");
+ }
+
+ public static AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+ ECParameterSpec s = k.getParameters();
+
+ if (s == null)
+ {
+ s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ return new ECPrivateKeyParameters(
+ k.getD(),
+ new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed()));
+ }
+
+ throw new InvalidKeyException("can't identify EC private key.");
+ }
+
+ public static ASN1ObjectIdentifier getNamedCurveOid(
+ String name)
+ {
+ ASN1ObjectIdentifier oid = X962NamedCurves.getOID(name);
+
+ if (oid == null)
+ {
+ oid = SECNamedCurves.getOID(name);
+ if (oid == null)
+ {
+ oid = NISTNamedCurves.getOID(name);
+ }
+ // BEGIN android-removed
+ // if (oid == null)
+ // {
+ // oid = TeleTrusTNamedCurves.getOID(name);
+ // }
+ // if (oid == null)
+ // {
+ // oid = ECGOST3410NamedCurves.getOID(name);
+ // }
+ // END android-removed
+ }
+
+ return oid;
+ }
+
+ public static X9ECParameters getNamedCurveByOid(
+ ASN1ObjectIdentifier oid)
+ {
+ X9ECParameters params = X962NamedCurves.getByOID(oid);
+
+ if (params == null)
+ {
+ params = SECNamedCurves.getByOID(oid);
+ if (params == null)
+ {
+ params = NISTNamedCurves.getByOID(oid);
+ }
+ // BEGIN android-removed
+ // if (params == null)
+ // {
+ // params = TeleTrusTNamedCurves.getByOID(oid);
+ // }
+ // END android-removed
+ }
+
+ return params;
+ }
+
+ public static String getCurveName(
+ ASN1ObjectIdentifier oid)
+ {
+ String name = X962NamedCurves.getName(oid);
+
+ if (name == null)
+ {
+ name = SECNamedCurves.getName(oid);
+ if (name == null)
+ {
+ name = NISTNamedCurves.getName(oid);
+ }
+ // BEGIN android-removed
+ // if (name == null)
+ // {
+ // name = TeleTrusTNamedCurves.getName(oid);
+ // }
+ // if (name == null)
+ // {
+ // name = ECGOST3410NamedCurves.getName(oid);
+ // }
+ // END android-removed
+ }
+
+ return name;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
new file mode 100644
index 0000000..38a7143
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java
@@ -0,0 +1,337 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+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.DERObjectIdentifier;
+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;
+import org.bouncycastle.crypto.DerivationFunction;
+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;
+// END android-removed
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.MQVPrivateParameters;
+// import org.bouncycastle.crypto.params.MQVPublicParameters;
+// END android-removed
+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
+
+/**
+ * Diffie-Hellman key agreement using elliptic curve keys, ala IEEE P1363
+ * both the simple one, and the simple one with cofactors are supported.
+ *
+ * Also, MQV key agreement per SEC-1
+ */
+public class KeyAgreementSpi
+ extends javax.crypto.KeyAgreementSpi
+{
+ private static final X9IntegerConverter converter = new X9IntegerConverter();
+ private static final Hashtable algorithms = new Hashtable();
+
+ static
+ {
+ // BEGIN android-changed
+ Integer i128 = Integer.valueOf(128);
+ Integer i192 = Integer.valueOf(192);
+ Integer i256 = Integer.valueOf(256);
+ // END android-changed
+
+ 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;
+ // END android-removed
+
+ private byte[] bigIntToBytes(
+ BigInteger r)
+ {
+ return converter.integerToBytes(r, converter.getByteLength(parameters.getG().getX()));
+ }
+
+ protected KeyAgreementSpi(
+ String kaAlgorithm,
+ BasicAgreement agreement,
+ DerivationFunction kdf)
+ {
+ this.kaAlgorithm = kaAlgorithm;
+ this.agreement = agreement;
+ // BEGIN android-removed
+ // this.kdf = kdf;
+ // END android-removed
+ }
+
+ protected Key engineDoPhase(
+ Key key,
+ boolean lastPhase)
+ throws InvalidKeyException, IllegalStateException
+ {
+ if (parameters == null)
+ {
+ throw new IllegalStateException(kaAlgorithm + " not initialised.");
+ }
+
+ if (!lastPhase)
+ {
+ throw new IllegalStateException(kaAlgorithm + " can only be between two parties.");
+ }
+
+ CipherParameters pubKey;
+ // BEGIN android-removed
+ // if (agreement instanceof ECMQVBasicAgreement)
+ // {
+ // if (!(key instanceof MQVPublicKey))
+ // {
+ // throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ // + getSimpleName(MQVPublicKey.class) + " for doPhase");
+ // }
+ //
+ // MQVPublicKey mqvPubKey = (MQVPublicKey)key;
+ // ECPublicKeyParameters staticKey = (ECPublicKeyParameters)
+ // ECUtil.generatePublicKeyParameter(mqvPubKey.getStaticKey());
+ // ECPublicKeyParameters ephemKey = (ECPublicKeyParameters)
+ // ECUtil.generatePublicKeyParameter(mqvPubKey.getEphemeralKey());
+ //
+ // pubKey = new MQVPublicParameters(staticKey, ephemKey);
+ //
+ // // TODO Validate that all the keys are using the same parameters?
+ // }
+ // else
+ // END android-removed
+ {
+ if (!(key instanceof ECPublicKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPublicKey.class) + " for doPhase");
+ }
+
+ pubKey = ECUtil.generatePublicKeyParameter((PublicKey)key);
+
+ // TODO Validate that all the keys are using the same parameters?
+ }
+
+ result = agreement.calculateAgreement(pubKey);
+
+ 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 DERObjectIdentifier(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
+ {
+ initFromKey(key);
+ }
+
+ protected void engineInit(
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ initFromKey(key);
+ }
+
+ private void initFromKey(Key key)
+ throws InvalidKeyException
+ {
+ // BEGIN android-removed
+ // if (agreement instanceof ECMQVBasicAgreement)
+ // {
+ // if (!(key instanceof MQVPrivateKey))
+ // {
+ // throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ // + getSimpleName(MQVPrivateKey.class) + " for initialisation");
+ // }
+ //
+ // MQVPrivateKey mqvPrivKey = (MQVPrivateKey)key;
+ // ECPrivateKeyParameters staticPrivKey = (ECPrivateKeyParameters)
+ // ECUtil.generatePrivateKeyParameter(mqvPrivKey.getStaticPrivateKey());
+ // ECPrivateKeyParameters ephemPrivKey = (ECPrivateKeyParameters)
+ // ECUtil.generatePrivateKeyParameter(mqvPrivKey.getEphemeralPrivateKey());
+ //
+ // ECPublicKeyParameters ephemPubKey = null;
+ // if (mqvPrivKey.getEphemeralPublicKey() != null)
+ // {
+ // ephemPubKey = (ECPublicKeyParameters)
+ // ECUtil.generatePublicKeyParameter(mqvPrivKey.getEphemeralPublicKey());
+ // }
+ //
+ // MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey);
+ // this.parameters = staticPrivKey.getParameters();
+ //
+ // // TODO Validate that all the keys are using the same parameters?
+ //
+ // agreement.init(localParams);
+ // }
+ // else
+ // END android-removed
+ {
+ if (!(key instanceof ECPrivateKey))
+ {
+ throw new InvalidKeyException(kaAlgorithm + " key agreement requires "
+ + getSimpleName(ECPrivateKey.class) + " for initialisation");
+ }
+
+ ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)ECUtil.generatePrivateKeyParameter((PrivateKey)key);
+ this.parameters = privKey.getParameters();
+
+ agreement.init(privKey);
+ }
+ }
+
+ private static String getSimpleName(Class clazz)
+ {
+ String fullName = clazz.getName();
+
+ return fullName.substring(fullName.lastIndexOf('.') + 1);
+ }
+
+ public static class DH
+ extends KeyAgreementSpi
+ {
+ public DH()
+ {
+ super("ECDH", new ECDHBasicAgreement(), null);
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class DHC
+ // extends KeyAgreementSpi
+ // {
+ // public DHC()
+ // {
+ // super("ECDHC", new ECDHCBasicAgreement(), null);
+ // }
+ // }
+ //
+ // public static class MQV
+ // extends KeyAgreementSpi
+ // {
+ // public MQV()
+ // {
+ // super("ECMQV", new ECMQVBasicAgreement(), null);
+ // }
+ // }
+ //
+ // public static class DHwithSHA1KDF
+ // extends KeyAgreementSpi
+ // {
+ // public DHwithSHA1KDF()
+ // {
+ // super("ECDHwithSHA1KDF", new ECDHBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ // }
+ // }
+ //
+ // public static class MQVwithSHA1KDF
+ // extends KeyAgreementSpi
+ // {
+ // public MQVwithSHA1KDF()
+ // {
+ // super("ECMQVwithSHA1KDF", new ECMQVBasicAgreement(), new ECDHKEKGenerator(new SHA1Digest()));
+ // }
+ // }
+ // END android-removed
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
new file mode 100644
index 0000000..156b1d0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java
@@ -0,0 +1,240 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.bouncycastle.jce.spec.ECPrivateKeySpec;
+import org.bouncycastle.jce.spec.ECPublicKeySpec;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ String algorithm;
+ ProviderConfiguration configuration;
+
+ KeyFactorySpi(
+ String algorithm,
+ ProviderConfiguration configuration)
+ {
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof ECPublicKey)
+ {
+ return new BCECPublicKey((ECPublicKey)key, configuration);
+ }
+ else if (key instanceof ECPrivateKey)
+ {
+ return new BCECPrivateKey((ECPrivateKey)key, configuration);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+ }
+ }
+ else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams());
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec));
+ }
+ }
+ else if (spec.isAssignableFrom(org.bouncycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey)
+ {
+ ECPublicKey k = (ECPublicKey)key;
+ if (k.getParams() != null)
+ {
+ return new org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false));
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec);
+ }
+ }
+ else if (spec.isAssignableFrom(org.bouncycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey)
+ {
+ ECPrivateKey k = (ECPrivateKey)key;
+
+ if (k.getParams() != null)
+ {
+ return new org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false));
+ }
+ else
+ {
+ ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ return new org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec);
+ }
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPrivateKeySpec)
+ {
+ return new BCECPrivateKey(algorithm, (ECPrivateKeySpec)keySpec, configuration);
+ }
+ else if (keySpec instanceof java.security.spec.ECPrivateKeySpec)
+ {
+ return new BCECPrivateKey(algorithm, (java.security.spec.ECPrivateKeySpec)keySpec, configuration);
+ }
+
+ return super.engineGeneratePrivate(keySpec);
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof ECPublicKeySpec)
+ {
+ return new BCECPublicKey(algorithm, (ECPublicKeySpec)keySpec, configuration);
+ }
+ else if (keySpec instanceof java.security.spec.ECPublicKeySpec)
+ {
+ return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ return new BCECPrivateKey(algorithm, keyInfo, configuration);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (algOid.equals(X9ObjectIdentifiers.id_ecPublicKey))
+ {
+ return new BCECPublicKey(algorithm, keyInfo, configuration);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public static class EC
+ extends KeyFactorySpi
+ {
+ public EC()
+ {
+ super("EC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDSA
+ extends KeyFactorySpi
+ {
+ public ECDSA()
+ {
+ super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class ECGOST3410
+ // extends KeyFactorySpi
+ // {
+ // public ECGOST3410()
+ // {
+ // super("ECGOST3410", BouncyCastleProvider.CONFIGURATION);
+ // }
+ // }
+ // END android-removed
+
+ public static class ECDH
+ extends KeyFactorySpi
+ {
+ public ECDH()
+ {
+ super("ECDH", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDHC
+ extends KeyFactorySpi
+ {
+ public ECDHC()
+ {
+ super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECMQV
+ extends KeyFactorySpi
+ {
+ public ECMQV()
+ {
+ super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+} \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..31090ae
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java
@@ -0,0 +1,329 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.util.Hashtable;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+public abstract class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ public KeyPairGeneratorSpi(String algorithmName)
+ {
+ super(algorithmName);
+ }
+
+ public static class EC
+ extends KeyPairGeneratorSpi
+ {
+ ECKeyGenerationParameters param;
+ ECKeyPairGenerator engine = new ECKeyPairGenerator();
+ Object ecParams = null;
+ int strength = 239;
+ int certainty = 50;
+ SecureRandom random = new SecureRandom();
+ boolean initialised = false;
+ String algorithm;
+ ProviderConfiguration configuration;
+
+ static private Hashtable ecParameters;
+
+ static {
+ ecParameters = new Hashtable();
+
+ // BEGIN android-changed
+ ecParameters.put(Integer.valueOf(192), new ECGenParameterSpec("prime192v1")); // a.k.a P-192
+ ecParameters.put(Integer.valueOf(239), new ECGenParameterSpec("prime239v1"));
+ ecParameters.put(Integer.valueOf(256), new ECGenParameterSpec("prime256v1")); // a.k.a P-256
+
+ ecParameters.put(Integer.valueOf(224), new ECGenParameterSpec("P-224"));
+ ecParameters.put(Integer.valueOf(384), new ECGenParameterSpec("P-384"));
+ ecParameters.put(Integer.valueOf(521), new ECGenParameterSpec("P-521"));
+ // END android-changed
+ }
+
+ public EC()
+ {
+ super("EC");
+ this.algorithm = "EC";
+ this.configuration = BouncyCastleProvider.CONFIGURATION;
+ }
+
+ public EC(
+ String algorithm,
+ ProviderConfiguration configuration)
+ {
+ super(algorithm);
+ this.algorithm = algorithm;
+ this.configuration = configuration;
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ // BEGIN android-added
+ if (random != null) {
+ // END android-added
+ this.random = random;
+ // BEGIN android-added
+ }
+ // END android-added
+ // BEGIN android-changed
+ ECGenParameterSpec ecParams = (ECGenParameterSpec)ecParameters.get(Integer.valueOf(strength));
+ // END android-changed
+
+ if (ecParams != null)
+ {
+ try
+ {
+ initialize(ecParams, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new InvalidParameterException("key size not configurable.");
+ }
+ }
+ else
+ {
+ throw new InvalidParameterException("unknown key size.");
+ }
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ // BEGIN android-added
+ if (random == null) {
+ random = this.random;
+ }
+ // END android-added
+ if (params instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)params;
+ this.ecParams = params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params instanceof java.security.spec.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;
+ }
+ else if (params instanceof ECGenParameterSpec || params instanceof ECNamedCurveGenParameterSpec)
+ {
+ String curveName;
+
+ if (params instanceof ECGenParameterSpec)
+ {
+ curveName = ((ECGenParameterSpec)params).getName();
+ }
+ else
+ {
+ curveName = ((ECNamedCurveGenParameterSpec)params).getName();
+ }
+
+ X9ECParameters ecP = X962NamedCurves.getByName(curveName);
+ if (ecP == null)
+ {
+ ecP = SECNamedCurves.getByName(curveName);
+ if (ecP == null)
+ {
+ ecP = NISTNamedCurves.getByName(curveName);
+ }
+ // BEGIN android-removed
+ // if (ecP == null)
+ // {
+ // ecP = TeleTrusTNamedCurves.getByName(curveName);
+ // }
+ // END android-removed
+ if (ecP == null)
+ {
+ // See if it's actually an OID string (SunJSSE ServerHandshaker setupEphemeralECDHKeys bug)
+ try
+ {
+ ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(curveName);
+ ecP = X962NamedCurves.getByOID(oid);
+ if (ecP == null)
+ {
+ ecP = SECNamedCurves.getByOID(oid);
+ }
+ if (ecP == null)
+ {
+ ecP = NISTNamedCurves.getByOID(oid);
+ }
+ // BEGIN android-removed
+ // if (ecP == null)
+ // {
+ // ecP = TeleTrusTNamedCurves.getByOID(oid);
+ // }
+ // END android-removed
+ 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;
+ }
+ else if (params == null && configuration.getEcImplicitlyCa() != null)
+ {
+ ECParameterSpec p = configuration.getEcImplicitlyCa();
+ this.ecParams = params;
+
+ param = new ECKeyGenerationParameters(new ECDomainParameters(p.getCurve(), p.getG(), p.getN()), random);
+
+ engine.init(param);
+ initialised = true;
+ }
+ else if (params == null && configuration.getEcImplicitlyCa() == null)
+ {
+ throw new InvalidAlgorithmParameterException("null parameter passed but no implicitCA set");
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec");
+ }
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ if (!initialised)
+ {
+ // BEGIN android-removed
+ // throw new IllegalStateException("EC Key Pair Generator not initialised");
+ // END android-removed
+ // BEGIN android-added
+ /*
+ * KeyPairGenerator documentation says that a default initialization must be provided
+ */
+ initialize(192, random);
+ // END android-added
+ }
+
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ ECPublicKeyParameters pub = (ECPublicKeyParameters)pair.getPublic();
+ ECPrivateKeyParameters priv = (ECPrivateKeyParameters)pair.getPrivate();
+
+ if (ecParams instanceof ECParameterSpec)
+ {
+ ECParameterSpec p = (ECParameterSpec)ecParams;
+
+ BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
+ return new KeyPair(pubKey,
+ new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
+ }
+ else if (ecParams == null)
+ {
+ return new KeyPair(new BCECPublicKey(algorithm, pub, configuration),
+ new BCECPrivateKey(algorithm, priv, configuration));
+ }
+ else
+ {
+ java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams;
+
+ BCECPublicKey pubKey = new BCECPublicKey(algorithm, pub, p, configuration);
+
+ return new KeyPair(pubKey, new BCECPrivateKey(algorithm, priv, pubKey, p, configuration));
+ }
+ }
+ }
+
+ public static class ECDSA
+ extends EC
+ {
+ public ECDSA()
+ {
+ super("ECDSA", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDH
+ extends EC
+ {
+ public ECDH()
+ {
+ super("ECDH", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECDHC
+ extends EC
+ {
+ public ECDHC()
+ {
+ super("ECDHC", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+
+ public static class ECMQV
+ extends EC
+ {
+ public ECMQV()
+ {
+ super("ECMQV", BouncyCastleProvider.CONFIGURATION);
+ }
+ }
+} \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
new file mode 100644
index 0000000..a92b7da
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java
@@ -0,0 +1,352 @@
+package org.bouncycastle.jcajce.provider.asymmetric.ec;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPublicKey;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.NullDigest;
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-added
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// import org.bouncycastle.crypto.digests.SHA1Digest;
+// import org.bouncycastle.crypto.digests.SHA224Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.SHA384Digest;
+// import org.bouncycastle.crypto.digests.SHA512Digest;
+// END android-removed
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.signers.ECDSASigner;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.signers.ECNRSigner;
+// END android-removed
+import org.bouncycastle.jcajce.provider.asymmetric.util.DSABase;
+import org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder;
+import org.bouncycastle.jce.interfaces.ECKey;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class SignatureSpi
+ extends DSABase
+{
+ SignatureSpi(Digest digest, DSA signer, DSAEncoder encoder)
+ {
+ super(digest, signer, encoder);
+ }
+
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ try
+ {
+ byte[] bytes = publicKey.getEncoded();
+
+ publicKey = BouncyCastleProvider.getPublicKey(SubjectPublicKeyInfo.getInstance(bytes));
+
+ if (publicKey instanceof ECPublicKey)
+ {
+ param = ECUtil.generatePublicKeyParameter(publicKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+ }
+ }
+
+ digest.reset();
+ signer.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ CipherParameters param;
+
+ if (privateKey instanceof ECKey)
+ {
+ param = ECUtil.generatePrivateKeyParameter(privateKey);
+ }
+ else
+ {
+ throw new InvalidKeyException("can't recognise key type in ECDSA based signer");
+ }
+
+ digest.reset();
+
+ if (appRandom != null)
+ {
+ signer.init(true, new ParametersWithRandom(param, appRandom));
+ }
+ else
+ {
+ signer.init(true, param);
+ }
+ }
+
+ static public class ecDSA
+ extends SignatureSpi
+ {
+ public ecDSA()
+ {
+ // BEGIN android-changed
+ super(AndroidDigestFactory.getSHA1(), new ECDSASigner(), new StdDSAEncoder());
+ // END android-changed
+ }
+ }
+
+ static public class ecDSAnone
+ extends SignatureSpi
+ {
+ public ecDSAnone()
+ {
+ super(new NullDigest(), new ECDSASigner(), new StdDSAEncoder());
+ }
+ }
+
+ // BEGIN android-removed
+ // static public class ecDSA224
+ // extends SignatureSpi
+ // {
+ // public ecDSA224()
+ // {
+ // super(new SHA224Digest(), new ECDSASigner(), new StdDSAEncoder());
+ // }
+ // }
+ // END android-removed
+
+ static public class ecDSA256
+ extends SignatureSpi
+ {
+ public ecDSA256()
+ {
+ // BEGIN android-changed
+ super(AndroidDigestFactory.getSHA256(), new ECDSASigner(), new StdDSAEncoder());
+ // END android-changed
+ }
+ }
+
+ static public class ecDSA384
+ extends SignatureSpi
+ {
+ public ecDSA384()
+ {
+ // BEGIN android-changed
+ super(AndroidDigestFactory.getSHA384(), new ECDSASigner(), new StdDSAEncoder());
+ // END android-changed
+ }
+ }
+
+ static public class ecDSA512
+ extends SignatureSpi
+ {
+ public ecDSA512()
+ {
+ // BEGIN android-changed
+ super(AndroidDigestFactory.getSHA512(), new ECDSASigner(), new StdDSAEncoder());
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // static public class ecDSARipeMD160
+ // extends SignatureSpi
+ // {
+ // public ecDSARipeMD160()
+ // {
+ // super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder());
+ // }
+ // }
+ //
+ // static public class ecNR
+ // extends SignatureSpi
+ // {
+ // public ecNR()
+ // {
+ // super(new SHA1Digest(), new ECNRSigner(), new StdDSAEncoder());
+ // }
+ // }
+ //
+ // static public class ecNR224
+ // extends SignatureSpi
+ // {
+ // public ecNR224()
+ // {
+ // super(new SHA224Digest(), new ECNRSigner(), new StdDSAEncoder());
+ // }
+ // }
+ //
+ // static public class ecNR256
+ // extends SignatureSpi
+ // {
+ // public ecNR256()
+ // {
+ // super(new SHA256Digest(), new ECNRSigner(), new StdDSAEncoder());
+ // }
+ // }
+ //
+ // static public class ecNR384
+ // extends SignatureSpi
+ // {
+ // public ecNR384()
+ // {
+ // super(new SHA384Digest(), new ECNRSigner(), new StdDSAEncoder());
+ // }
+ // }
+ //
+ // static public class ecNR512
+ // extends SignatureSpi
+ // {
+ // public ecNR512()
+ // {
+ // super(new SHA512Digest(), new ECNRSigner(), new StdDSAEncoder());
+ // }
+ // }
+ //
+ // static public class ecCVCDSA
+ // extends SignatureSpi
+ // {
+ // public ecCVCDSA()
+ // {
+ // super(new SHA1Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ // }
+ // }
+ //
+ // static public class ecCVCDSA224
+ // extends SignatureSpi
+ // {
+ // public ecCVCDSA224()
+ // {
+ // super(new SHA224Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ // }
+ // }
+ //
+ // static public class ecCVCDSA256
+ // extends SignatureSpi
+ // {
+ // public ecCVCDSA256()
+ // {
+ // super(new SHA256Digest(), new ECDSASigner(), new CVCDSAEncoder());
+ // }
+ // }
+ // END android-removed
+
+ private static class StdDSAEncoder
+ implements DSAEncoder
+ {
+ public byte[] encode(
+ BigInteger r,
+ BigInteger s)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(new DERInteger(r));
+ v.add(new DERInteger(s));
+
+ return new DERSequence(v).getEncoded(ASN1Encoding.DER);
+ }
+
+ public BigInteger[] decode(
+ byte[] encoding)
+ throws IOException
+ {
+ ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding);
+ BigInteger[] sig = new BigInteger[2];
+
+ sig[0] = ((DERInteger)s.getObjectAt(0)).getValue();
+ sig[1] = ((DERInteger)s.getObjectAt(1)).getValue();
+
+ return sig;
+ }
+ }
+
+ 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;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
new file mode 100644
index 0000000..99ac36c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java
@@ -0,0 +1,273 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+import java.security.spec.PSSParameterSpec;
+
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
+import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.jcajce.provider.util.DigestFactory;
+
+public abstract class AlgorithmParametersSpi
+ extends java.security.AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ public static class OAEP
+ extends AlgorithmParametersSpi
+ {
+ OAEPParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSAES-OAEP-params.
+ */
+ protected byte[] engineGetEncoded()
+ {
+ AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+ DigestFactory.getOID(currentSpec.getDigestAlgorithm()),
+ // BEGIN android-changed
+ DERNull.INSTANCE);
+ // END android-changed
+ MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)currentSpec.getMGFParameters();
+ AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_mgf1,
+ // BEGIN android-changed
+ new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+ // END android-changed
+ PSource.PSpecified pSource = (PSource.PSpecified)currentSpec.getPSource();
+ AlgorithmIdentifier pSourceAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(pSource.getValue()));
+ RSAESOAEPparams oaepP = new RSAESOAEPparams(hashAlgorithm, maskGenAlgorithm, pSourceAlgorithm);
+
+ try
+ {
+ return oaepP.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Error encoding OAEPParameters");
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == OAEPParameterSpec.class && currentSpec != null)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof OAEPParameterSpec))
+ {
+ throw new InvalidParameterSpecException("OAEPParameterSpec required to initialise an OAEP algorithm parameters object");
+ }
+
+ this.currentSpec = (OAEPParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSAESOAEPparams oaepP = RSAESOAEPparams.getInstance(params);
+
+ currentSpec = new OAEPParameterSpec(
+ oaepP.getHashAlgorithm().getAlgorithm().getId(),
+ oaepP.getMaskGenAlgorithm().getAlgorithm().getId(),
+ new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(oaepP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+ new PSource.PSpecified(ASN1OctetString.getInstance(oaepP.getPSourceAlgorithm().getParameters()).getOctets()));
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid OAEP Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "OAEP Parameters";
+ }
+ }
+
+ public static class PSS
+ extends AlgorithmParametersSpi
+ {
+ PSSParameterSpec currentSpec;
+
+ /**
+ * Return the PKCS#1 ASN.1 structure RSASSA-PSS-params.
+ */
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ PSSParameterSpec pssSpec = currentSpec;
+ AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(
+ DigestFactory.getOID(pssSpec.getDigestAlgorithm()),
+ // BEGIN android-changed
+ DERNull.INSTANCE);
+ // END android-changed
+ MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec)pssSpec.getMGFParameters();
+ AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(
+ PKCSObjectIdentifiers.id_mgf1,
+ // BEGIN android-changed
+ new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE));
+ // END android-changed
+ RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new ASN1Integer(pssSpec.getSaltLength()), new ASN1Integer(pssSpec.getTrailerField()));
+
+ return pssP.getEncoded("DER");
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (format.equalsIgnoreCase("X.509")
+ || format.equalsIgnoreCase("ASN.1"))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PSSParameterSpec.class && currentSpec != null)
+ {
+ return currentSpec;
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PSSParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PSSParameterSpec required to initialise an PSS algorithm parameters object");
+ }
+
+ this.currentSpec = (PSSParameterSpec)paramSpec;
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ try
+ {
+ RSASSAPSSparams pssP = RSASSAPSSparams.getInstance(params);
+
+ currentSpec = new PSSParameterSpec(
+ pssP.getHashAlgorithm().getAlgorithm().getId(),
+ pssP.getMaskGenAlgorithm().getAlgorithm().getId(),
+ new MGF1ParameterSpec(AlgorithmIdentifier.getInstance(pssP.getMaskGenAlgorithm().getParameters()).getAlgorithm().getId()),
+ pssP.getSaltLength().intValue(),
+ pssP.getTrailerField().intValue());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new IOException("Not a valid PSS Parameter encoding.");
+ }
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ {
+ engineInit(params);
+ }
+ else
+ {
+ throw new IOException("Unknown parameter format " + format);
+ }
+ }
+
+ protected String engineToString()
+ {
+ return "PSS Parameters";
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
new file mode 100644
index 0000000..b0aa66e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java
@@ -0,0 +1,243 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+/**
+ * A provider representation for a RSA private key, with CRT factors included.
+ */
+public class BCRSAPrivateCrtKey
+ extends BCRSAPrivateKey
+ implements RSAPrivateCrtKey
+{
+ static final long serialVersionUID = 7834723820638524718L;
+
+ private BigInteger publicExponent;
+ private BigInteger primeP;
+ private BigInteger primeQ;
+ private BigInteger primeExponentP;
+ private BigInteger primeExponentQ;
+ private BigInteger crtCoefficient;
+
+ /**
+ * construct a private key from it's org.bouncycastle.crypto equivalent.
+ *
+ * @param key the parameters object representing the private key.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateCrtKeyParameters key)
+ {
+ super(key);
+
+ this.publicExponent = key.getPublicExponent();
+ this.primeP = key.getP();
+ this.primeQ = key.getQ();
+ this.primeExponentP = key.getDP();
+ this.primeExponentQ = key.getDQ();
+ this.crtCoefficient = key.getQInv();
+ }
+
+ /**
+ * construct a private key from an RSAPrivateCrtKeySpec
+ *
+ * @param spec the spec to be used in construction.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateCrtKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ this.privateExponent = spec.getPrivateExponent();
+ this.primeP = spec.getPrimeP();
+ this.primeQ = spec.getPrimeQ();
+ this.primeExponentP = spec.getPrimeExponentP();
+ this.primeExponentQ = spec.getPrimeExponentQ();
+ this.crtCoefficient = spec.getCrtCoefficient();
+ }
+
+ /**
+ * construct a private key from another RSAPrivateCrtKey.
+ *
+ * @param key the object implementing the RSAPrivateCrtKey interface.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateCrtKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrimeP();
+ this.primeQ = key.getPrimeQ();
+ this.primeExponentP = key.getPrimeExponentP();
+ this.primeExponentQ = key.getPrimeExponentQ();
+ this.crtCoefficient = key.getCrtCoefficient();
+ }
+
+ /**
+ * construct an RSA key from a private key info object.
+ */
+ BCRSAPrivateCrtKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ this(RSAPrivateKey.getInstance(info.parsePrivateKey()));
+ }
+
+ /**
+ * construct an RSA key from a ASN.1 RSA private key object.
+ */
+ BCRSAPrivateCrtKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrime1();
+ this.primeQ = key.getPrime2();
+ this.primeExponentP = key.getExponent1();
+ this.primeExponentQ = key.getExponent2();
+ this.crtCoefficient = key.getCoefficient();
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the encoding format we produce in getEncoded().
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ // BEGIN android-changed
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
+ // END android-changed
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ /**
+ * return the prime P.
+ *
+ * @return the prime P.
+ */
+ public BigInteger getPrimeP()
+ {
+ return primeP;
+ }
+
+ /**
+ * return the prime Q.
+ *
+ * @return the prime Q.
+ */
+ public BigInteger getPrimeQ()
+ {
+ return primeQ;
+ }
+
+ /**
+ * return the prime exponent for P.
+ *
+ * @return the prime exponent for P.
+ */
+ public BigInteger getPrimeExponentP()
+ {
+ return primeExponentP;
+ }
+
+ /**
+ * return the prime exponent for Q.
+ *
+ * @return the prime exponent for Q.
+ */
+ public BigInteger getPrimeExponentQ()
+ {
+ return primeExponentQ;
+ }
+
+ /**
+ * return the CRT coefficient.
+ *
+ * @return the CRT coefficient.
+ */
+ public BigInteger getCrtCoefficient()
+ {
+ return crtCoefficient;
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode()
+ ^ this.getPublicExponent().hashCode()
+ ^ this.getPrivateExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPrivateCrtKey))
+ {
+ return false;
+ }
+
+ RSAPrivateCrtKey key = (RSAPrivateCrtKey)o;
+
+ return this.getModulus().equals(key.getModulus())
+ && this.getPublicExponent().equals(key.getPublicExponent())
+ && this.getPrivateExponent().equals(key.getPrivateExponent())
+ && this.getPrimeP().equals(key.getPrimeP())
+ && this.getPrimeQ().equals(key.getPrimeQ())
+ && this.getPrimeExponentP().equals(key.getPrimeExponentP())
+ && this.getPrimeExponentQ().equals(key.getPrimeExponentQ())
+ && this.getCrtCoefficient().equals(key.getCrtCoefficient());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Private CRT Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+ buf.append(" private exponent: ").append(this.getPrivateExponent().toString(16)).append(nl);
+ buf.append(" primeP: ").append(this.getPrimeP().toString(16)).append(nl);
+ buf.append(" primeQ: ").append(this.getPrimeQ().toString(16)).append(nl);
+ buf.append(" primeExponentP: ").append(this.getPrimeExponentP().toString(16)).append(nl);
+ buf.append(" primeExponentQ: ").append(this.getPrimeExponentQ().toString(16)).append(nl);
+ buf.append(" crtCoefficient: ").append(this.getCrtCoefficient().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
new file mode 100644
index 0000000..6643f13
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java
@@ -0,0 +1,142 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class BCRSAPrivateKey
+ implements RSAPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 5110188922551353628L;
+
+ private static BigInteger ZERO = BigInteger.valueOf(0);
+
+ protected BigInteger modulus;
+ protected BigInteger privateExponent;
+
+ private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected BCRSAPrivateKey()
+ {
+ }
+
+ BCRSAPrivateKey(
+ RSAKeyParameters key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getExponent();
+ }
+
+ BCRSAPrivateKey(
+ RSAPrivateKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.privateExponent = spec.getPrivateExponent();
+ }
+
+ BCRSAPrivateKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getPrivateExponent();
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPrivateExponent()
+ {
+ return privateExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ public byte[] getEncoded()
+ {
+ // BEGIN android-changed
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
+ // END android-changed
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof RSAPrivateKey))
+ {
+ return false;
+ }
+
+ if (o == this)
+ {
+ return true;
+ }
+
+ RSAPrivateKey key = (RSAPrivateKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPrivateExponent().equals(key.getPrivateExponent());
+ }
+
+ public int hashCode()
+ {
+ return getModulus().hashCode() ^ getPrivateExponent().hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ in.defaultReadObject();
+
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.defaultWriteObject();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
new file mode 100644
index 0000000..e57da4a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java
@@ -0,0 +1,131 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class BCRSAPublicKey
+ implements RSAPublicKey
+{
+ static final long serialVersionUID = 2675817738516720772L;
+
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+
+ BCRSAPublicKey(
+ RSAKeyParameters key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getExponent();
+ }
+
+ BCRSAPublicKey(
+ RSAPublicKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ }
+
+ BCRSAPublicKey(
+ RSAPublicKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ }
+
+ BCRSAPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ try
+ {
+ org.bouncycastle.asn1.pkcs.RSAPublicKey pubKey = org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(info.parsePublicKey());
+
+ this.modulus = pubKey.getModulus();
+ this.publicExponent = pubKey.getPublicExponent();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in RSA public key");
+ }
+ }
+
+ /**
+ * return the modulus.
+ *
+ * @return the modulus.
+ */
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ // BEGIN android-changed
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent()));
+ // END android-changed
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode() ^ this.getPublicExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPublicKey))
+ {
+ return false;
+ }
+
+ RSAPublicKey key = (RSAPublicKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPublicExponent().equals(key.getPublicExponent());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Public Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
new file mode 100644
index 0000000..1f53f5a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -0,0 +1,589 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.ByteArrayOutputStream;
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.MGF1ParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.OAEPParameterSpec;
+import javax.crypto.spec.PSource;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
+// END android-removed
+import org.bouncycastle.crypto.encodings.OAEPEncoding;
+import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import org.bouncycastle.crypto.engines.RSABlindedEngine;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
+import org.bouncycastle.jcajce.provider.util.DigestFactory;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Strings;
+
+public class CipherSpi
+ extends BaseCipherSpi
+{
+ private AsymmetricBlockCipher cipher;
+ private AlgorithmParameterSpec paramSpec;
+ private AlgorithmParameters engineParams;
+ private boolean publicKeyOnly = false;
+ private boolean privateKeyOnly = false;
+ private ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ public CipherSpi(
+ AsymmetricBlockCipher engine)
+ {
+ cipher = engine;
+ }
+
+ public CipherSpi(
+ OAEPParameterSpec pSpec)
+ {
+ try
+ {
+ initFromSpec(pSpec);
+ }
+ catch (NoSuchPaddingException e)
+ {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+
+ public CipherSpi(
+ boolean publicKeyOnly,
+ boolean privateKeyOnly,
+ AsymmetricBlockCipher engine)
+ {
+ this.publicKeyOnly = publicKeyOnly;
+ this.privateKeyOnly = privateKeyOnly;
+ cipher = engine;
+ }
+
+ private void initFromSpec(
+ OAEPParameterSpec pSpec)
+ throws NoSuchPaddingException
+ {
+ MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)pSpec.getMGFParameters();
+ Digest digest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+
+ if (digest == null)
+ {
+ throw new NoSuchPaddingException("no match on OAEP constructor for digest algorithm: "+ mgfParams.getDigestAlgorithm());
+ }
+
+ cipher = new OAEPEncoding(new RSABlindedEngine(), digest, ((PSource.PSpecified)pSpec.getPSource()).getValue());
+ paramSpec = pSpec;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ try
+ {
+ return cipher.getInputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ if (key instanceof RSAPrivateKey)
+ {
+ RSAPrivateKey k = (RSAPrivateKey)key;
+
+ return k.getModulus().bitLength();
+ }
+ else if (key instanceof RSAPublicKey)
+ {
+ RSAPublicKey k = (RSAPublicKey)key;
+
+ return k.getModulus().bitLength();
+ }
+
+ throw new IllegalArgumentException("not an RSA key!");
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ try
+ {
+ return cipher.getOutputBlockSize();
+ }
+ catch (NullPointerException e)
+ {
+ throw new IllegalStateException("RSA Cipher not initialised");
+ }
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (paramSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance("OAEP", BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(paramSpec);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ String md = Strings.toUpperCase(mode);
+
+ if (md.equals("NONE") || md.equals("ECB"))
+ {
+ return;
+ }
+
+ if (md.equals("1"))
+ {
+ privateKeyOnly = true;
+ publicKeyOnly = false;
+ return;
+ }
+ else if (md.equals("2"))
+ {
+ privateKeyOnly = false;
+ publicKeyOnly = true;
+ return;
+ }
+
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String pad = Strings.toUpperCase(padding);
+
+ if (pad.equals("NOPADDING"))
+ {
+ cipher = new RSABlindedEngine();
+ }
+ else if (pad.equals("PKCS1PADDING"))
+ {
+ cipher = new PKCS1Encoding(new RSABlindedEngine());
+ }
+ // BEGIN android-removed
+ // else if (pad.equals("ISO9796-1PADDING"))
+ // {
+ // cipher = new ISO9796d1Encoding(new RSABlindedEngine());
+ // }
+ // END android-removed
+ else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("MD5", "MGF1", new MGF1ParameterSpec("MD5"), PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPPADDING"))
+ {
+ initFromSpec(OAEPParameterSpec.DEFAULT);
+ }
+ else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-1ANDMGF1PADDING"))
+ {
+ initFromSpec(OAEPParameterSpec.DEFAULT);
+ }
+ // BEGIN android-removed
+ // else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-224ANDMGF1PADDING"))
+ // {
+ // initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), PSource.PSpecified.DEFAULT));
+ // }
+ // END android-removed
+ else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-256ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA384ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-384ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-384", "MGF1", MGF1ParameterSpec.SHA384, PSource.PSpecified.DEFAULT));
+ }
+ else if (pad.equals("OAEPWITHSHA512ANDMGF1PADDING") || pad.equals("OAEPWITHSHA-512ANDMGF1PADDING"))
+ {
+ initFromSpec(new OAEPParameterSpec("SHA-512", "MGF1", MGF1ParameterSpec.SHA512, PSource.PSpecified.DEFAULT));
+ }
+ else
+ {
+ throw new NoSuchPaddingException(padding + " unavailable with RSA.");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (params == null || params instanceof OAEPParameterSpec)
+ {
+ if (key instanceof RSAPublicKey)
+ {
+ if (privateKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 1 requires RSAPrivateKey");
+ }
+
+ param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)key);
+ }
+ else if (key instanceof RSAPrivateKey)
+ {
+ if (publicKeyOnly && opmode == Cipher.ENCRYPT_MODE)
+ {
+ throw new InvalidKeyException(
+ "mode 2 requires RSAPublicKey");
+ }
+
+ param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)key);
+ }
+ else
+ {
+ throw new InvalidKeyException("unknown key type passed to RSA");
+ }
+
+ if (params != null)
+ {
+ OAEPParameterSpec spec = (OAEPParameterSpec)params;
+
+ paramSpec = params;
+
+ if (!spec.getMGFAlgorithm().equalsIgnoreCase("MGF1") && !spec.getMGFAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1.getId()))
+ {
+ throw new InvalidAlgorithmParameterException("unknown mask generation function specified");
+ }
+
+ if (!(spec.getMGFParameters() instanceof MGF1ParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("unkown MGF parameters");
+ }
+
+ Digest digest = DigestFactory.getDigest(spec.getDigestAlgorithm());
+
+ if (digest == null)
+ {
+ throw new InvalidAlgorithmParameterException("no match on digest algorithm: "+ spec.getDigestAlgorithm());
+ }
+
+ MGF1ParameterSpec mgfParams = (MGF1ParameterSpec)spec.getMGFParameters();
+ Digest mgfDigest = DigestFactory.getDigest(mgfParams.getDigestAlgorithm());
+
+ if (mgfDigest == null)
+ {
+ throw new InvalidAlgorithmParameterException("no match on MGF digest algorithm: "+ mgfParams.getDigestAlgorithm());
+ }
+
+ cipher = new OAEPEncoding(new RSABlindedEngine(), digest, mgfDigest, ((PSource.PSpecified)spec.getPSource()).getValue());
+ }
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown parameter type.");
+ }
+
+ if (!(cipher instanceof RSABlindedEngine))
+ {
+ if (random != null)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+ else
+ {
+ param = new ParametersWithRandom(param, new SecureRandom());
+ }
+ }
+
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed to RSA");
+ }
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameters params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ AlgorithmParameterSpec paramSpec = null;
+
+ if (params != null)
+ {
+ try
+ {
+ paramSpec = params.getParameterSpec(OAEPParameterSpec.class);
+ }
+ catch (InvalidParameterSpecException e)
+ {
+ throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + e.toString(), e);
+ }
+ }
+
+ engineParams = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // this shouldn't happen
+ throw new InvalidKeyException("Eeeek! " + e.toString(), e);
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ {
+ bOut.write(input, inputOffset, inputLen);
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ return 0;
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+
+ bOut.reset();
+
+ return cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ if (input != null)
+ {
+ bOut.write(input, inputOffset, inputLen);
+ }
+
+ if (cipher instanceof RSABlindedEngine)
+ {
+ if (bOut.size() > cipher.getInputBlockSize() + 1)
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+ else
+ {
+ if (bOut.size() > cipher.getInputBlockSize())
+ {
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
+ }
+ }
+
+ byte[] out;
+
+ try
+ {
+ byte[] bytes = bOut.toByteArray();
+ bOut.reset();
+
+ out = cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ for (int i = 0; i != out.length; i++)
+ {
+ output[outputOffset + i] = out[i];
+ }
+
+ return out.length;
+ }
+
+ /**
+ * classes that inherit from us.
+ */
+
+ static public class NoPadding
+ extends CipherSpi
+ {
+ public NoPadding()
+ {
+ super(new RSABlindedEngine());
+ }
+ }
+
+ // BEGIN android-removed
+ // static public class PKCS1v1_5Padding
+ // extends CipherSpi
+ // {
+ // public PKCS1v1_5Padding()
+ // {
+ // super(new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ //
+ // static public class PKCS1v1_5Padding_PrivateOnly
+ // extends CipherSpi
+ // {
+ // public PKCS1v1_5Padding_PrivateOnly()
+ // {
+ // super(false, true, new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ //
+ // static public class PKCS1v1_5Padding_PublicOnly
+ // extends CipherSpi
+ // {
+ // public PKCS1v1_5Padding_PublicOnly()
+ // {
+ // super(true, false, new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ //
+ // static public class OAEPPadding
+ // extends CipherSpi
+ // {
+ // public OAEPPadding()
+ // {
+ // super(OAEPParameterSpec.DEFAULT);
+ // }
+ // }
+ //
+ // static public class ISO9796d1Padding
+ // extends CipherSpi
+ // {
+ // public ISO9796d1Padding()
+ // {
+ // super(new ISO9796d1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ // END android-removed
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
new file mode 100644
index 0000000..a1bdc65
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -0,0 +1,389 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DigestInfo;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD2Digest;
+// import org.bouncycastle.crypto.digests.MD4Digest;
+// import org.bouncycastle.crypto.digests.MD5Digest;
+// import org.bouncycastle.crypto.digests.NullDigest;
+// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD256Digest;
+// import org.bouncycastle.crypto.digests.SHA1Digest;
+// import org.bouncycastle.crypto.digests.SHA224Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.SHA384Digest;
+// import org.bouncycastle.crypto.digests.SHA512Digest;
+// END android-removed
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-added
+import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import org.bouncycastle.crypto.engines.RSABlindedEngine;
+
+public class DigestSignatureSpi
+ extends SignatureSpi
+{
+ private Digest digest;
+ private AsymmetricBlockCipher cipher;
+ private AlgorithmIdentifier algId;
+
+ // care - this constructor is actually used by outside organisations
+ protected DigestSignatureSpi(
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ this.algId = null;
+ }
+
+ // care - this constructor is actually used by outside organisations
+ protected DigestSignatureSpi(
+ ASN1ObjectIdentifier objId,
+ Digest digest,
+ AsymmetricBlockCipher cipher)
+ {
+ this.digest = digest;
+ this.cipher = cipher;
+ this.algId = new AlgorithmIdentifier(objId, DERNull.INSTANCE);
+ }
+
+ protected void engineInitVerify(
+ PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ if (!(publicKey instanceof RSAPublicKey))
+ {
+ throw new InvalidKeyException("Supplied key (" + getType(publicKey) + ") is not a RSAPublicKey instance");
+ }
+
+ CipherParameters param = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
+
+ digest.reset();
+ cipher.init(false, param);
+ }
+
+ protected void engineInitSign(
+ PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ if (!(privateKey instanceof RSAPrivateKey))
+ {
+ throw new InvalidKeyException("Supplied key (" + getType(privateKey) + ") is not a RSAPrivateKey instance");
+ }
+
+ CipherParameters param = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
+
+ digest.reset();
+
+ cipher.init(true, param);
+ }
+
+ private String getType(
+ Object o)
+ {
+ if (o == null)
+ {
+ return null;
+ }
+
+ return o.getClass().getName();
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ byte[] bytes = derEncode(hash);
+
+ return cipher.processBlock(bytes, 0, bytes.length);
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ throw new SignatureException("key too small for signature type");
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ byte[] sig;
+ byte[] expected;
+
+ try
+ {
+ sig = cipher.processBlock(sigBytes, 0, sigBytes.length);
+
+ expected = derEncode(hash);
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ if (sig.length == expected.length)
+ {
+ for (int i = 0; i < sig.length; i++)
+ {
+ if (sig[i] != expected[i])
+ {
+ return false;
+ }
+ }
+ }
+ else if (sig.length == expected.length - 2) // NULL left out
+ {
+ int sigOffset = sig.length - hash.length - 2;
+ int expectedOffset = expected.length - hash.length - 2;
+
+ expected[1] -= 2; // adjust lengths
+ expected[3] -= 2;
+
+ for (int i = 0; i < hash.length; i++)
+ {
+ if (sig[sigOffset + i] != expected[expectedOffset + i]) // check hash
+ {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < sigOffset; i++)
+ {
+ if (sig[i] != expected[i]) // check header less NULL
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ return null;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return null;
+ }
+
+ private byte[] derEncode(
+ byte[] hash)
+ throws IOException
+ {
+ if (algId == null)
+ {
+ // For raw RSA, the DigestInfo must be prepared externally
+ return hash;
+ }
+
+ DigestInfo dInfo = new DigestInfo(algId, hash);
+
+ return dInfo.getEncoded(ASN1Encoding.DER);
+ }
+
+ static public class SHA1
+ extends DigestSignatureSpi
+ {
+ public SHA1()
+ {
+ // BEGIN android-changed
+ super(OIWObjectIdentifiers.idSHA1, AndroidDigestFactory.getSHA1(), new PKCS1Encoding(new RSABlindedEngine()));
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // static public class SHA224
+ // extends DigestSignatureSpi
+ // {
+ // public SHA224()
+ // {
+ // super(NISTObjectIdentifiers.id_sha224, new SHA224Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ // END android-removed
+
+ static public class SHA256
+ extends DigestSignatureSpi
+ {
+ public SHA256()
+ {
+ // BEGIN android-changed
+ super(NISTObjectIdentifiers.id_sha256, AndroidDigestFactory.getSHA256(), new PKCS1Encoding(new RSABlindedEngine()));
+ // END android-changed
+ }
+ }
+
+ static public class SHA384
+ extends DigestSignatureSpi
+ {
+ public SHA384()
+ {
+ // BEGIN android-changed
+ super(NISTObjectIdentifiers.id_sha384, AndroidDigestFactory.getSHA384(), new PKCS1Encoding(new RSABlindedEngine()));
+ // END android-changed
+ }
+ }
+
+ static public class SHA512
+ extends DigestSignatureSpi
+ {
+ public SHA512()
+ {
+ // BEGIN android-changed
+ super(NISTObjectIdentifiers.id_sha512, AndroidDigestFactory.getSHA512(), new PKCS1Encoding(new RSABlindedEngine()));
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // static public class MD2
+ // extends DigestSignatureSpi
+ // {
+ // public MD2()
+ // {
+ // super(PKCSObjectIdentifiers.md2, new MD2Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ //
+ // static public class MD4
+ // extends DigestSignatureSpi
+ // {
+ // public MD4()
+ // {
+ // super(PKCSObjectIdentifiers.md4, new MD4Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ // END android-removed
+
+ static public class MD5
+ extends DigestSignatureSpi
+ {
+ public MD5()
+ {
+ // BEGIN android-changed
+ super(PKCSObjectIdentifiers.md5, AndroidDigestFactory.getMD5(), new PKCS1Encoding(new RSABlindedEngine()));
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // static public class RIPEMD160
+ // extends DigestSignatureSpi
+ // {
+ // public RIPEMD160()
+ // {
+ // super(TeleTrusTObjectIdentifiers.ripemd160, new RIPEMD160Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ //
+ // static public class RIPEMD128
+ // extends DigestSignatureSpi
+ // {
+ // public RIPEMD128()
+ // {
+ // super(TeleTrusTObjectIdentifiers.ripemd128, new RIPEMD128Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ //
+ // static public class RIPEMD256
+ // extends DigestSignatureSpi
+ // {
+ // public RIPEMD256()
+ // {
+ // super(TeleTrusTObjectIdentifiers.ripemd256, new RIPEMD256Digest(), new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ //
+ // static public class noneRSA
+ // extends DigestSignatureSpi
+ // {
+ // public noneRSA()
+ // {
+ // super(new NullDigest(), new PKCS1Encoding(new RSABlindedEngine()));
+ // }
+ // }
+ // END android-removed
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
new file mode 100644
index 0000000..d8eb539
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java
@@ -0,0 +1,162 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPrivateKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException;
+
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
+{
+ public KeyFactorySpi()
+ {
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(RSAPublicKeySpec.class) && key instanceof RSAPublicKey)
+ {
+ RSAPublicKey k = (RSAPublicKey)key;
+
+ return new RSAPublicKeySpec(k.getModulus(), k.getPublicExponent());
+ }
+ else if (spec.isAssignableFrom(RSAPrivateKeySpec.class) && key instanceof java.security.interfaces.RSAPrivateKey)
+ {
+ java.security.interfaces.RSAPrivateKey k = (java.security.interfaces.RSAPrivateKey)key;
+
+ return new RSAPrivateKeySpec(k.getModulus(), k.getPrivateExponent());
+ }
+ else if (spec.isAssignableFrom(RSAPrivateCrtKeySpec.class) && key instanceof RSAPrivateCrtKey)
+ {
+ RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+ return new RSAPrivateCrtKeySpec(
+ k.getModulus(), k.getPublicExponent(),
+ k.getPrivateExponent(),
+ k.getPrimeP(), k.getPrimeQ(),
+ k.getPrimeExponentP(), k.getPrimeExponentQ(),
+ k.getCrtCoefficient());
+ }
+
+ return super.engineGetKeySpec(key, spec);
+ }
+
+ protected Key engineTranslateKey(
+ Key key)
+ throws InvalidKeyException
+ {
+ if (key instanceof RSAPublicKey)
+ {
+ return new BCRSAPublicKey((RSAPublicKey)key);
+ }
+ else if (key instanceof RSAPrivateCrtKey)
+ {
+ return new BCRSAPrivateCrtKey((RSAPrivateCrtKey)key);
+ }
+ else if (key instanceof java.security.interfaces.RSAPrivateKey)
+ {
+ return new BCRSAPrivateKey((java.security.interfaces.RSAPrivateKey)key);
+ }
+
+ throw new InvalidKeyException("key type unknown");
+ }
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ try
+ {
+ return generatePrivate(PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+ }
+ catch (Exception e)
+ {
+ //
+ // in case it's just a RSAPrivateKey object... -- openSSL produces these
+ //
+ try
+ {
+ return new BCRSAPrivateCrtKey(
+ RSAPrivateKey.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+ }
+ catch (Exception ex)
+ {
+ throw new ExtendedInvalidKeySpecException("unable to process key spec: " + e.toString(), e);
+ }
+ }
+ }
+ else if (keySpec instanceof RSAPrivateCrtKeySpec)
+ {
+ return new BCRSAPrivateCrtKey((RSAPrivateCrtKeySpec)keySpec);
+ }
+ else if (keySpec instanceof RSAPrivateKeySpec)
+ {
+ return new BCRSAPrivateKey((RSAPrivateKeySpec)keySpec);
+ }
+
+ throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof RSAPublicKeySpec)
+ {
+ return new BCRSAPublicKey((RSAPublicKeySpec)keySpec);
+ }
+
+ return super.engineGeneratePublic(keySpec);
+ }
+
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
+
+ if (RSAUtil.isRsaOid(algOid))
+ {
+ return new BCRSAPrivateCrtKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
+ {
+ ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm();
+
+ if (RSAUtil.isRsaOid(algOid))
+ {
+ return new BCRSAPublicKey(keyInfo);
+ }
+ else
+ {
+ throw new IOException("algorithm identifier " + algOid + " in key not recognised");
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
new file mode 100644
index 0000000..c61e7cb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi.java
@@ -0,0 +1,78 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.RSAKeyGenParameterSpec;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
+import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGenerator
+{
+ public KeyPairGeneratorSpi(
+ String algorithmName)
+ {
+ super(algorithmName);
+ }
+
+ final static BigInteger defaultPublicExponent = BigInteger.valueOf(0x10001);
+ final static int defaultTests = 12;
+
+ RSAKeyGenerationParameters param;
+ RSAKeyPairGenerator engine;
+
+ public KeyPairGeneratorSpi()
+ {
+ super("RSA");
+
+ engine = new RSAKeyPairGenerator();
+ param = new RSAKeyGenerationParameters(defaultPublicExponent,
+ new SecureRandom(), 2048, defaultTests);
+ engine.init(param);
+ }
+
+ public void initialize(
+ int strength,
+ SecureRandom random)
+ {
+ param = new RSAKeyGenerationParameters(defaultPublicExponent,
+ random, strength, defaultTests);
+
+ engine.init(param);
+ }
+
+ public void initialize(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof RSAKeyGenParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("parameter object not a RSAKeyGenParameterSpec");
+ }
+ RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
+
+ param = new RSAKeyGenerationParameters(
+ rsaParams.getPublicExponent(),
+ random, rsaParams.getKeysize(), defaultTests);
+
+ engine.init(param);
+ }
+
+ public KeyPair generateKeyPair()
+ {
+ AsymmetricCipherKeyPair pair = engine.generateKeyPair();
+ RSAKeyParameters pub = (RSAKeyParameters)pair.getPublic();
+ RSAPrivateCrtKeyParameters priv = (RSAPrivateCrtKeyParameters)pair.getPrivate();
+
+ return new KeyPair(new BCRSAPublicKey(pub),
+ new BCRSAPrivateCrtKey(priv));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
new file mode 100644
index 0000000..4943a99
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.jcajce.provider.asymmetric.rsa;
+
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+
+/**
+ * utility class for converting java.security RSA objects into their
+ * org.bouncycastle.crypto counterparts.
+ */
+public class RSAUtil
+{
+ public static final ASN1ObjectIdentifier[] rsaOids =
+ {
+ PKCSObjectIdentifiers.rsaEncryption,
+ X509ObjectIdentifiers.id_ea_rsa,
+ PKCSObjectIdentifiers.id_RSAES_OAEP,
+ PKCSObjectIdentifiers.id_RSASSA_PSS
+ };
+
+ public static boolean isRsaOid(
+ ASN1ObjectIdentifier algOid)
+ {
+ for (int i = 0; i != rsaOids.length; i++)
+ {
+ if (algOid.equals(rsaOids[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static RSAKeyParameters generatePublicKeyParameter(
+ RSAPublicKey key)
+ {
+ return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent());
+
+ }
+
+ static RSAKeyParameters generatePrivateKeyParameter(
+ RSAPrivateKey key)
+ {
+ if (key instanceof RSAPrivateCrtKey)
+ {
+ RSAPrivateCrtKey k = (RSAPrivateCrtKey)key;
+
+ return new RSAPrivateCrtKeyParameters(k.getModulus(),
+ k.getPublicExponent(), k.getPrivateExponent(),
+ k.getPrimeP(), k.getPrimeQ(), k.getPrimeExponentP(), k.getPrimeExponentQ(), k.getCrtCoefficient());
+ }
+ else
+ {
+ RSAPrivateKey k = key;
+
+ return new RSAKeyParameters(true, k.getModulus(), k.getPrivateExponent());
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
new file mode 100644
index 0000000..fabad43
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseCipherSpi.java
@@ -0,0 +1,220 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.security.AlgorithmParameters;
+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.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.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.InvalidCipherTextException;
+import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public abstract class BaseCipherSpi
+ extends CipherSpi
+{
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ IvParameterSpec.class,
+ PBEParameterSpec.class,
+ // BEGIN android-removed
+ // RC2ParameterSpec.class,
+ // RC5ParameterSpec.class
+ // END android-removed
+ };
+
+
+ protected AlgorithmParameters engineParams = null;
+
+ protected Wrapper wrapEngine = null;
+
+ private int ivSize;
+ private byte[] iv;
+
+ protected BaseCipherSpi()
+ {
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return 0;
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return null;
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return -1;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return null;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+
+ protected byte[] engineWrap(
+ Key key)
+ throws IllegalBlockSizeException, InvalidKeyException
+ {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null)
+ {
+ throw new InvalidKeyException("Cannot wrap key, null encoding.");
+ }
+
+ try
+ {
+ if (wrapEngine == null)
+ {
+ return engineDoFinal(encoded, 0, encoded.length);
+ }
+ else
+ {
+ return wrapEngine.wrap(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
+ {
+ if (wrapEngine == null)
+ {
+ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ }
+ else
+ {
+ encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
+ }
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ 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);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
new file mode 100644
index 0000000..621069a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseKeyFactorySpi.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.io.IOException;
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+public abstract class BaseKeyFactorySpi
+ extends java.security.KeyFactorySpi
+ implements AsymmetricKeyInfoConverter
+{
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ try
+ {
+ return generatePrivate(PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded()));
+ }
+ // BEGIN android-changed
+ catch (Exception e)
+ // END android-changed
+ {
+ throw new InvalidKeySpecException("encoded key spec not recognised");
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("key spec not recognised");
+ }
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof X509EncodedKeySpec)
+ {
+ try
+ {
+ return generatePublic(SubjectPublicKeyInfo.getInstance(((X509EncodedKeySpec)keySpec).getEncoded()));
+ }
+ // BEGIN android-changed
+ catch (Exception e)
+ // END android-changed
+ {
+ throw new InvalidKeySpecException("encoded key spec not recognised");
+ }
+ }
+ else
+ {
+ throw new InvalidKeySpecException("key spec not recognised");
+ }
+ }
+
+ protected KeySpec engineGetKeySpec(
+ Key key,
+ Class spec)
+ throws InvalidKeySpecException
+ {
+ if (spec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (spec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+
+ throw new InvalidKeySpecException("not implemented yet " + key + " " + spec);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java
new file mode 100644
index 0000000..463de89
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java
@@ -0,0 +1,112 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.math.BigInteger;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.crypto.DSA;
+import org.bouncycastle.crypto.Digest;
+
+public abstract class DSABase
+ extends SignatureSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers
+{
+ protected Digest digest;
+ protected DSA signer;
+ protected DSAEncoder encoder;
+
+ protected DSABase(
+ Digest digest,
+ DSA signer,
+ DSAEncoder encoder)
+ {
+ this.digest = digest;
+ this.signer = signer;
+ this.encoder = encoder;
+ }
+
+ protected void engineUpdate(
+ byte b)
+ throws SignatureException
+ {
+ digest.update(b);
+ }
+
+ protected void engineUpdate(
+ byte[] b,
+ int off,
+ int len)
+ throws SignatureException
+ {
+ digest.update(b, off, len);
+ }
+
+ protected byte[] engineSign()
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ try
+ {
+ BigInteger[] sig = signer.generateSignature(hash);
+
+ return encoder.encode(sig[0], sig[1]);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException(e.toString());
+ }
+ }
+
+ protected boolean engineVerify(
+ byte[] sigBytes)
+ throws SignatureException
+ {
+ byte[] hash = new byte[digest.getDigestSize()];
+
+ digest.doFinal(hash, 0);
+
+ BigInteger[] sig;
+
+ try
+ {
+ sig = encoder.decode(sigBytes);
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("error decoding signature bytes.");
+ }
+
+ return signer.verifySignature(hash, sig[0], sig[1]);
+ }
+
+ protected void engineSetParameter(
+ AlgorithmParameterSpec params)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated replaced with <a href = "#engineSetParameter(java.security.spec.AlgorithmParameterSpec)">
+ */
+ protected void engineSetParameter(
+ String param,
+ Object value)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+
+ /**
+ * @deprecated
+ */
+ protected Object engineGetParameter(
+ String param)
+ {
+ throw new UnsupportedOperationException("engineSetParameter unsupported");
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java
new file mode 100644
index 0000000..4ea0ff9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java
@@ -0,0 +1,13 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public interface DSAEncoder
+{
+ byte[] encode(BigInteger r, BigInteger s)
+ throws IOException;
+
+ BigInteger[] decode(byte[] sig)
+ throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java
new file mode 100644
index 0000000..7945639
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ExtendedInvalidKeySpecException.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.security.spec.InvalidKeySpecException;
+
+public class ExtendedInvalidKeySpecException
+ extends InvalidKeySpecException
+{
+ private Throwable cause;
+
+ public ExtendedInvalidKeySpecException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java
new file mode 100644
index 0000000..4dff91a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/KeyUtil.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public class KeyUtil
+{
+ public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, ASN1Encodable keyData)
+ {
+ try
+ {
+ return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedSubjectPublicKeyInfo(AlgorithmIdentifier algId, byte[] keyData)
+ {
+ try
+ {
+ return getEncodedSubjectPublicKeyInfo(new SubjectPublicKeyInfo(algId, keyData));
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedSubjectPublicKeyInfo(SubjectPublicKeyInfo info)
+ {
+ try
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedPrivateKeyInfo(AlgorithmIdentifier algId, ASN1Encodable privKey)
+ {
+ try
+ {
+ PrivateKeyInfo info = new PrivateKeyInfo(algId, privKey.toASN1Primitive());
+
+ return getEncodedPrivateKeyInfo(info);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ public static byte[] getEncodedPrivateKeyInfo(PrivateKeyInfo info)
+ {
+ try
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
new file mode 100644
index 0000000..06ccd66
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java
@@ -0,0 +1,125 @@
+package org.bouncycastle.jcajce.provider.asymmetric.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+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
+ implements PKCS12BagAttributeCarrier
+{
+ private Hashtable pkcs12Attributes;
+ private Vector pkcs12Ordering;
+
+ PKCS12BagAttributeCarrierImpl(Hashtable attributes, Vector ordering)
+ {
+ this.pkcs12Attributes = attributes;
+ this.pkcs12Ordering = ordering;
+ }
+
+ public PKCS12BagAttributeCarrierImpl()
+ {
+ this(new Hashtable(), new Vector());
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ if (pkcs12Attributes.containsKey(oid))
+ { // preserve original ordering
+ pkcs12Attributes.put(oid, attribute);
+ }
+ else
+ {
+ pkcs12Attributes.put(oid, attribute);
+ pkcs12Ordering.addElement(oid);
+ }
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return (ASN1Encodable)pkcs12Attributes.get(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return pkcs12Ordering.elements();
+ }
+
+ int size()
+ {
+ return pkcs12Ordering.size();
+ }
+
+ Hashtable getAttributes()
+ {
+ return pkcs12Attributes;
+ }
+
+ Vector getOrdering()
+ {
+ return pkcs12Ordering;
+ }
+
+ public void writeObject(ObjectOutputStream out)
+ throws IOException
+ {
+ if (pkcs12Ordering.size() == 0)
+ {
+ out.writeObject(new Hashtable());
+ out.writeObject(new Vector());
+ }
+ else
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ Enumeration e = this.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+
+ aOut.writeObject(oid);
+ aOut.writeObject((ASN1Encodable)pkcs12Attributes.get(oid));
+ }
+
+ out.writeObject(bOut.toByteArray());
+ }
+ }
+
+ public void readObject(ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ Object obj = in.readObject();
+
+ if (obj instanceof Hashtable)
+ {
+ this.pkcs12Attributes = (Hashtable)obj;
+ this.pkcs12Ordering = (Vector)in.readObject();
+ }
+ else
+ {
+ ASN1InputStream aIn = new ASN1InputStream((byte[])obj);
+
+ ASN1ObjectIdentifier oid;
+
+ while ((oid = (ASN1ObjectIdentifier)aIn.readObject()) != null)
+ {
+ this.setBagAttribute(oid, aIn.readObject());
+ }
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
new file mode 100644
index 0000000..33f3db7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/CertificateFactory.java
@@ -0,0 +1,397 @@
+package org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactorySpi;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.SignedData;
+import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.jce.provider.X509CRLObject;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class for dealing with X509 certificates.
+ * <p>
+ * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
+ * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
+ * objects.
+ */
+public class CertificateFactory
+ extends CertificateFactorySpi
+{
+ private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE");
+ private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
+
+ private ASN1Set sData = null;
+ private int sDataObjectCount = 0;
+ private InputStream currentStream = null;
+
+ private ASN1Set sCrlData = null;
+ private int sCrlDataObjectCount = 0;
+ private InputStream currentCrlStream = null;
+
+ private java.security.cert.Certificate readDERCertificate(
+ ASN1InputStream dIn)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
+
+ return getCertificate();
+ }
+ }
+
+ return new X509CertificateObject(
+ X509CertificateStructure.getInstance(seq));
+ }
+
+ private java.security.cert.Certificate getCertificate()
+ throws CertificateParsingException
+ {
+ if (sData != null)
+ {
+ while (sDataObjectCount < sData.size())
+ {
+ Object obj = sData.getObjectAt(sDataObjectCount++);
+
+ if (obj instanceof ASN1Sequence)
+ {
+ return new X509CertificateObject(
+ X509CertificateStructure.getInstance(obj));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private java.security.cert.Certificate readPEMCertificate(
+ InputStream in)
+ throws IOException, CertificateParsingException
+ {
+ ASN1Sequence seq = PEM_CERT_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return new X509CertificateObject(
+ X509CertificateStructure.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ protected CRL createCRL(CertificateList c)
+ throws CRLException
+ {
+ return new X509CRLObject(c);
+ }
+
+ private CRL readPEMCRL(
+ InputStream in)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = PEM_CRL_PARSER.readPEMObject(in);
+
+ if (seq != null)
+ {
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ return null;
+ }
+
+ private CRL readDERCRL(
+ ASN1InputStream aIn)
+ throws IOException, CRLException
+ {
+ ASN1Sequence seq = (ASN1Sequence)aIn.readObject();
+
+ if (seq.size() > 1
+ && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
+ {
+ if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
+ {
+ sCrlData = SignedData.getInstance(ASN1Sequence.getInstance(
+ (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
+
+ return getCRL();
+ }
+ }
+
+ return createCRL(
+ CertificateList.getInstance(seq));
+ }
+
+ private CRL getCRL()
+ throws CRLException
+ {
+ if (sCrlData == null || sCrlDataObjectCount >= sCrlData.size())
+ {
+ return null;
+ }
+
+ return createCRL(
+ CertificateList.getInstance(
+ sCrlData.getObjectAt(sCrlDataObjectCount++)));
+ }
+
+ /**
+ * Generates a certificate object and initializes it with the data
+ * read from the input stream inStream.
+ */
+ public java.security.cert.Certificate engineGenerateCertificate(
+ InputStream in)
+ throws CertificateException
+ {
+ if (currentStream == null)
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+ else if (currentStream != in) // reset if input stream has changed
+ {
+ currentStream = in;
+ sData = null;
+ sDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sData != null)
+ {
+ if (sDataObjectCount != sData.size())
+ {
+ return getCertificate();
+ }
+ else
+ {
+ sData = null;
+ sDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(in);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCertificate(pis);
+ }
+ else
+ {
+ return readDERCertificate(new ASN1InputStream(pis));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ExCertificateException(e);
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the certificates
+ * read from the given input stream inStream.
+ */
+ public Collection engineGenerateCertificates(
+ InputStream inStream)
+ throws CertificateException
+ {
+ java.security.cert.Certificate cert;
+ List certs = new ArrayList();
+
+ while ((cert = engineGenerateCertificate(inStream)) != null)
+ {
+ certs.add(cert);
+ }
+
+ return certs;
+ }
+
+ /**
+ * Generates a certificate revocation list (CRL) object and initializes
+ * it with the data read from the input stream inStream.
+ */
+ public CRL engineGenerateCRL(
+ InputStream inStream)
+ throws CRLException
+ {
+ if (currentCrlStream == null)
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+ else if (currentCrlStream != inStream) // reset if input stream has changed
+ {
+ currentCrlStream = inStream;
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ }
+
+ try
+ {
+ if (sCrlData != null)
+ {
+ if (sCrlDataObjectCount != sCrlData.size())
+ {
+ return getCRL();
+ }
+ else
+ {
+ sCrlData = null;
+ sCrlDataObjectCount = 0;
+ return null;
+ }
+ }
+
+ PushbackInputStream pis = new PushbackInputStream(inStream);
+ int tag = pis.read();
+
+ if (tag == -1)
+ {
+ return null;
+ }
+
+ pis.unread(tag);
+
+ if (tag != 0x30) // assume ascii PEM encoded.
+ {
+ return readPEMCRL(pis);
+ }
+ else
+ { // lazy evaluate to help processing of large CRLs
+ return readDERCRL(new ASN1InputStream(pis, true));
+ }
+ }
+ catch (CRLException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ /**
+ * Returns a (possibly empty) collection view of the CRLs read from
+ * the given input stream inStream.
+ *
+ * The inStream may contain a sequence of DER-encoded CRLs, or
+ * a PKCS#7 CRL set. This is a PKCS#7 SignedData object, with the
+ * only signficant field being crls. In particular the signature
+ * and the contents are ignored.
+ */
+ public Collection engineGenerateCRLs(
+ InputStream inStream)
+ throws CRLException
+ {
+ CRL crl;
+ List crls = new ArrayList();
+
+ while ((crl = engineGenerateCRL(inStream)) != null)
+ {
+ crls.add(crl);
+ }
+
+ return crls;
+ }
+
+ public Iterator engineGetCertPathEncodings()
+ {
+ return null; // TODO: PKIXCertPath.certPathEncodings.iterator();
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream)
+ throws CertificateException
+ {
+ return engineGenerateCertPath(inStream, "PkiPath");
+ }
+
+ public CertPath engineGenerateCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ return new PKIXCertPath(inStream, encoding);
+ }
+
+ public CertPath engineGenerateCertPath(
+ List certificates)
+ throws CertificateException
+ {
+ Iterator iter = certificates.iterator();
+ Object obj;
+ while (iter.hasNext())
+ {
+ obj = iter.next();
+ if (obj != null)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ throw new CertificateException("list contains non X509Certificate object while creating CertPath\n" + obj.toString());
+ }
+ }
+ }
+ return new PKIXCertPath(certificates);
+ }
+
+ private class ExCertificateException
+ extends CertificateException
+ {
+ private Throwable cause;
+
+ public ExCertificateException(Throwable cause)
+ {
+ this.cause = cause;
+ }
+
+ public ExCertificateException(String msg, Throwable cause)
+ {
+ super(msg);
+
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java
new file mode 100644
index 0000000..a4c701d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/KeyFactory.java
@@ -0,0 +1,95 @@
+package org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactorySpi;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+public class KeyFactory
+ extends KeyFactorySpi
+{
+
+ protected PrivateKey engineGeneratePrivate(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PKCS8EncodedKeySpec)
+ {
+ try
+ {
+ PrivateKeyInfo info = PrivateKeyInfo.getInstance(((PKCS8EncodedKeySpec)keySpec).getEncoded());
+ PrivateKey key = BouncyCastleProvider.getPrivateKey(info);
+
+ if (key != null)
+ {
+ return key;
+ }
+
+ throw new InvalidKeySpecException("no factory found for OID: " + info.getPrivateKeyAlgorithm().getAlgorithm());
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+ }
+
+ protected PublicKey engineGeneratePublic(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof X509EncodedKeySpec)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(((X509EncodedKeySpec)keySpec).getEncoded());
+ PublicKey key = BouncyCastleProvider.getPublicKey(info);
+
+ if (key != null)
+ {
+ return key;
+ }
+
+ throw new InvalidKeySpecException("no factory found for OID: " + info.getAlgorithm().getAlgorithm());
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName());
+ }
+
+ protected KeySpec engineGetKeySpec(Key key, Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class) && key.getFormat().equals("PKCS#8"))
+ {
+ return new PKCS8EncodedKeySpec(key.getEncoded());
+ }
+ else if (keySpec.isAssignableFrom(X509EncodedKeySpec.class) && key.getFormat().equals("X.509"))
+ {
+ return new X509EncodedKeySpec(key.getEncoded());
+ }
+
+ throw new InvalidKeySpecException("not implemented yet " + key + " " + keySpec);
+ }
+
+ protected Key engineTranslateKey(Key key)
+ throws InvalidKeyException
+ {
+ throw new InvalidKeyException("not implemented yet " + key);
+ }
+} \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
new file mode 100644
index 0000000..8699c3c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java
@@ -0,0 +1,93 @@
+package org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.util.encoders.Base64;
+
+public class PEMUtil
+{
+ private final String _header1;
+ private final String _header2;
+ private final String _footer1;
+ private final String _footer2;
+
+ PEMUtil(
+ String type)
+ {
+ _header1 = "-----BEGIN " + type + "-----";
+ _header2 = "-----BEGIN X509 " + type + "-----";
+ _footer1 = "-----END " + type + "-----";
+ _footer2 = "-----END X509 " + type + "-----";
+ }
+
+ private String readLine(
+ InputStream in)
+ throws IOException
+ {
+ int c;
+ StringBuffer l = new StringBuffer();
+
+ do
+ {
+ while (((c = in.read()) != '\r') && c != '\n' && (c >= 0))
+ {
+ if (c == '\r')
+ {
+ continue;
+ }
+
+ l.append((char)c);
+ }
+ }
+ while (c >= 0 && l.length() == 0);
+
+ if (c < 0)
+ {
+ return null;
+ }
+
+ return l.toString();
+ }
+
+ ASN1Sequence readPEMObject(
+ InputStream in)
+ throws IOException
+ {
+ String line;
+ StringBuffer pemBuf = new StringBuffer();
+
+ while ((line = readLine(in)) != null)
+ {
+ if (line.startsWith(_header1) || line.startsWith(_header2))
+ {
+ break;
+ }
+ }
+
+ while ((line = readLine(in)) != null)
+ {
+ if (line.startsWith(_footer1) || line.startsWith(_footer2))
+ {
+ break;
+ }
+
+ pemBuf.append(line);
+ }
+
+ if (pemBuf.length() != 0)
+ {
+ try
+ {
+ return ASN1Sequence.getInstance(Base64.decode(pemBuf.toString()));
+ }
+ catch (Exception e)
+ {
+ throw new IOException("malformed PEM data encountered");
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
new file mode 100644
index 0000000..e13412d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java
@@ -0,0 +1,376 @@
+package org.bouncycastle.jcajce.provider.asymmetric.x509;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.security.NoSuchProviderException;
+import java.security.cert.CertPath;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+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.util.io.pem.PemObject;
+// BEGIN android-removed
+// import org.bouncycastle.util.io.pem.PemWriter;
+// END android-removed
+
+/**
+ * CertPath implementation for X.509 certificates.
+ * <br />
+ **/
+public class PKIXCertPath
+ extends CertPath
+{
+ static final List certPathEncodings;
+
+ static
+ {
+ List encodings = new ArrayList();
+ encodings.add("PkiPath");
+ encodings.add("PEM");
+ encodings.add("PKCS7");
+ certPathEncodings = Collections.unmodifiableList(encodings);
+ }
+
+ private List certificates;
+
+ /**
+ * @param certs
+ */
+ private List sortCerts(
+ List certs)
+ {
+ if (certs.size() < 2)
+ {
+ return certs;
+ }
+
+ X500Principal issuer = ((X509Certificate)certs.get(0)).getIssuerX500Principal();
+ boolean okay = true;
+
+ for (int i = 1; i != certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+
+ if (issuer.equals(cert.getSubjectX500Principal()))
+ {
+ issuer = ((X509Certificate)certs.get(i)).getIssuerX500Principal();
+ }
+ else
+ {
+ okay = false;
+ break;
+ }
+ }
+
+ if (okay)
+ {
+ return certs;
+ }
+
+ // find end-entity cert
+ List retList = new ArrayList(certs.size());
+ List orig = new ArrayList(certs);
+
+ for (int i = 0; i < certs.size(); i++)
+ {
+ X509Certificate cert = (X509Certificate)certs.get(i);
+ boolean found = false;
+
+ X500Principal subject = cert.getSubjectX500Principal();
+
+ for (int j = 0; j != certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (c.getIssuerX500Principal().equals(subject))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ retList.add(cert);
+ certs.remove(i);
+ }
+ }
+
+ // can only have one end entity cert - something's wrong, give up.
+ if (retList.size() > 1)
+ {
+ return orig;
+ }
+
+ for (int i = 0; i != retList.size(); i++)
+ {
+ issuer = ((X509Certificate)retList.get(i)).getIssuerX500Principal();
+
+ for (int j = 0; j < certs.size(); j++)
+ {
+ X509Certificate c = (X509Certificate)certs.get(j);
+ if (issuer.equals(c.getSubjectX500Principal()))
+ {
+ retList.add(c);
+ certs.remove(j);
+ break;
+ }
+ }
+ }
+
+ // make sure all certificates are accounted for.
+ if (certs.size() > 0)
+ {
+ return orig;
+ }
+
+ return retList;
+ }
+
+ PKIXCertPath(List certificates)
+ {
+ super("X.509");
+ this.certificates = sortCerts(new ArrayList(certificates));
+ }
+
+ /**
+ * Creates a CertPath of the specified type.
+ * This constructor is protected because most users should use
+ * a CertificateFactory to create CertPaths.
+ **/
+ PKIXCertPath(
+ InputStream inStream,
+ String encoding)
+ throws CertificateException
+ {
+ super("X.509");
+ try
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Primitive derObject = derInStream.readObject();
+ if (!(derObject instanceof ASN1Sequence))
+ {
+ throw new CertificateException("input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+ }
+ Enumeration e = ((ASN1Sequence)derObject).getObjects();
+ certificates = new ArrayList();
+ CertificateFactory certFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ while (e.hasMoreElements())
+ {
+ ASN1Encodable element = (ASN1Encodable)e.nextElement();
+ byte[] encoded = element.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ certificates.add(0, certFactory.generateCertificate(
+ new ByteArrayInputStream(encoded)));
+ }
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7") || encoding.equalsIgnoreCase("PEM"))
+ {
+ inStream = new BufferedInputStream(inStream);
+ certificates = new ArrayList();
+ CertificateFactory certFactory= CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ Certificate cert;
+ while ((cert = certFactory.generateCertificate(inStream)) != null)
+ {
+ certificates.add(cert);
+ }
+ }
+ else
+ {
+ throw new CertificateException("unsupported encoding: " + encoding);
+ }
+ }
+ catch (IOException ex)
+ {
+ throw new CertificateException("IOException throw while decoding CertPath:\n" + ex.toString());
+ }
+ catch (NoSuchProviderException ex)
+ {
+ throw new CertificateException("BouncyCastle provider not found while trying to get a CertificateFactory:\n" + ex.toString());
+ }
+
+ this.certificates = sortCerts(certificates);
+ }
+
+ /**
+ * Returns an iteration of the encodings supported by this
+ * certification path, with the default encoding
+ * first. Attempts to modify the returned Iterator via its
+ * remove method result in an UnsupportedOperationException.
+ *
+ * @return an Iterator over the names of the supported encodings (as Strings)
+ **/
+ public Iterator getEncodings()
+ {
+ return certPathEncodings.iterator();
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the default encoding.
+ *
+ * @return the encoded bytes
+ * @exception java.security.cert.CertificateEncodingException if an encoding error occurs
+ **/
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ Iterator iter = getEncodings();
+ if (iter.hasNext())
+ {
+ Object enc = iter.next();
+ if (enc instanceof String)
+ {
+ return getEncoded((String)enc);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the encoded form of this certification path, using
+ * the specified encoding.
+ *
+ * @param encoding the name of the encoding to use
+ * @return the encoded bytes
+ * @exception java.security.cert.CertificateEncodingException if an encoding error
+ * occurs or the encoding requested is not supported
+ *
+ **/
+ public byte[] getEncoded(String encoding)
+ throws CertificateEncodingException
+ {
+ if (encoding.equalsIgnoreCase("PkiPath"))
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ ListIterator iter = certificates.listIterator(certificates.size());
+ while (iter.hasPrevious())
+ {
+ v.add(toASN1Object((X509Certificate)iter.previous()));
+ }
+
+ return toDEREncoded(new DERSequence(v));
+ }
+ else if (encoding.equalsIgnoreCase("PKCS7"))
+ {
+ ContentInfo encInfo = new ContentInfo(PKCSObjectIdentifiers.data, null);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ for (int i = 0; i != certificates.size(); i++)
+ {
+ v.add(toASN1Object((X509Certificate)certificates.get(i)));
+ }
+
+ SignedData sd = new SignedData(
+ new ASN1Integer(1),
+ new DERSet(),
+ encInfo,
+ new DERSet(v),
+ null,
+ new DERSet());
+
+ return toDEREncoded(new ContentInfo(
+ PKCSObjectIdentifiers.signedData, sd));
+ }
+ // BEGIN android-removed
+ // else if (encoding.equalsIgnoreCase("PEM"))
+ // {
+ // ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ // PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
+ //
+ // try
+ // {
+ // for (int i = 0; i != certificates.size(); i++)
+ // {
+ // pWrt.writeObject(new PemObject("CERTIFICATE", ((X509Certificate)certificates.get(i)).getEncoded()));
+ // }
+ //
+ // pWrt.close();
+ // }
+ // catch (Exception e)
+ // {
+ // throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+ // }
+ //
+ // return bOut.toByteArray();
+ // }
+ // END android-removed
+ else
+ {
+ throw new CertificateEncodingException("unsupported encoding: " + encoding);
+ }
+ }
+
+ /**
+ * Returns the list of certificates in this certification
+ * path. The List returned must be immutable and thread-safe.
+ *
+ * @return an immutable List of Certificates (may be empty, but not null)
+ **/
+ public List getCertificates()
+ {
+ return Collections.unmodifiableList(new ArrayList(certificates));
+ }
+
+ /**
+ * Return a DERObject containing the encoded certificate.
+ *
+ * @param cert the X509Certificate object to be encoded
+ *
+ * @return the DERObject
+ **/
+ private ASN1Primitive toASN1Object(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return new ASN1InputStream(cert.getEncoded()).readObject();
+ }
+ catch (Exception e)
+ {
+ throw new CertificateEncodingException("Exception while encoding certificate: " + e.toString());
+ }
+ }
+
+ private byte[] toDEREncoded(ASN1Encodable obj)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return obj.toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException("Exception thrown: " + e);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
new file mode 100644
index 0000000..692b0d7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ConfigurableProvider.java
@@ -0,0 +1,41 @@
+package org.bouncycastle.jcajce.provider.config;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * Implemented by the BC provider. This allows setting of hidden parameters,
+ * such as the ImplicitCA parameters from X.962, if used.
+ */
+public interface ConfigurableProvider
+{
+ /**
+ * Elliptic Curve CA parameters - thread local version
+ */
+ static final String THREAD_LOCAL_EC_IMPLICITLY_CA = "threadLocalEcImplicitlyCa";
+
+ /**
+ * Elliptic Curve CA parameters - thread local version
+ */
+ static final String EC_IMPLICITLY_CA = "ecImplicitlyCa";
+
+ /**
+ * Diffie-Hellman Default Parameters - thread local version
+ */
+ static final String THREAD_LOCAL_DH_DEFAULT_PARAMS = "threadLocalDhDefaultParams";
+
+ /**
+ * Diffie-Hellman Default Parameters - VM wide version
+ */
+ static final String DH_DEFAULT_PARAMS = "DhDefaultParams";
+
+ void setParameter(String parameterName, Object parameter);
+
+ void addAlgorithm(String key, String value);
+
+ boolean hasAlgorithm(String type, String name);
+
+ void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter);
+
+ AsymmetricKeyInfoConverter getConverter(ASN1ObjectIdentifier oid);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java
new file mode 100644
index 0000000..2b7efe9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfiguration.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.jcajce.provider.config;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.jce.spec.ECParameterSpec;
+
+public interface ProviderConfiguration
+{
+ ECParameterSpec getEcImplicitlyCa();
+
+ DHParameterSpec getDHDefaultParameters();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
new file mode 100644
index 0000000..b21afc5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/config/ProviderConfigurationPermission.java
@@ -0,0 +1,146 @@
+package org.bouncycastle.jcajce.provider.config;
+
+import java.security.BasicPermission;
+import java.security.Permission;
+import java.util.StringTokenizer;
+
+import org.bouncycastle.util.Strings;
+
+/**
+ * A permission class to define what can be done with the ConfigurableProvider interface.
+ * <p>
+ * Available permissions are "threadLocalEcImplicitlyCa" and "ecImplicitlyCa" which allow the setting
+ * of the thread local and global ecImplicitlyCa parameters respectively.
+ * </p>
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>ProviderConfigurationPermission("BC"); // enable all permissions</li>
+ * <li>ProviderConfigurationPermission("BC", "threadLocalEcImplicitlyCa"); // enable thread local only</li>
+ * <li>ProviderConfigurationPermission("BC", "ecImplicitlyCa"); // enable global setting only</li>
+ * <li>ProviderConfigurationPermission("BC", "threadLocalEcImplicitlyCa, ecImplicitlyCa"); // enable both explicitly</li>
+ * </ul>
+ * <p>
+ * Note: permission checks are only enforced if a security manager is present.
+ * </p>
+ */
+public class ProviderConfigurationPermission
+ extends BasicPermission
+{
+ private static final int THREAD_LOCAL_EC_IMPLICITLY_CA = 0x01;
+ private static final int EC_IMPLICITLY_CA = 0x02;
+ private static final int THREAD_LOCAL_DH_DEFAULT_PARAMS = 0x04;
+ private static final int DH_DEFAULT_PARAMS = 0x08;
+
+ private static final int ALL = THREAD_LOCAL_EC_IMPLICITLY_CA | EC_IMPLICITLY_CA | THREAD_LOCAL_DH_DEFAULT_PARAMS | DH_DEFAULT_PARAMS;
+
+ private static final String THREAD_LOCAL_EC_IMPLICITLY_CA_STR = "threadlocalecimplicitlyca";
+ private static final String EC_IMPLICITLY_CA_STR = "ecimplicitlyca";
+ private static final String THREAD_LOCAL_DH_DEFAULT_PARAMS_STR = "threadlocaldhdefaultparams";
+ private static final String DH_DEFAULT_PARAMS_STR = "dhdefaultparams";
+
+ private static final String ALL_STR = "all";
+
+ private final String actions;
+ private final int permissionMask;
+
+ public ProviderConfigurationPermission(String name)
+ {
+ super(name);
+ this.actions = "all";
+ this.permissionMask = ALL;
+ }
+
+ public ProviderConfigurationPermission(String name, String actions)
+ {
+ super(name, actions);
+ this.actions = actions;
+ this.permissionMask = calculateMask(actions);
+ }
+
+ private int calculateMask(
+ String actions)
+ {
+ StringTokenizer tok = new StringTokenizer(Strings.toLowerCase(actions), " ,");
+ int mask = 0;
+
+ while (tok.hasMoreTokens())
+ {
+ String s = tok.nextToken();
+
+ if (s.equals(THREAD_LOCAL_EC_IMPLICITLY_CA_STR))
+ {
+ mask |= THREAD_LOCAL_EC_IMPLICITLY_CA;
+ }
+ else if (s.equals(EC_IMPLICITLY_CA_STR))
+ {
+ mask |= EC_IMPLICITLY_CA;
+ }
+ else if (s.equals(THREAD_LOCAL_DH_DEFAULT_PARAMS_STR))
+ {
+ mask |= THREAD_LOCAL_DH_DEFAULT_PARAMS;
+ }
+ else if (s.equals(DH_DEFAULT_PARAMS_STR))
+ {
+ mask |= DH_DEFAULT_PARAMS;
+ }
+ else if (s.equals(ALL_STR))
+ {
+ mask |= ALL;
+ }
+ }
+
+ if (mask == 0)
+ {
+ throw new IllegalArgumentException("unknown permissions passed to mask");
+ }
+
+ return mask;
+ }
+
+ public String getActions()
+ {
+ return actions;
+ }
+
+ public boolean implies(
+ Permission permission)
+ {
+ if (!(permission instanceof ProviderConfigurationPermission))
+ {
+ return false;
+ }
+
+ if (!this.getName().equals(permission.getName()))
+ {
+ return false;
+ }
+
+ ProviderConfigurationPermission other = (ProviderConfigurationPermission)permission;
+
+ return (this.permissionMask & other.permissionMask) == other.permissionMask;
+ }
+
+ public boolean equals(
+ Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (obj instanceof ProviderConfigurationPermission)
+ {
+ ProviderConfigurationPermission other = (ProviderConfigurationPermission)obj;
+
+ return this.permissionMask == other.permissionMask && this.getName().equals(other.getName());
+ }
+
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return this.getName().hashCode() + this.permissionMask;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java
new file mode 100644
index 0000000..3c5b78d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/BCMessageDigest.java
@@ -0,0 +1,47 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import java.security.MessageDigest;
+
+import org.bouncycastle.crypto.Digest;
+
+public class BCMessageDigest
+ extends MessageDigest
+{
+ protected Digest digest;
+
+ protected BCMessageDigest(
+ Digest digest)
+ {
+ super(digest.getAlgorithmName());
+
+ this.digest = digest;
+ }
+
+ public void engineReset()
+ {
+ digest.reset();
+ }
+
+ public void engineUpdate(
+ byte input)
+ {
+ digest.update(input);
+ }
+
+ public void engineUpdate(
+ byte[] input,
+ int offset,
+ int len)
+ {
+ digest.update(input, offset, len);
+ }
+
+ public byte[] engineDigest()
+ {
+ byte[] digestBytes = new byte[digest.getDigestSize()];
+
+ digest.doFinal(digestBytes, 0);
+
+ return digestBytes;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java
new file mode 100644
index 0000000..2325f59
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/DigestAlgorithmProvider.java
@@ -0,0 +1,36 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+abstract class DigestAlgorithmProvider
+ extends AlgorithmProvider
+{
+ protected void addHMACAlgorithm(
+ ConfigurableProvider provider,
+ String algorithm,
+ String algorithmClassName,
+ String keyGeneratorClassName)
+ {
+ String mainName = "HMAC" + algorithm;
+
+ provider.addAlgorithm("Mac." + mainName, algorithmClassName);
+ provider.addAlgorithm("Alg.Alias.Mac.HMAC-" + algorithm, mainName);
+ provider.addAlgorithm("Alg.Alias.Mac.HMAC/" + algorithm, mainName);
+ provider.addAlgorithm("KeyGenerator." + mainName, keyGeneratorClassName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.HMAC-" + algorithm, mainName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.HMAC/" + algorithm, mainName);
+ }
+
+ protected void addHMACAlias(
+ ConfigurableProvider provider,
+ String algorithm,
+ ASN1ObjectIdentifier oid)
+ {
+ String mainName = "HMAC" + algorithm;
+
+ provider.addAlgorithm("Alg.Alias.Mac." + oid, mainName);
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + oid, mainName);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java
new file mode 100644
index 0000000..6834e3c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java
@@ -0,0 +1,72 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class MD5
+{
+ /**
+ * MD5 HMac
+ */
+ public static class HashMac
+ extends JCEMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new MD5Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACMD5", 128, new CipherKeyGenerator());
+ }
+ }
+
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new MD5Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new MD5Digest((MD5Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = MD5.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.MD5", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + PKCSObjectIdentifiers.md5, "MD5");
+
+ addHMACAlgorithm(provider, "MD5", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "MD5", IANAObjectIdentifiers.hmacMD5);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
new file mode 100644
index 0000000..2a9eceb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
@@ -0,0 +1,76 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class SHA1
+{
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SHA1Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SHA1Digest((SHA1Digest)digest);
+
+ return d;
+ }
+ }
+
+ /**
+ * SHA1 HMac
+ */
+ public static class HashMac
+ extends JCEMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new SHA1Digest()));
+ }
+ }
+
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACSHA1", 160, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA1.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA-1", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA1", "SHA-1");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA", "SHA-1");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + OIWObjectIdentifiers.idSHA1, "SHA-1");
+
+ addHMACAlgorithm(provider, "SHA1", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "SHA1", PKCSObjectIdentifiers.id_hmacWithSHA1);
+ addHMACAlias(provider, "SHA1", IANAObjectIdentifiers.hmacSHA1);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
new file mode 100644
index 0000000..4e25c39
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA256.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class SHA256
+{
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SHA256Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SHA256Digest((SHA256Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class HashMac
+ extends JCEMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new SHA256Digest()));
+ }
+ }
+
+ /**
+ * HMACSHA256
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACSHA256", 256, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA256.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA-256", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA256", "SHA-256");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha256, "SHA-256");
+
+ addHMACAlgorithm(provider, "SHA256", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "SHA256", PKCSObjectIdentifiers.id_hmacWithSHA256);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
new file mode 100644
index 0000000..c724310
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA384.java
@@ -0,0 +1,73 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class SHA384
+{
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SHA384Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SHA384Digest((SHA384Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class HashMac
+ extends JCEMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new SHA384Digest()));
+ }
+ }
+
+ /**
+ * HMACSHA384
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACSHA384", 384, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA384.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA-384", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA384", "SHA-384");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha384, "SHA-384");
+
+ addHMACAlgorithm(provider, "SHA384", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "SHA384", PKCSObjectIdentifiers.id_hmacWithSHA384);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
new file mode 100644
index 0000000..cae9e7b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA512.java
@@ -0,0 +1,74 @@
+package org.bouncycastle.jcajce.provider.digest;
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jce.provider.JCEMac;
+
+public class SHA512
+{
+ static public class Digest
+ extends BCMessageDigest
+ implements Cloneable
+ {
+ public Digest()
+ {
+ super(new SHA512Digest());
+ }
+
+ public Object clone()
+ throws CloneNotSupportedException
+ {
+ Digest d = (Digest)super.clone();
+ d.digest = new SHA512Digest((SHA512Digest)digest);
+
+ return d;
+ }
+ }
+
+ public static class HashMac
+ extends JCEMac
+ {
+ public HashMac()
+ {
+ super(new HMac(new SHA512Digest()));
+ }
+ }
+
+ /**
+ * HMACSHA512
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("HMACSHA512", 512, new CipherKeyGenerator());
+ }
+ }
+
+ public static class Mappings
+ extends DigestAlgorithmProvider
+ {
+ private static final String PREFIX = SHA512.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("MessageDigest.SHA-512", PREFIX + "$Digest");
+ provider.addAlgorithm("Alg.Alias.MessageDigest.SHA512", "SHA-512");
+ provider.addAlgorithm("Alg.Alias.MessageDigest." + NISTObjectIdentifiers.id_sha512, "SHA-512");
+
+ addHMACAlgorithm(provider, "SHA512", PREFIX + "$HashMac", PREFIX + "$KeyGenerator");
+ addHMACAlias(provider, "SHA512", PKCSObjectIdentifiers.id_hmacWithSHA512);
+ }
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
new file mode 100644
index 0000000..1e12ee3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/AES.java
@@ -0,0 +1,295 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+// BEGIN android-removed
+// import java.security.AlgorithmParameters;
+// import java.security.InvalidAlgorithmParameterException;
+// END android-removed
+import java.security.SecureRandom;
+// BEGIN android-removed
+// import java.security.spec.AlgorithmParameterSpec;
+//
+// import javax.crypto.spec.IvParameterSpec;
+// END android-removed
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherKeyGenerator;
+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.macs.CMac;
+// END android-removed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+// BEGIN android-removed
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+// END android-removed
+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.BaseWrapCipher;
+import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+// BEGIN android-removed
+// import org.bouncycastle.jce.provider.BouncyCastleProvider;
+// END android-removed
+
+public final class AES
+{
+ private AES()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new AESFastEngine());
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new AESFastEngine()), 128);
+ }
+ }
+
+ static public class CFB
+ extends BaseBlockCipher
+ {
+ public CFB()
+ {
+ super(new BufferedBlockCipher(new CFBBlockCipher(new AESFastEngine(), 128)), 128);
+ }
+ }
+
+ static public class OFB
+ extends BaseBlockCipher
+ {
+ public OFB()
+ {
+ super(new BufferedBlockCipher(new OFBBlockCipher(new AESFastEngine(), 128)), 128);
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class AESCMAC
+ // extends BaseMac
+ // {
+ // public AESCMAC()
+ // {
+ // super(new CMac(new AESFastEngine()));
+ // }
+ // }
+ // END android-removed
+
+ static public class Wrap
+ extends BaseWrapCipher
+ {
+ public Wrap()
+ {
+ super(new AESWrapEngine());
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class RFC3211Wrap
+ // extends BaseWrapCipher
+ // {
+ // public RFC3211Wrap()
+ // {
+ // super(new RFC3211WrapEngine(new AESFastEngine()), 16);
+ // }
+ // }
+ // END android-removed
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ this(192);
+ }
+
+ public KeyGen(int keySize)
+ {
+ super("AES", keySize, new CipherKeyGenerator());
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class KeyGen128
+ // extends KeyGen
+ // {
+ // public KeyGen128()
+ // {
+ // super(128);
+ // }
+ // }
+ //
+ // public static class KeyGen192
+ // extends KeyGen
+ // {
+ // public KeyGen192()
+ // {
+ // super(192);
+ // }
+ // }
+ //
+ // public static class KeyGen256
+ // extends KeyGen
+ // {
+ // public KeyGen256()
+ // {
+ // super(256);
+ // }
+ // }
+ //
+ // public static class AlgParamGen
+ // 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[16];
+ //
+ // if (random == null)
+ // {
+ // random = new SecureRandom();
+ // }
+ //
+ // random.nextBytes(iv);
+ //
+ // AlgorithmParameters params;
+ //
+ // try
+ // {
+ // params = AlgorithmParameters.getInstance("AES", BouncyCastleProvider.PROVIDER_NAME);
+ // params.init(new IvParameterSpec(iv));
+ // }
+ // catch (Exception e)
+ // {
+ // throw new RuntimeException(e.getMessage());
+ // }
+ //
+ // return params;
+ // }
+ // }
+ // END android-removed
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "AES IV";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = AES.class.getName();
+
+ /**
+ * These three got introduced in some messages as a result of a typo in an
+ * early document. We don't produce anything using these OID values, but we'll
+ * read them.
+ */
+ private static final String wrongAES128 = "2.16.840.1.101.3.4.2";
+ private static final String wrongAES192 = "2.16.840.1.101.3.4.22";
+ private static final String wrongAES256 = "2.16.840.1.101.3.4.42";
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("AlgorithmParameters.AES", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES128, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES192, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + wrongAES256, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+
+ // BEGIN android-removed
+ // provider.addAlgorithm("AlgorithmParameterGenerator.AES", PREFIX + "$AlgParamGen");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES128, "AES");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES192, "AES");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + wrongAES256, "AES");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes128_CBC, "AES");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes192_CBC, "AES");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + NISTObjectIdentifiers.id_aes256_CBC, "AES");
+ // END android-removed
+
+ provider.addAlgorithm("Cipher.AES", PREFIX + "$ECB");
+ provider.addAlgorithm("Alg.Alias.Cipher." + wrongAES128, "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");
+ // 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");
+ // BEGIN android-removed
+ // provider.addAlgorithm("Cipher.AESRFC3211WRAP", PREFIX + "$RFC3211Wrap");
+ // END android-removed
+
+ 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.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("Mac.AESCMAC", PREFIX + "$AESCMAC");
+ // END android-removed
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
new file mode 100644
index 0000000..1bbdae7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARC4.java
@@ -0,0 +1,58 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.engines.RC4Engine;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class ARC4
+{
+ private ARC4()
+ {
+ }
+
+ public static class Base
+ extends BaseStreamCipher
+ {
+ public Base()
+ {
+ super(new RC4Engine(), 0);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ // BEGIN android-changed
+ super("ARC4", 128, new CipherKeyGenerator());
+ // END android-changed
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = ARC4.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.ARC4", PREFIX + "$Base");
+ provider.addAlgorithm("Alg.Alias.Cipher.1.2.840.113549.3.4", "ARC4");
+ provider.addAlgorithm("Alg.Alias.Cipher.ARCFOUR", "ARC4");
+ provider.addAlgorithm("Alg.Alias.Cipher.RC4", "ARC4");
+ provider.addAlgorithm("KeyGenerator.ARC4", PREFIX + "$KeyGen");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.RC4", "ARC4");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator.1.2.840.113549.3.4", "ARC4");
+
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
new file mode 100644
index 0000000..0e37487
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
@@ -0,0 +1,77 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.engines.BlowfishEngine;
+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;
+import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+
+public final class Blowfish
+{
+ private Blowfish()
+ {
+ }
+
+ public static class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new BlowfishEngine());
+ }
+ }
+
+ public static class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new BlowfishEngine()), 64);
+ }
+ }
+
+ public static class KeyGen
+ extends BaseKeyGenerator
+ {
+ public KeyGen()
+ {
+ super("Blowfish", 128, new CipherKeyGenerator());
+ }
+ }
+
+ public static class AlgParams
+ extends IvAlgorithmParameters
+ {
+ protected String engineToString()
+ {
+ return "Blowfish IV";
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = Blowfish.class.getName();
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.BLOWFISH", PREFIX + "$ECB");
+ // BEGIN android-removed
+ // provider.addAlgorithm("Cipher.1.3.6.1.4.1.3029.1.2", 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("AlgorithmParameters.BLOWFISH", PREFIX + "$AlgParams");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters.1.3.6.1.4.1.3029.1.2", "BLOWFISH");
+
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
new file mode 100644
index 0000000..3ba874c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
@@ -0,0 +1,316 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.engines.DESEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+// END android-removed
+import org.bouncycastle.crypto.generators.DESKeyGenerator;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// import org.bouncycastle.crypto.macs.CMac;
+// END android-removed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+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 DES
+{
+ private DES()
+ {
+ }
+
+ static public class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new DESEngine());
+ }
+ }
+
+ // BEGIN android-removed
+ // static public class CBC
+ // extends BaseBlockCipher
+ // {
+ // public CBC()
+ // {
+ // super(new CBCBlockCipher(new DESEngine()), 64);
+ // }
+ // }
+ //
+ // /**
+ // * DES CFB8
+ // */
+ // public static class DESCFB8
+ // extends BaseMac
+ // {
+ // public DESCFB8()
+ // {
+ // super(new CFBBlockCipherMac(new DESEngine()));
+ // }
+ // }
+ //
+ // /**
+ // * DES64
+ // */
+ // public static class DES64
+ // extends BaseMac
+ // {
+ // public DES64()
+ // {
+ // super(new CBCBlockCipherMac(new DESEngine(), 64));
+ // }
+ // }
+ //
+ // /**
+ // * DES64with7816-4Padding
+ // */
+ // public static class DES64with7816d4
+ // extends BaseMac
+ // {
+ // public DES64with7816d4()
+ // {
+ // super(new CBCBlockCipherMac(new DESEngine(), 64, new ISO7816d4Padding()));
+ // }
+ // }
+ //
+ // public static class CBCMAC
+ // extends BaseMac
+ // {
+ // public CBCMAC()
+ // {
+ // super(new CBCBlockCipherMac(new DESEngine()));
+ // }
+ // }
+ //
+ // static public class CMAC
+ // extends BaseMac
+ // {
+ // public CMAC()
+ // {
+ // super(new CMac(new DESEngine()));
+ // }
+ // }
+ //
+ // public static class RFC3211
+ // extends BaseWrapCipher
+ // {
+ // public RFC3211()
+ // {
+ // super(new RFC3211WrapEngine(new DESEngine()), 8);
+ // }
+ // }
+ //
+ // public static class AlgParamGen
+ // extends BaseAlgorithmParameterGenerator
+ // {
+ // protected void engineInit(
+ // AlgorithmParameterSpec genParamSpec,
+ // SecureRandom random)
+ // throws InvalidAlgorithmParameterException
+ // {
+ // 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.init(new IvParameterSpec(iv));
+ // }
+ // catch (Exception e)
+ // {
+ // throw new RuntimeException(e.getMessage());
+ // }
+ //
+ // return params;
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * DES - the default for this is to generate a key in
+ * a-b-a format that's 24 bytes long but has 16 bytes of
+ * key material (the first 8 bytes is repeated as the last
+ * 8 bytes). If you give it a size, you'll get just what you
+ * asked for.
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator()
+ {
+ super("DES", 64, new DESKeyGenerator());
+ }
+
+ protected void engineInit(
+ int keySize,
+ SecureRandom random)
+ {
+ super.engineInit(keySize, random);
+ }
+
+ protected SecretKey engineGenerateKey()
+ {
+ if (uninitialised)
+ {
+ engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
+ uninitialised = false;
+ }
+
+ return new SecretKeySpec(engine.generateKey(), algName);
+ }
+ }
+
+ static public class KeyFactory
+ extends BaseSecretKeyFactory
+ {
+ public KeyFactory()
+ {
+ super("DES", null);
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+ else if (DESKeySpec.class.isAssignableFrom(keySpec))
+ {
+ byte[] bytes = key.getEncoded();
+
+ try
+ {
+ return new DESKeySpec(bytes);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESKeySpec)
+ {
+ DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DES");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = DES.class.getName();
+ private static final String PACKAGE = "org.bouncycastle.jcajce.provider.symmetric"; // JDK 1.2
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+
+ provider.addAlgorithm("Cipher.DES", PREFIX + "$ECB");
+ // BEGIN android-removed
+ // provider.addAlgorithm("Cipher." + OIWObjectIdentifiers.desCBC, PREFIX + "$CBC");
+ //
+ // addAlias(provider, OIWObjectIdentifiers.desCBC, "DES");
+ //
+ // provider.addAlgorithm("Cipher.DESRFC3211WRAP", PREFIX + "$RFC3211");
+ // END android-removed
+
+ provider.addAlgorithm("KeyGenerator.DES", PREFIX + "$KeyGenerator");
+
+ provider.addAlgorithm("SecretKeyFactory.DES", PREFIX + "$KeyFactory");
+
+ // BEGIN android-removed
+ // provider.addAlgorithm("Mac.DESCMAC", PREFIX + "$CMAC");
+ // provider.addAlgorithm("Mac.DESMAC", PREFIX + "$CBCMAC");
+ // provider.addAlgorithm("Alg.Alias.Mac.DES", "DESMAC");
+ //
+ // provider.addAlgorithm("Mac.DESMAC/CFB8", PREFIX + "$DESCFB8");
+ // provider.addAlgorithm("Alg.Alias.Mac.DES/CFB8", "DESMAC/CFB8");
+ //
+ // provider.addAlgorithm("Mac.DESMAC64", PREFIX + "$DES64");
+ // provider.addAlgorithm("Alg.Alias.Mac.DES64", "DESMAC64");
+ //
+ // provider.addAlgorithm("Mac.DESMAC64WITHISO7816-4PADDING", PREFIX + "$DES64with7816d4");
+ // provider.addAlgorithm("Alg.Alias.Mac.DES64WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+ // provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1MACWITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+ // provider.addAlgorithm("Alg.Alias.Mac.DESISO9797ALG1WITHISO7816-4PADDING", "DESMAC64WITHISO7816-4PADDING");
+ // END android-removed
+
+ provider.addAlgorithm("AlgorithmParameters.DES", PACKAGE + ".util.IvAlgorithmParameters");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + OIWObjectIdentifiers.desCBC, "DES");
+
+ // BEGIN android-removed
+ // provider.addAlgorithm("AlgorithmParameterGenerator.DES", PREFIX + "$AlgParamGen");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + OIWObjectIdentifiers.desCBC, "DES");
+ // END android-removed
+ }
+
+ private void addAlias(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+ {
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + oid.getId(), name);
+ provider.addAlgorithm("Alg.Alias.KeyFactory." + oid.getId(), name);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
new file mode 100644
index 0000000..8e719d6
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
@@ -0,0 +1,423 @@
+package org.bouncycastle.jcajce.provider.symmetric;
+
+// BEGIN android-removed
+// import java.security.AlgorithmParameters;
+// import java.security.InvalidAlgorithmParameterException;
+// END android-removed
+import java.security.SecureRandom;
+// BEGIN android-removed
+// import java.security.spec.AlgorithmParameterSpec;
+// END android-removed
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.DESedeKeySpec;
+// BEGIN android-removed
+// import javax.crypto.spec.IvParameterSpec;
+// END android-removed
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.engines.DESedeEngine;
+import org.bouncycastle.crypto.engines.DESedeWrapEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RFC3211WrapEngine;
+// END android-removed
+import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// import org.bouncycastle.crypto.macs.CMac;
+// END android-removed
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+// BEGIN android-removed
+// import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
+// END android-removed
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
+import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
+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
+{
+ private DESede()
+ {
+ }
+
+ static public class ECB
+ extends BaseBlockCipher
+ {
+ public ECB()
+ {
+ super(new DESedeEngine());
+ }
+ }
+
+ static public class CBC
+ extends BaseBlockCipher
+ {
+ public CBC()
+ {
+ super(new CBCBlockCipher(new DESedeEngine()), 64);
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * DESede CFB8
+ // */
+ // public static class DESedeCFB8
+ // extends BaseMac
+ // {
+ // public DESedeCFB8()
+ // {
+ // super(new CFBBlockCipherMac(new DESedeEngine()));
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * DESede64
+ */
+ public static class DESede64
+ extends BaseMac
+ {
+ public DESede64()
+ {
+ super(new CBCBlockCipherMac(new DESedeEngine(), 64));
+ }
+ }
+
+ /**
+ * DESede64with7816-4Padding
+ */
+ public static class DESede64with7816d4
+ extends BaseMac
+ {
+ public DESede64with7816d4()
+ {
+ super(new CBCBlockCipherMac(new DESedeEngine(), 64, new ISO7816d4Padding()));
+ }
+ }
+
+ public static class CBCMAC
+ extends BaseMac
+ {
+ public CBCMAC()
+ {
+ super(new CBCBlockCipherMac(new DESedeEngine()));
+ }
+ }
+
+ // BEGIN android-removed
+ // static public class CMAC
+ // extends BaseMac
+ // {
+ // public CMAC()
+ // {
+ // super(new CMac(new DESedeEngine()));
+ // }
+ // }
+ // END android-removed
+
+ public static class Wrap
+ extends BaseWrapCipher
+ {
+ public Wrap()
+ {
+ super(new DESedeWrapEngine());
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class RFC3211
+ // extends BaseWrapCipher
+ // {
+ // public RFC3211()
+ // {
+ // super(new RFC3211WrapEngine(new DESedeEngine()), 8);
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * DESede - the default for this is to generate a key in
+ * a-b-a format that's 24 bytes long but has 16 bytes of
+ * key material (the first 8 bytes is repeated as the last
+ * 8 bytes). If you give it a size, you'll get just what you
+ * asked for.
+ */
+ public static class KeyGenerator
+ extends BaseKeyGenerator
+ {
+ private boolean keySizeSet = false;
+
+ public KeyGenerator()
+ {
+ super("DESede", 192, new DESedeKeyGenerator());
+ }
+
+ protected void engineInit(
+ int keySize,
+ SecureRandom random)
+ {
+ super.engineInit(keySize, random);
+ keySizeSet = true;
+ }
+
+ protected SecretKey engineGenerateKey()
+ {
+ if (uninitialised)
+ {
+ engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
+ uninitialised = false;
+ }
+
+ //
+ // if no key size has been defined generate a 24 byte key in
+ // the a-b-a format
+ //
+ if (!keySizeSet)
+ {
+ byte[] k = engine.generateKey();
+
+ System.arraycopy(k, 0, k, 16, 8);
+
+ return new SecretKeySpec(k, algName);
+ }
+ else
+ {
+ return new SecretKeySpec(engine.generateKey(), algName);
+ }
+ }
+ }
+
+ /**
+ * generate a desEDE key in the a-b-c format.
+ */
+ public static class KeyGenerator3
+ extends BaseKeyGenerator
+ {
+ public KeyGenerator3()
+ {
+ super("DESede3", 192, new DESedeKeyGenerator());
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd3-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES3Key
+ extends BaseBlockCipher
+ {
+ public PBEWithSHAAndDES3Key()
+ {
+ super(new CBCBlockCipher(new DESedeEngine()));
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd2-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES2Key
+ extends BaseBlockCipher
+ {
+ public PBEWithSHAAndDES2Key()
+ {
+ super(new CBCBlockCipher(new DESedeEngine()));
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class AlgParamGen
+ // extends BaseAlgorithmParameterGenerator
+ // {
+ // protected void engineInit(
+ // AlgorithmParameterSpec genParamSpec,
+ // SecureRandom random)
+ // throws InvalidAlgorithmParameterException
+ // {
+ // 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.init(new IvParameterSpec(iv));
+ // }
+ // catch (Exception e)
+ // {
+ // throw new RuntimeException(e.getMessage());
+ // }
+ //
+ // return params;
+ // }
+ // }
+ // END android-removed
+
+ static public class KeyFactory
+ extends BaseSecretKeyFactory
+ {
+ public KeyFactory()
+ {
+ super("DESede", null);
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+ else if (DESedeKeySpec.class.isAssignableFrom(keySpec))
+ {
+ byte[] bytes = key.getEncoded();
+
+ try
+ {
+ if (bytes.length == 16)
+ {
+ byte[] longKey = new byte[24];
+
+ System.arraycopy(bytes, 0, longKey, 0, 16);
+ System.arraycopy(bytes, 0, longKey, 16, 8);
+
+ return new DESedeKeySpec(longKey);
+ }
+ else
+ {
+ return new DESedeKeySpec(bytes);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESedeKeySpec)
+ {
+ DESedeKeySpec desKeySpec = (DESedeKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DESede");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+
+ public static class Mappings
+ extends AlgorithmProvider
+ {
+ private static final String PREFIX = DESede.class.getName();
+ private static final String PACKAGE = "org.bouncycastle.jcajce.provider.symmetric"; // JDK 1.2
+
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("Cipher.DESEDE", PREFIX + "$ECB");
+ // BEGIN android-removed
+ // provider.addAlgorithm("Cipher." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$CBC");
+ // END android-removed
+ provider.addAlgorithm("Cipher.DESEDEWRAP", PREFIX + "$Wrap");
+ // BEGIN android-changed
+ provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_CMS3DESwrap, "DESEDEWRAP");
+ // END android-changed
+ // BEGIN android-removed
+ // provider.addAlgorithm("Cipher.DESEDERFC3211WRAP", PREFIX + "$RFC3211");
+ // END android-removed
+
+ if (provider.hasAlgorithm("MessageDigest", "SHA-1"))
+ {
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3Key");
+ // BEGIN android-removed
+ // provider.addAlgorithm("Cipher.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$BrokePBEWithSHAAndDES3Key");
+ // provider.addAlgorithm("Cipher.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$OldPBEWithSHAAndDES3Key");
+ // END android-removed
+ provider.addAlgorithm("Cipher.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2Key");
+ // 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.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("KeyGenerator.DESEDE", PREFIX + "$KeyGenerator");
+ // BEGIN android-removed
+ // provider.addAlgorithm("KeyGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, PREFIX + "$KeyGenerator3");
+ // provider.addAlgorithm("KeyGenerator.DESEDEWRAP", PREFIX + "$KeyGenerator");
+ // END android-removed
+
+ provider.addAlgorithm("SecretKeyFactory.DESEDE", PREFIX + "$KeyFactory");
+
+ // BEGIN android-removed
+ // provider.addAlgorithm("Mac.DESEDECMAC", PREFIX + "$CMAC");
+ // provider.addAlgorithm("Mac.DESEDEMAC", PREFIX + "$CBCMAC");
+ // provider.addAlgorithm("Alg.Alias.Mac.DESEDE", "DESEDEMAC");
+ //
+ // provider.addAlgorithm("Mac.DESEDEMAC/CFB8", PREFIX + "$DESedeCFB8");
+ // provider.addAlgorithm("Alg.Alias.Mac.DESEDE/CFB8", "DESEDEMAC/CFB8");
+ //
+ // provider.addAlgorithm("Mac.DESEDEMAC64", PREFIX + "$DESede64");
+ // provider.addAlgorithm("Alg.Alias.Mac.DESEDE64", "DESEDEMAC64");
+ //
+ // provider.addAlgorithm("Mac.DESEDEMAC64WITHISO7816-4PADDING", PREFIX + "$DESede64with7816d4");
+ // provider.addAlgorithm("Alg.Alias.Mac.DESEDE64WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+ // provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+ // provider.addAlgorithm("Alg.Alias.Mac.DESEDEISO9797ALG1WITHISO7816-4PADDING", "DESEDEMAC64WITHISO7816-4PADDING");
+ // END android-removed
+
+ provider.addAlgorithm("AlgorithmParameters.DESEDE", PACKAGE + ".util.IvAlgorithmParameters");
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+
+ // BEGIN android-removed
+ // provider.addAlgorithm("AlgorithmParameterGenerator.DESEDE", PREFIX + "$AlgParamGen");
+ // provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + PKCSObjectIdentifiers.des_EDE3_CBC, "DESEDE");
+ // END android-removed
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java
new file mode 100644
index 0000000..7f5d3c9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BCPBEKey.java
@@ -0,0 +1,151 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import javax.crypto.interfaces.PBEKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public class BCPBEKey
+ implements PBEKey
+{
+ String algorithm;
+ DERObjectIdentifier oid;
+ int type;
+ int digest;
+ int keySize;
+ int ivSize;
+ CipherParameters param;
+ PBEKeySpec pbeKeySpec;
+ boolean tryWrong = false;
+
+ /**
+ * @param param
+ */
+ public BCPBEKey(
+ String algorithm,
+ DERObjectIdentifier oid,
+ int type,
+ int digest,
+ int keySize,
+ int ivSize,
+ PBEKeySpec pbeKeySpec,
+ CipherParameters param)
+ {
+ this.algorithm = algorithm;
+ this.oid = oid;
+ this.type = type;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ this.pbeKeySpec = pbeKeySpec;
+ this.param = param;
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "RAW";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (param != null)
+ {
+ KeyParameter kParam;
+
+ if (param instanceof ParametersWithIV)
+ {
+ kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+ }
+ else
+ {
+ kParam = (KeyParameter)param;
+ }
+
+ return kParam.getKey();
+ }
+ else
+ {
+ if (type == PBE.PKCS12)
+ {
+ return PBEParametersGenerator.PKCS12PasswordToBytes(pbeKeySpec.getPassword());
+ }
+ else
+ {
+ return PBEParametersGenerator.PKCS5PasswordToBytes(pbeKeySpec.getPassword());
+ }
+ }
+ }
+
+ int getType()
+ {
+ return type;
+ }
+
+ int getDigest()
+ {
+ return digest;
+ }
+
+ int getKeySize()
+ {
+ return keySize;
+ }
+
+ public int getIvSize()
+ {
+ return ivSize;
+ }
+
+ public CipherParameters getParam()
+ {
+ return param;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.interfaces.PBEKey#getPassword()
+ */
+ public char[] getPassword()
+ {
+ return pbeKeySpec.getPassword();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.interfaces.PBEKey#getSalt()
+ */
+ public byte[] getSalt()
+ {
+ return pbeKeySpec.getSalt();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.interfaces.PBEKey#getIterationCount()
+ */
+ public int getIterationCount()
+ {
+ return pbeKeySpec.getIterationCount();
+ }
+
+ public DERObjectIdentifier getOID()
+ {
+ return oid;
+ }
+
+ public void setTryWrongPKCS12Zero(boolean tryWrong)
+ {
+ this.tryWrong = tryWrong;
+ }
+
+ boolean shouldTryWrongPKCS12()
+ {
+ return tryWrong;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
new file mode 100644
index 0000000..63d6548
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameterGenerator.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameterGeneratorSpi;
+import java.security.SecureRandom;
+
+public abstract class BaseAlgorithmParameterGenerator
+ extends AlgorithmParameterGeneratorSpi
+{
+ protected SecureRandom random;
+ protected int strength = 1024;
+
+ protected void engineInit(
+ int strength,
+ SecureRandom random)
+ {
+ this.strength = strength;
+ this.random = random;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java
new file mode 100644
index 0000000..8231ad8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseAlgorithmParameters.java
@@ -0,0 +1,385 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+// BEGIN android-removed
+// import javax.crypto.spec.RC2ParameterSpec;
+// END android-removed
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
+// END android-removed
+import org.bouncycastle.util.Arrays;
+
+public abstract class BaseAlgorithmParameters
+ extends AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ // BEGIN android-removed
+ // public static class RC2AlgorithmParameters
+ // extends BaseAlgorithmParameters
+ // {
+ // private static final short[] table = {
+ // 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0,
+ // 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a,
+ // 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36,
+ // 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c,
+ // 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60,
+ // 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa,
+ // 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e,
+ // 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf,
+ // 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6,
+ // 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3,
+ // 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c,
+ // 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2,
+ // 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5,
+ // 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5,
+ // 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,
+ // 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef,
+ // 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d,
+ // 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb,
+ // 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d,
+ // 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3,
+ // 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61,
+ // 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1,
+ // 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21,
+ // 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42,
+ // 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f,
+ // 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7,
+ // 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15,
+ // 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
+ // {
+ // if (this.isASN1FormatString(format))
+ // {
+ // if (parameterVersion == -1)
+ // {
+ // return new RC2CBCParameter(engineGetEncoded()).getEncoded();
+ // }
+ // else
+ // {
+ // return new RC2CBCParameter(parameterVersion, engineGetEncoded()).getEncoded();
+ // }
+ // }
+ //
+ // if (format.equals("RAW"))
+ // {
+ // return engineGetEncoded();
+ // }
+ //
+ // return null;
+ // }
+ //
+ // protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ // Class paramSpec)
+ // throws InvalidParameterSpecException
+ // {
+ // if (paramSpec == RC2ParameterSpec.class)
+ // {
+ // if (parameterVersion != -1)
+ // {
+ // if (parameterVersion < 256)
+ // {
+ // return new RC2ParameterSpec(ekb[parameterVersion], iv);
+ // }
+ // else
+ // {
+ // return new RC2ParameterSpec(parameterVersion, iv);
+ // }
+ // }
+ // }
+ //
+ // 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
+ // {
+ // if (paramSpec instanceof IvParameterSpec)
+ // {
+ // this.iv = ((IvParameterSpec)paramSpec).getIV();
+ // }
+ // else if (paramSpec instanceof RC2ParameterSpec)
+ // {
+ // int effKeyBits = ((RC2ParameterSpec)paramSpec).getEffectiveKeyBits();
+ // if (effKeyBits != -1)
+ // {
+ // if (effKeyBits < 256)
+ // {
+ // parameterVersion = table[effKeyBits];
+ // }
+ // else
+ // {
+ // parameterVersion = effKeyBits;
+ // }
+ // }
+ //
+ // this.iv = ((RC2ParameterSpec)paramSpec).getIV();
+ // }
+ // else
+ // {
+ // 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)
+ // throws IOException
+ // {
+ // 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";
+ // }
+ // }
+ // END android-removed
+
+ public static class PBKDF2
+ extends BaseAlgorithmParameters
+ {
+ PBKDF2Params params;
+
+ protected byte[] engineGetEncoded()
+ {
+ try
+ {
+ return params.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Oooops! " + e.toString());
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PBEParameterSpec.class)
+ {
+ return new PBEParameterSpec(params.getSalt(),
+ params.getIterationCount().intValue());
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PBEParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+ }
+
+ PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+ this.params = new PBKDF2Params(pbeSpec.getSalt(),
+ pbeSpec.getIterationCount());
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.params = PBKDF2Params.getInstance(ASN1Primitive.fromByteArray(params));
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in PWRIKEK parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "PBKDF2 Parameters";
+ }
+ }
+
+ public static class PKCS12PBE
+ extends BaseAlgorithmParameters
+ {
+ PKCS12PBEParams params;
+
+ protected byte[] engineGetEncoded()
+ {
+ try
+ {
+ return params.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Oooops! " + e.toString());
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (this.isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PBEParameterSpec.class)
+ {
+ return new PBEParameterSpec(params.getIV(),
+ params.getIterations().intValue());
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PBEParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+ }
+
+ PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+ this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
+ pbeSpec.getIterationCount());
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.params = PKCS12PBEParams.getInstance(ASN1Primitive.fromByteArray(params));
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (this.isASN1FormatString(format))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "PKCS12 PBE Parameters";
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
new file mode 100644
index 0000000..ce54655
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java
@@ -0,0 +1,921 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+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 org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.modes.AEADBlockCipher;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.CCMBlockCipher;
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.CTSBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.EAXBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.GOFBBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
+// import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.SICBlockCipher;
+import org.bouncycastle.crypto.paddings.BlockCipherPadding;
+import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.paddings.TBCPadding;
+import org.bouncycastle.crypto.paddings.X923Padding;
+import org.bouncycastle.crypto.paddings.ZeroBytePadding;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.ParametersWithSBox;
+// END android-removed
+import org.bouncycastle.crypto.params.RC2Parameters;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.RC5Parameters;
+// END android-removed
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+// BEGIN android-removed
+// import org.bouncycastle.jce.spec.GOST28147ParameterSpec;
+// END android-removed
+import org.bouncycastle.jce.spec.RepeatedSecretKeySpec;
+import org.bouncycastle.util.Strings;
+
+public class BaseBlockCipher
+ extends BaseWrapCipher
+ implements PBE
+{
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ // BEGIN android-removed
+ // RC2ParameterSpec.class,
+ // RC5ParameterSpec.class,
+ // END android-removed
+ IvParameterSpec.class,
+ PBEParameterSpec.class,
+ // BEGIN android-removed
+ // GOST28147ParameterSpec.class
+ // END android-removed
+ };
+
+ private org.bouncycastle.crypto.BlockCipher baseEngine;
+ private GenericBlockCipher cipher;
+ private ParametersWithIV ivParam;
+
+ private int ivLength = 0;
+
+ private boolean padded;
+
+ private PBEParameterSpec pbeSpec = null;
+ private String pbeAlgorithm = null;
+
+ private String modeName = null;
+
+ protected BaseBlockCipher(
+ org.bouncycastle.crypto.BlockCipher engine)
+ {
+ baseEngine = engine;
+
+ cipher = new BufferedGenericBlockCipher(engine);
+ }
+
+ protected BaseBlockCipher(
+ org.bouncycastle.crypto.BlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine;
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected BaseBlockCipher(
+ BufferedBlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine.getUnderlyingCipher();
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return baseEngine.getBlockSize();
+ }
+
+ 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 cipher.getOutputSize(inputLen);
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (pbeSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(pbeSpec);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ else if (ivParam != null)
+ {
+ String name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+ if (name.indexOf('/') >= 0)
+ {
+ name = name.substring(0, name.indexOf('/'));
+ }
+
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(ivParam.getIV());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ modeName = Strings.toUpperCase(mode);
+
+ if (modeName.equals("ECB"))
+ {
+ ivLength = 0;
+ cipher = new BufferedGenericBlockCipher(baseEngine);
+ }
+ else if (modeName.equals("CBC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(
+ new CBCBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("OFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ else if (modeName.startsWith("CFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ // BEGIN android-removed
+ // else if (modeName.startsWith("PGP"))
+ // {
+ // boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
+
+ // ivLength = baseEngine.getBlockSize();
+ // cipher = new BufferedGenericBlockCipher(
+ // new PGPCFBBlockCipher(baseEngine, inlineIV));
+ // }
+ // else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
+ // {
+ // ivLength = 0;
+ // cipher = new BufferedGenericBlockCipher(
+ // new OpenPGPCFBBlockCipher(baseEngine));
+ // }
+ // END android-removed
+ else if (modeName.startsWith("SIC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (ivLength < 16)
+ {
+ 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)");
+ }
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CTR"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ // BEGIN android-removed
+ // else if (modeName.startsWith("GOFB"))
+ // {
+ // ivLength = baseEngine.getBlockSize();
+ // cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ // new GOFBBlockCipher(baseEngine)));
+ // }
+ // END android-removed
+ else if (modeName.startsWith("CTS"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CCM"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
+ }
+ // BEGIN android-removed
+ // else if (modeName.startsWith("EAX"))
+ // {
+ // ivLength = baseEngine.getBlockSize();
+ // cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+ // }
+ // END android-removed
+ else if (modeName.startsWith("GCM"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine));
+ }
+ else
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String paddingName = Strings.toUpperCase(padding);
+
+ if (paddingName.equals("NOPADDING"))
+ {
+ if (cipher.wrapOnNoPadding())
+ {
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ }
+ else if (paddingName.equals("WITHCTS"))
+ {
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ else
+ {
+ padded = true;
+
+ if (isAEADModeName(modeName))
+ {
+ throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes.");
+ }
+ else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher());
+ }
+ else if (paddingName.equals("ZEROBYTEPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding());
+ }
+ else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding());
+ }
+ else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding());
+ }
+ else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding());
+ }
+ else if (paddingName.equals("TBCPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding());
+ }
+ else
+ {
+ 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.");
+ }
+
+ //
+ // for RC5-64 we must have some default parameters
+ //
+ if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64"))
+ {
+ throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in.");
+ }
+
+ //
+ // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+ //
+ 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)
+ {
+ pbeSpec = (PBEParameterSpec)params;
+ param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName());
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+
+ if (param instanceof ParametersWithIV)
+ {
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ if (ivLength != 0)
+ {
+ IvParameterSpec p = (IvParameterSpec)params;
+
+ if (p.getIV().length != ivLength && !isAEADModeName(modeName))
+ {
+ throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
+ }
+
+ if (key instanceof RepeatedSecretKeySpec)
+ {
+ param = new ParametersWithIV(null, p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else
+ {
+ if (modeName != null && modeName.equals("ECB"))
+ {
+ throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
+ }
+
+ param = new KeyParameter(key.getEncoded());
+ }
+ }
+ // BEGIN android-removed
+ // else if (params instanceof GOST28147ParameterSpec)
+ // {
+ // GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+ //
+ // param = new ParametersWithSBox(
+ // new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
+ //
+ // if (gost28147Param.getIV() != null && ivLength != 0)
+ // {
+ // param = new ParametersWithIV(param, gost28147Param.getIV());
+ // ivParam = (ParametersWithIV)param;
+ // }
+ // }
+ // else if (params instanceof RC2ParameterSpec)
+ // {
+ // RC2ParameterSpec rc2Param = (RC2ParameterSpec)params;
+ //
+ // param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+ //
+ // if (rc2Param.getIV() != null && ivLength != 0)
+ // {
+ // param = new ParametersWithIV(param, rc2Param.getIV());
+ // ivParam = (ParametersWithIV)param;
+ // }
+ // }
+ // else if (params instanceof RC5ParameterSpec)
+ // {
+ // RC5ParameterSpec rc5Param = (RC5ParameterSpec)params;
+ //
+ // param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+ // if (baseEngine.getAlgorithmName().startsWith("RC5"))
+ // {
+ // if (baseEngine.getAlgorithmName().equals("RC5-32"))
+ // {
+ // if (rc5Param.getWordSize() != 32)
+ // {
+ // throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
+ // }
+ // }
+ // else if (baseEngine.getAlgorithmName().equals("RC5-64"))
+ // {
+ // if (rc5Param.getWordSize() != 64)
+ // {
+ // throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
+ // }
+ // }
+ // }
+ // else
+ // {
+ // throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
+ // }
+ // if ((rc5Param.getIV() != null) && (ivLength != 0))
+ // {
+ // param = new ParametersWithIV(param, rc5Param.getIV());
+ // ivParam = (ParametersWithIV)param;
+ // }
+ // }
+ // END android-removed
+ else
+ {
+ throw new InvalidAlgorithmParameterException("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 if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
+ {
+ throw new InvalidAlgorithmParameterException("no IV set when one expected");
+ }
+ }
+
+ if (random != null && padded)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ try
+ {
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ }
+
+ 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)
+ {
+ // try again if possible
+ }
+ }
+
+ 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)
+ {
+ int length = cipher.getUpdateOutputSize(inputLen);
+
+ if (length > 0)
+ {
+ byte[] out = new byte[length];
+
+ int len = cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+ if (len == 0)
+ {
+ return null;
+ }
+ else if (len != out.length)
+ {
+ byte[] tmp = new byte[len];
+
+ System.arraycopy(out, 0, tmp, 0, len);
+
+ return tmp;
+ }
+
+ return out;
+ }
+
+ cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException
+ {
+ try
+ {
+ return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+ catch (DataLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ int len = 0;
+ byte[] tmp = new byte[engineGetOutputSize(inputLen)];
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+ }
+
+ try
+ {
+ len += cipher.doFinal(tmp, len);
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ if (len == tmp.length)
+ {
+ return tmp;
+ }
+
+ byte[] out = new byte[len];
+
+ System.arraycopy(tmp, 0, out, 0, len);
+
+ return out;
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+ {
+ // BEGIN android-note
+ // added ShortBufferException to the throws statement
+ // END android-note
+ int len = 0;
+
+ // BEGIN android-added
+ int outputLen = cipher.getOutputSize(inputLen);
+
+ if (outputLen + outputOffset > output.length) {
+ throw new ShortBufferException("need at least " + outputLen + " bytes");
+ }
+ // BEGIN android-added
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ try
+ {
+ return (len + cipher.doFinal(output, outputOffset + len));
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ private boolean isAEADModeName(
+ String modeName)
+ {
+ return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName);
+ }
+
+ /*
+ * The ciphers that inherit from us.
+ */
+
+ static private interface GenericBlockCipher
+ {
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ public boolean wrapOnNoPadding();
+
+ public String getAlgorithmName();
+
+ public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher();
+
+ public int getOutputSize(int len);
+
+ public int getUpdateOutputSize(int len);
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException;
+ }
+
+ private static class BufferedGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private BufferedBlockCipher cipher;
+
+ BufferedGenericBlockCipher(BufferedBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher);
+ }
+
+ BufferedGenericBlockCipher(org.bouncycastle.crypto.BlockCipher cipher, BlockCipherPadding padding)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher, padding);
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return !(cipher instanceof CTSBlockCipher);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+
+ private static class AEADGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private AEADBlockCipher cipher;
+
+ AEADGenericBlockCipher(AEADBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return false;
+ }
+
+ public org.bouncycastle.crypto.BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java
new file mode 100644
index 0000000..0e190d3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseKeyGenerator.java
@@ -0,0 +1,83 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.KeyGeneratorSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.crypto.CipherKeyGenerator;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+
+public class BaseKeyGenerator
+ extends KeyGeneratorSpi
+{
+ protected String algName;
+ protected int keySize;
+ protected int defaultKeySize;
+ protected CipherKeyGenerator engine;
+
+ protected boolean uninitialised = true;
+
+ protected BaseKeyGenerator(
+ String algName,
+ int defaultKeySize,
+ CipherKeyGenerator engine)
+ {
+ this.algName = algName;
+ this.keySize = this.defaultKeySize = defaultKeySize;
+ this.engine = engine;
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidAlgorithmParameterException
+ {
+ throw new InvalidAlgorithmParameterException("Not Implemented");
+ }
+
+ protected void engineInit(
+ SecureRandom random)
+ {
+ if (random != null)
+ {
+ engine.init(new KeyGenerationParameters(random, defaultKeySize));
+ uninitialised = false;
+ }
+ }
+
+ protected void engineInit(
+ int keySize,
+ SecureRandom random)
+ {
+ try
+ {
+ // BEGIN android-added
+ if (random == null) {
+ random = new SecureRandom();
+ }
+ // END android-added
+ engine.init(new KeyGenerationParameters(random, keySize));
+ uninitialised = false;
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new InvalidParameterException(e.getMessage());
+ }
+ }
+
+ protected SecretKey engineGenerateKey()
+ {
+ if (uninitialised)
+ {
+ engine.init(new KeyGenerationParameters(new SecureRandom(), defaultKeySize));
+ uninitialised = false;
+ }
+
+ return new SecretKeySpec(engine.generateKey(), algName);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
new file mode 100644
index 0000000..31f3278
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseMac.java
@@ -0,0 +1,463 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.MacSpi;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD2Digest;
+// import org.bouncycastle.crypto.digests.MD4Digest;
+// import org.bouncycastle.crypto.digests.MD5Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// 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;
+// import org.bouncycastle.crypto.digests.TigerDigest;
+// END android-removed
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-added
+import org.bouncycastle.crypto.engines.DESEngine;
+import org.bouncycastle.crypto.engines.RC2Engine;
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// import org.bouncycastle.crypto.macs.GOST28147Mac;
+// END android-removed
+import org.bouncycastle.crypto.macs.HMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
+// import org.bouncycastle.crypto.macs.OldHMac;
+// END android-removed
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public class BaseMac
+ extends MacSpi implements PBE
+{
+ private Mac macEngine;
+
+ private int pbeType = PKCS12;
+ private int pbeHash = SHA1;
+ private int keySize = 160;
+
+ protected BaseMac(
+ Mac macEngine)
+ {
+ this.macEngine = macEngine;
+ }
+
+ protected BaseMac(
+ Mac macEngine,
+ int pbeType,
+ int pbeHash,
+ int keySize)
+ {
+ this.macEngine = macEngine;
+ this.pbeType = pbeType;
+ this.pbeHash = pbeHash;
+ this.keySize = keySize;
+ }
+
+ protected void engineInit(
+ Key key,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (key == null)
+ {
+ throw new InvalidKeyException("key is null");
+ }
+
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (k.getParam() != null)
+ {
+ param = k.getParam();
+ }
+ else if (params instanceof PBEParameterSpec)
+ {
+ param = PBE.Util.makePBEMacParameters(k, params);
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type.");
+ }
+
+ macEngine.init(param);
+ }
+
+ protected int engineGetMacLength()
+ {
+ return macEngine.getMacSize();
+ }
+
+ protected void engineReset()
+ {
+ macEngine.reset();
+ }
+
+ protected void engineUpdate(
+ byte input)
+ {
+ macEngine.update(input);
+ }
+
+ protected void engineUpdate(
+ byte[] input,
+ int offset,
+ int len)
+ {
+ macEngine.update(input, offset, len);
+ }
+
+ protected byte[] engineDoFinal()
+ {
+ byte[] out = new byte[engineGetMacLength()];
+
+ macEngine.doFinal(out, 0);
+
+ return out;
+ }
+
+ /**
+ * the classes that extend directly off us.
+ */
+
+ /**
+ * DES
+ */
+ public static class DES
+ extends BaseMac
+ {
+ public DES()
+ {
+ super(new CBCBlockCipherMac(new DESEngine()));
+ }
+ }
+
+ /**
+ * DES 64 bit MAC
+ */
+ public static class DES64
+ extends BaseMac
+ {
+ public DES64()
+ {
+ super(new CBCBlockCipherMac(new DESEngine(), 64));
+ }
+ }
+
+ /**
+ * RC2
+ */
+ public static class RC2
+ extends BaseMac
+ {
+ public RC2()
+ {
+ super(new CBCBlockCipherMac(new RC2Engine()));
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * GOST28147
+ // */
+ // public static class GOST28147
+ // extends BaseMac
+ // {
+ // public GOST28147()
+ // {
+ // super(new GOST28147Mac());
+ // }
+ // }
+ //
+ //
+ //
+ // /**
+ // * DES
+ // */
+ // public static class DESCFB8
+ // extends BaseMac
+ // {
+ // public DESCFB8()
+ // {
+ // super(new CFBBlockCipherMac(new DESEngine()));
+ // }
+ // }
+ //
+ // /**
+ // * RC2CFB8
+ // */
+ // public static class RC2CFB8
+ // extends BaseMac
+ // {
+ // public RC2CFB8()
+ // {
+ // super(new CFBBlockCipherMac(new RC2Engine()));
+ // }
+ // }
+ //
+ // /**
+ // * DES9797Alg3with7816-4Padding
+ // */
+ // public static class DES9797Alg3with7816d4
+ // extends BaseMac
+ // {
+ // public DES9797Alg3with7816d4()
+ // {
+ // super(new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()));
+ // }
+ // }
+ //
+ // /**
+ // * DES9797Alg3
+ // */
+ // public static class DES9797Alg3
+ // extends BaseMac
+ // {
+ // public DES9797Alg3()
+ // {
+ // super(new ISO9797Alg3Mac(new DESEngine()));
+ // }
+ // }
+ //
+ // /**
+ // * MD2 HMac
+ // */
+ // public static class MD2
+ // extends BaseMac
+ // {
+ // public MD2()
+ // {
+ // super(new HMac(new MD2Digest()));
+ // }
+ // }
+ //
+ // /**
+ // * MD4 HMac
+ // */
+ // public static class MD4
+ // extends BaseMac
+ // {
+ // public MD4()
+ // {
+ // super(new HMac(new MD4Digest()));
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * MD5 HMac
+ */
+ public static class MD5
+ extends BaseMac
+ {
+ public MD5()
+ {
+ // BEGIN android-changed
+ super(new HMac(AndroidDigestFactory.getMD5()));
+ // END android-changed
+ }
+ }
+
+ /**
+ * SHA1 HMac
+ */
+ public static class SHA1
+ extends BaseMac
+ {
+ public SHA1()
+ {
+ // BEGIN android-changed
+ super(new HMac(AndroidDigestFactory.getSHA1()));
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * SHA-224 HMac
+ // */
+ // public static class SHA224
+ // extends BaseMac
+ // {
+ // public SHA224()
+ // {
+ // super(new HMac(new SHA224Digest()));
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * SHA-256 HMac
+ */
+ public static class SHA256
+ extends BaseMac
+ {
+ public SHA256()
+ {
+ super(new HMac(AndroidDigestFactory.getSHA256()));
+ }
+ }
+
+ /**
+ * SHA-384 HMac
+ */
+ public static class SHA384
+ extends BaseMac
+ {
+ public SHA384()
+ {
+ super(new HMac(AndroidDigestFactory.getSHA384()));
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class OldSHA384
+ // extends BaseMac
+ // {
+ // public OldSHA384()
+ // {
+ // super(new OldHMac(new SHA384Digest()));
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * SHA-512 HMac
+ */
+ public static class SHA512
+ extends BaseMac
+ {
+ public SHA512()
+ {
+ super(new HMac(AndroidDigestFactory.getSHA512()));
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * SHA-512 HMac
+ // */
+ // public static class OldSHA512
+ // extends BaseMac
+ // {
+ // public OldSHA512()
+ // {
+ // super(new OldHMac(new SHA512Digest()));
+ // }
+ // }
+ //
+ // /**
+ // * RIPEMD128 HMac
+ // */
+ // public static class RIPEMD128
+ // extends BaseMac
+ // {
+ // public RIPEMD128()
+ // {
+ // super(new HMac(new RIPEMD128Digest()));
+ // }
+ // }
+ //
+ // /**
+ // * RIPEMD160 HMac
+ // */
+ // public static class RIPEMD160
+ // extends BaseMac
+ // {
+ // public RIPEMD160()
+ // {
+ // super(new HMac(new RIPEMD160Digest()));
+ // }
+ // }
+ //
+ // /**
+ // * Tiger HMac
+ // */
+ // public static class Tiger
+ // extends BaseMac
+ // {
+ // public Tiger()
+ // {
+ // super(new HMac(new TigerDigest()));
+ // }
+ // }
+ //
+ // //
+ // // PKCS12 states that the same algorithm should be used
+ // // for the key generation as is used in the HMAC, so that
+ // // is what we do here.
+ // //
+ //
+ // /**
+ // * PBEWithHmacRIPEMD160
+ // */
+ // public static class PBEWithRIPEMD160
+ // extends BaseMac
+ // {
+ // public PBEWithRIPEMD160()
+ // {
+ // super(new HMac(new RIPEMD160Digest()), PKCS12, RIPEMD160, 160);
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * PBEWithHmacSHA
+ */
+ public static class PBEWithSHA
+ extends BaseMac
+ {
+ public PBEWithSHA()
+ {
+ // BEGIN android-changed
+ super(new HMac(AndroidDigestFactory.getSHA1()), PKCS12, SHA1, 160);
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * PBEWithHmacTiger
+ // */
+ // public static class PBEWithTiger
+ // extends BaseMac
+ // {
+ // public PBEWithTiger()
+ // {
+ // super(new HMac(new TigerDigest()), PKCS12, TIGER, 192);
+ // }
+ // }
+ // END android-removed
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
new file mode 100644
index 0000000..23e7b19
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseSecretKeyFactory.java
@@ -0,0 +1,196 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.lang.reflect.Constructor;
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.DESParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public class BaseSecretKeyFactory
+ extends SecretKeyFactorySpi
+ implements PBE
+{
+ protected String algName;
+ protected DERObjectIdentifier algOid;
+
+ protected BaseSecretKeyFactory(
+ String algName,
+ DERObjectIdentifier algOid)
+ {
+ this.algName = algName;
+ this.algOid = algOid;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof SecretKeySpec)
+ {
+ return (SecretKey)keySpec;
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+
+ try
+ {
+ Class[] parameters = { byte[].class };
+
+ Constructor c = keySpec.getConstructor(parameters);
+ Object[] p = new Object[1];
+
+ p[0] = key.getEncoded();
+
+ return (KeySpec)c.newInstance(p);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ protected SecretKey engineTranslateKey(
+ SecretKey key)
+ throws InvalidKeyException
+ {
+ if (key == null)
+ {
+ throw new InvalidKeyException("key parameter is null");
+ }
+
+ if (!key.getAlgorithm().equalsIgnoreCase(algName))
+ {
+ throw new InvalidKeyException("Key not of type " + algName + ".");
+ }
+
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+
+ /*
+ * classes that inherit from us
+ */
+
+
+
+ static public class DESPBEKeyFactory
+ extends BaseSecretKeyFactory
+ {
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public DESPBEKeyFactory(
+ String algorithm,
+ DERObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ if (pbeSpec.getSalt() == null)
+ {
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ if (forCipher)
+ {
+ param = PBE.Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+ }
+ else
+ {
+ param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+ }
+
+ KeyParameter kParam;
+ if (param instanceof ParametersWithIV)
+ {
+ kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+ }
+ else
+ {
+ kParam = (KeyParameter)param;
+ }
+
+ DESParameters.setOddParity(kParam.getKey());
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ static public class DES
+ extends BaseSecretKeyFactory
+ {
+ public DES()
+ {
+ super("DES", null);
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESKeySpec)
+ {
+ DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DES");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
new file mode 100644
index 0000000..2031929
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java
@@ -0,0 +1,366 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+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 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;
+
+public class BaseStreamCipher
+ extends BaseWrapCipher
+ 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;
+
+ protected BaseStreamCipher(
+ StreamCipher engine,
+ int ivLength)
+ {
+ cipher = engine;
+ this.ivLength = ivLength;
+ }
+
+ protected BaseStreamCipher(
+ 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)
+ {
+ 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)
+ {
+ if (inputLen != 0)
+ {
+ cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ cipher.reset();
+
+ return inputLen;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
new file mode 100644
index 0000000..2800a7f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java
@@ -0,0 +1,406 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+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.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.CipherParameters;
+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.jce.provider.BouncyCastleProvider;
+
+public abstract class BaseWrapCipher
+ extends CipherSpi
+ implements PBE
+{
+ //
+ // specs we can handle.
+ //
+ private Class[] availableSpecs =
+ {
+ IvParameterSpec.class,
+ PBEParameterSpec.class,
+ // BEGIN android-removed
+ // RC2ParameterSpec.class,
+ // RC5ParameterSpec.class
+ // END android-removed
+ };
+
+ protected int pbeType = PKCS12;
+ protected int pbeHash = SHA1;
+ protected int pbeKeySize;
+ protected int pbeIvSize;
+
+ protected AlgorithmParameters engineParams = null;
+
+ protected Wrapper wrapEngine = null;
+
+ private int ivSize;
+ private byte[] iv;
+
+ protected BaseWrapCipher()
+ {
+ }
+
+ protected BaseWrapCipher(
+ Wrapper wrapEngine)
+ {
+ this(wrapEngine, 0);
+ }
+
+ protected BaseWrapCipher(
+ Wrapper wrapEngine,
+ int ivSize)
+ {
+ this.wrapEngine = wrapEngine;
+ this.ivSize = ivSize;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return 0;
+ }
+
+ protected byte[] engineGetIV()
+ {
+ return (byte[])iv.clone();
+ }
+
+ protected int engineGetKeySize(
+ Key key)
+ {
+ return key.getEncoded().length;
+ }
+
+ protected int engineGetOutputSize(
+ int inputLen)
+ {
+ return -1;
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ return null;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ throw new NoSuchPaddingException("Padding " + padding + " unknown.");
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ AlgorithmParameterSpec params,
+ SecureRandom random)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (params instanceof PBEParameterSpec)
+ {
+ param = PBE.Util.makePBEParameters(k, params, wrapEngine.getAlgorithmName());
+ }
+ else if (k.getParam() != null)
+ {
+ param = k.getParam();
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+ }
+ else
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+
+ if (params instanceof IvParameterSpec)
+ {
+ IvParameterSpec iv = (IvParameterSpec) params;
+ param = new ParametersWithIV(param, iv.getIV());
+ }
+
+ if (param instanceof KeyParameter && ivSize != 0)
+ {
+ iv = new byte[ivSize];
+ random.nextBytes(iv);
+ param = new ParametersWithIV(param, iv);
+ }
+
+ switch (opmode)
+ {
+ case Cipher.WRAP_MODE:
+ wrapEngine.init(true, param);
+ break;
+ case Cipher.UNWRAP_MODE:
+ wrapEngine.init(false, param);
+ break;
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.DECRYPT_MODE:
+ throw new IllegalArgumentException("engine only valid for wrapping");
+ 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)
+ {
+ // try next spec
+ }
+ }
+
+ if (paramSpec == null)
+ {
+ throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString());
+ }
+ }
+
+ engineParams = params;
+ engineInit(opmode, key, paramSpec, random);
+ }
+
+ protected void engineInit(
+ int opmode,
+ Key key,
+ SecureRandom random)
+ throws InvalidKeyException
+ {
+ try
+ {
+ engineInit(opmode, key, (AlgorithmParameterSpec)null, random);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ {
+ throw new RuntimeException("not supported for wrapping");
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException
+ {
+ throw new RuntimeException("not supported for wrapping");
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ return null;
+ }
+
+ // BEGIN android-changed
+ // added ShortBufferException to throws statement
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+ {
+ return 0;
+ }
+ // END android-changed
+
+ protected byte[] engineWrap(
+ Key key)
+ throws IllegalBlockSizeException, InvalidKeyException
+ {
+ byte[] encoded = key.getEncoded();
+ if (encoded == null)
+ {
+ throw new InvalidKeyException("Cannot wrap key, null encoding.");
+ }
+
+ try
+ {
+ if (wrapEngine == null)
+ {
+ return engineDoFinal(encoded, 0, encoded.length);
+ }
+ else
+ {
+ return wrapEngine.wrap(encoded, 0, encoded.length);
+ }
+ }
+ catch (BadPaddingException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ }
+
+ protected Key engineUnwrap(
+ byte[] wrappedKey,
+ String wrappedKeyAlgorithm,
+ int wrappedKeyType)
+ // BEGIN android-removed
+ // throws InvalidKeyException
+ // END android-removed
+ // BEGIN android-added
+ throws InvalidKeyException, NoSuchAlgorithmException
+ // END android-added
+ {
+ byte[] encoded;
+ try
+ {
+ if (wrapEngine == null)
+ {
+ encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
+ }
+ else
+ {
+ encoded = wrapEngine.unwrap(wrappedKey, 0, wrappedKey.length);
+ }
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ 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());
+ }
+ // BEGIN android-removed
+ // catch (NoSuchAlgorithmException e)
+ // {
+ // throw new InvalidKeyException("Unknown key type " + e.getMessage());
+ // }
+ // END android-removed
+ catch (InvalidKeySpecException e2)
+ {
+ throw new InvalidKeyException("Unknown key type " + e2.getMessage());
+ }
+
+ throw new InvalidKeyException("Unknown key type " + wrappedKeyType);
+ }
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
new file mode 100644
index 0000000..b5a9552
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/IvAlgorithmParameters.java
@@ -0,0 +1,118 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.io.IOException;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.util.Arrays;
+
+public class IvAlgorithmParameters
+ extends BaseAlgorithmParameters
+{
+ private byte[] iv;
+
+ protected byte[] engineGetEncoded()
+ throws IOException
+ {
+ return engineGetEncoded("ASN.1");
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format))
+ {
+ return new DEROctetString(engineGetEncoded("RAW")).getEncoded();
+ }
+
+ if (format.equals("RAW"))
+ {
+ return Arrays.clone(iv);
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == IvParameterSpec.class)
+ {
+ return new IvParameterSpec(iv);
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to IV parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof IvParameterSpec))
+ {
+ throw new InvalidParameterSpecException("IvParameterSpec required to initialise a IV parameters algorithm parameters object");
+ }
+
+ this.iv = ((IvParameterSpec)paramSpec).getIV();
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ //
+ // check that we don't have a DER encoded octet string
+ //
+ if ((params.length % 8) != 0
+ && params[0] == 0x04 && params[1] == params.length - 2)
+ {
+ ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(params);
+
+ params = oct.getOctets();
+ }
+
+ this.iv = Arrays.clone(params);
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format))
+ {
+ try
+ {
+ ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(params);
+
+ engineInit(oct.getOctets());
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Exception decoding: " + e);
+ }
+
+ return;
+ }
+
+ if (format.equals("RAW"))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in IV parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "IV Parameters";
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
new file mode 100644
index 0000000..e9fb8dd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java
@@ -0,0 +1,306 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD2Digest;
+// import org.bouncycastle.crypto.digests.MD5Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// import org.bouncycastle.crypto.digests.SHA1Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.TigerDigest;
+// END android-removed
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-added
+import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator;
+import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator;
+import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
+import org.bouncycastle.crypto.params.DESParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+
+public interface PBE
+{
+ //
+ // PBE Based encryption constants - by default we do PKCS12 with SHA-1
+ //
+ static final int MD5 = 0;
+ static final int SHA1 = 1;
+ // BEGIN android-removed
+ // static final int RIPEMD160 = 2;
+ // static final int TIGER = 3;
+ // END android-removed
+ static final int SHA256 = 4;
+ // BEGIN android-removed
+ // static final int MD2 = 5;
+ // END android-removed
+
+ static final int PKCS5S1 = 0;
+ static final int PKCS5S2 = 1;
+ static final int PKCS12 = 2;
+ static final int OPENSSL = 3;
+
+ /**
+ * uses the appropriate mixer to generate the key and IV if necessary.
+ */
+ static class Util
+ {
+ static private PBEParametersGenerator makePBEGenerator(
+ int type,
+ int hash)
+ {
+ PBEParametersGenerator generator;
+
+ if (type == PKCS5S1)
+ {
+ switch (hash)
+ {
+ // BEGIN android-removed
+ // case MD2:
+ // generator = new PKCS5S1ParametersGenerator(new MD2Digest());
+ // break;
+ // END android-removed
+ case MD5:
+ // BEGIN android-changed
+ generator = new PKCS5S1ParametersGenerator(AndroidDigestFactory.getMD5());
+ // END android-changed
+ break;
+ case SHA1:
+ // BEGIN android-changed
+ generator = new PKCS5S1ParametersGenerator(AndroidDigestFactory.getSHA1());
+ // END android-changed
+ break;
+ default:
+ throw new IllegalStateException("PKCS5 scheme 1 only supports MD2, MD5 and SHA1.");
+ }
+ }
+ else if (type == PKCS5S2)
+ {
+ generator = new PKCS5S2ParametersGenerator();
+ }
+ else if (type == PKCS12)
+ {
+ switch (hash)
+ {
+ // BEGIN android-removed
+ // case MD2:
+ // generator = new PKCS12ParametersGenerator(new MD2Digest());
+ // break;
+ // END android-removed
+ case MD5:
+ // BEGIN android-changed
+ generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getMD5());
+ // END android-changed
+ break;
+ case SHA1:
+ // BEGIN android-changed
+ generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA1());
+ // END android-changed
+ break;
+ // BEGIN android-removed
+ // case RIPEMD160:
+ // generator = new PKCS12ParametersGenerator(new RIPEMD160Digest());
+ // break;
+ // case TIGER:
+ // generator = new PKCS12ParametersGenerator(new TigerDigest());
+ // break;
+ // END android-removed
+ case SHA256:
+ // BEGIN android-changed
+ generator = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA256());
+ // END android-changed
+ break;
+ default:
+ throw new IllegalStateException("unknown digest scheme for PBE encryption.");
+ }
+ }
+ else
+ {
+ generator = new OpenSSLPBEParametersGenerator();
+ }
+
+ return generator;
+ }
+
+ /**
+ * construct a key and iv (if necessary) suitable for use with a
+ * Cipher.
+ */
+ public static CipherParameters makePBEParameters(
+ BCPBEKey pbeKey,
+ AlgorithmParameterSpec spec,
+ String targetAlgorithm)
+ {
+ if ((spec == null) || !(spec instanceof PBEParameterSpec))
+ {
+ throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+ }
+
+ PBEParameterSpec pbeParam = (PBEParameterSpec)spec;
+ 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());
+
+ if (pbeKey.getIvSize() != 0)
+ {
+ param = generator.generateDerivedParameters(pbeKey.getKeySize(), pbeKey.getIvSize());
+ }
+ else
+ {
+ param = generator.generateDerivedParameters(pbeKey.getKeySize());
+ }
+
+ 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;
+ }
+
+ /**
+ * 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(
+ BCPBEKey pbeKey,
+ AlgorithmParameterSpec spec)
+ {
+ if ((spec == null) || !(spec instanceof PBEParameterSpec))
+ {
+ throw new IllegalArgumentException("Need a PBEParameter spec with a PBE key.");
+ }
+
+ PBEParameterSpec pbeParam = (PBEParameterSpec)spec;
+ 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());
+
+ param = generator.generateDerivedMacParameters(pbeKey.getKeySize());
+
+ 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.
+ */
+ public static CipherParameters makePBEParameters(
+ PBEKeySpec keySpec,
+ int type,
+ int hash,
+ int keySize,
+ int ivSize)
+ {
+ PBEParametersGenerator generator = makePBEGenerator(type, hash);
+ byte[] key;
+ CipherParameters param;
+
+ if (type == PKCS12)
+ {
+ key = PBEParametersGenerator.PKCS12PasswordToBytes(keySpec.getPassword());
+ }
+ else
+ {
+ key = PBEParametersGenerator.PKCS5PasswordToBytes(keySpec.getPassword());
+ }
+
+ generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
+
+ if (ivSize != 0)
+ {
+ param = generator.generateDerivedParameters(keySize, ivSize);
+ }
+ else
+ {
+ param = generator.generateDerivedParameters(keySize);
+ }
+
+ for (int i = 0; i != key.length; i++)
+ {
+ key[i] = 0;
+ }
+
+ 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;
+
+ if (type == PKCS12)
+ {
+ key = PBEParametersGenerator.PKCS12PasswordToBytes(keySpec.getPassword());
+ }
+ else
+ {
+ key = PBEParametersGenerator.PKCS5PasswordToBytes(keySpec.getPassword());
+ }
+
+ generator.init(key, keySpec.getSalt(), keySpec.getIterationCount());
+
+ param = generator.generateDerivedMacParameters(keySize);
+
+ for (int i = 0; i != key.length; i++)
+ {
+ key[i] = 0;
+ }
+
+ return param;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java
new file mode 100644
index 0000000..f00ad36
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBESecretKeyFactory.java
@@ -0,0 +1,68 @@
+package org.bouncycastle.jcajce.provider.symmetric.util;
+
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.PBEKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.crypto.CipherParameters;
+
+public class PBESecretKeyFactory
+ extends BaseSecretKeyFactory
+ implements PBE
+{
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public PBESecretKeyFactory(
+ String algorithm,
+ DERObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ if (pbeSpec.getSalt() == null)
+ {
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ if (forCipher)
+ {
+ param = PBE.Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+ }
+ else
+ {
+ param = PBE.Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+ }
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java
new file mode 100644
index 0000000..50fe939
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AlgorithmProvider.java
@@ -0,0 +1,8 @@
+package org.bouncycastle.jcajce.provider.util;
+
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+
+public abstract class AlgorithmProvider
+{
+ public abstract void configure(ConfigurableProvider provider);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java
new file mode 100644
index 0000000..c401084
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java
@@ -0,0 +1,42 @@
+package org.bouncycastle.jcajce.provider.util;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+
+public abstract class AsymmetricAlgorithmProvider
+ extends AlgorithmProvider
+{
+ protected void addSignatureAlgorithm(
+ ConfigurableProvider provider,
+ String digest,
+ String algorithm,
+ String className,
+ ASN1ObjectIdentifier oid)
+ {
+ String mainName = digest + "WITH" + algorithm;
+ String jdk11Variation1 = digest + "with" + algorithm;
+ String jdk11Variation2 = digest + "With" + algorithm;
+ String alias = digest + "/" + algorithm;
+
+ provider.addAlgorithm("Signature." + mainName, className);
+ provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation1, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + jdk11Variation2, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + alias, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature." + oid, mainName);
+ provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, mainName);
+ }
+
+ protected void registerOid(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name, AsymmetricKeyInfoConverter keyFactory)
+ {
+ provider.addAlgorithm("Alg.Alias.KeyFactory." + oid, name);
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator." + oid, name);
+
+ provider.addKeyInfoConverter(oid, keyFactory);
+ }
+
+ protected void registerOidAlgorithmParameters(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name)
+ {
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameterGenerator." + oid, name);
+ provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + oid, name);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java
new file mode 100644
index 0000000..e2f4e4a
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricKeyInfoConverter.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.jcajce.provider.util;
+
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+public interface AsymmetricKeyInfoConverter
+{
+ PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException;
+
+ PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
new file mode 100644
index 0000000..c4b0f18
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
@@ -0,0 +1,156 @@
+package org.bouncycastle.jcajce.provider.util;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.Digest;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD5Digest;
+// import org.bouncycastle.crypto.digests.SHA1Digest;
+// import org.bouncycastle.crypto.digests.SHA224Digest;
+// import org.bouncycastle.crypto.digests.SHA256Digest;
+// import org.bouncycastle.crypto.digests.SHA384Digest;
+// import org.bouncycastle.crypto.digests.SHA512Digest;
+// END android-removed
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-added
+import org.bouncycastle.util.Strings;
+
+public class DigestFactory
+{
+ private static Set md5 = new HashSet();
+ private static Set sha1 = new HashSet();
+ // BEGIN android-removed
+ // private static Set sha224 = new HashSet();
+ // END android-removed
+ private static Set sha256 = new HashSet();
+ private static Set sha384 = new HashSet();
+ private static Set sha512 = new HashSet();
+
+ private static Map oids = new HashMap();
+
+ static
+ {
+ md5.add("MD5");
+ md5.add(PKCSObjectIdentifiers.md5.getId());
+
+ sha1.add("SHA1");
+ sha1.add("SHA-1");
+ sha1.add(OIWObjectIdentifiers.idSHA1.getId());
+
+ // BEGIN android-removed
+ // sha224.add("SHA224");
+ // sha224.add("SHA-224");
+ // sha224.add(NISTObjectIdentifiers.id_sha224.getId());
+ // END android-removed
+
+ sha256.add("SHA256");
+ sha256.add("SHA-256");
+ sha256.add(NISTObjectIdentifiers.id_sha256.getId());
+
+ sha384.add("SHA384");
+ sha384.add("SHA-384");
+ sha384.add(NISTObjectIdentifiers.id_sha384.getId());
+
+ sha512.add("SHA512");
+ sha512.add("SHA-512");
+ sha512.add(NISTObjectIdentifiers.id_sha512.getId());
+
+ oids.put("MD5", PKCSObjectIdentifiers.md5);
+ oids.put(PKCSObjectIdentifiers.md5.getId(), PKCSObjectIdentifiers.md5);
+
+ oids.put("SHA1", OIWObjectIdentifiers.idSHA1);
+ oids.put("SHA-1", OIWObjectIdentifiers.idSHA1);
+ oids.put(OIWObjectIdentifiers.idSHA1.getId(), OIWObjectIdentifiers.idSHA1);
+
+ // BEGIN android-removed
+ // oids.put("SHA224", NISTObjectIdentifiers.id_sha224);
+ // oids.put("SHA-224", NISTObjectIdentifiers.id_sha224);
+ // oids.put(NISTObjectIdentifiers.id_sha224.getId(), NISTObjectIdentifiers.id_sha224);
+ // END android-removed
+
+ oids.put("SHA256", NISTObjectIdentifiers.id_sha256);
+ oids.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+ oids.put(NISTObjectIdentifiers.id_sha256.getId(), NISTObjectIdentifiers.id_sha256);
+
+ oids.put("SHA384", NISTObjectIdentifiers.id_sha384);
+ oids.put("SHA-384", NISTObjectIdentifiers.id_sha384);
+ oids.put(NISTObjectIdentifiers.id_sha384.getId(), NISTObjectIdentifiers.id_sha384);
+
+ oids.put("SHA512", NISTObjectIdentifiers.id_sha512);
+ oids.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+ oids.put(NISTObjectIdentifiers.id_sha512.getId(), NISTObjectIdentifiers.id_sha512);
+ }
+
+ public static Digest getDigest(
+ String digestName)
+ {
+ digestName = Strings.toUpperCase(digestName);
+
+ if (sha1.contains(digestName))
+ {
+ // BEGIN android-changed
+ return AndroidDigestFactory.getSHA1();
+ // END android-changed
+ }
+ if (md5.contains(digestName))
+ {
+ // BEGIN android-changed
+ return AndroidDigestFactory.getMD5();
+ // END android-changed
+ }
+ // BEGIN android-removed
+ // if (sha224.contains(digestName))
+ // {
+ // return new SHA224Digest();
+ // }
+ // END android-removed
+ if (sha256.contains(digestName))
+ {
+ // BEGIN android-changed
+ return AndroidDigestFactory.getSHA256();
+ // END android-changed
+ }
+ if (sha384.contains(digestName))
+ {
+ // BEGIN android-changed
+ return AndroidDigestFactory.getSHA384();
+ // END android-changed
+ }
+ if (sha512.contains(digestName))
+ {
+ // BEGIN android-changed
+ return AndroidDigestFactory.getSHA512();
+ // END android-changed
+ }
+
+ return null;
+ }
+
+ public static boolean isSameDigest(
+ String digest1,
+ String digest2)
+ {
+ return (sha1.contains(digest1) && sha1.contains(digest2))
+ // BEGIN android-removed
+ // || (sha224.contains(digest1) && sha224.contains(digest2))
+ // END android-removed
+ || (sha256.contains(digest1) && sha256.contains(digest2))
+ || (sha384.contains(digest1) && sha384.contains(digest2))
+ || (sha512.contains(digest1) && sha512.contains(digest2))
+ || (md5.contains(digest1) && md5.contains(digest2));
+ }
+
+ public static ASN1ObjectIdentifier getOID(
+ String digestName)
+ {
+ return (ASN1ObjectIdentifier)oids.get(digestName);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java b/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
new file mode 100644
index 0000000..b56351b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java
@@ -0,0 +1,125 @@
+package org.bouncycastle.jce;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTNamedCurves;
+import org.bouncycastle.asn1.sec.SECNamedCurves;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+// END android-removed
+import org.bouncycastle.asn1.x9.X962NamedCurves;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+
+/**
+ * a table of locally supported named curves.
+ */
+public class ECNamedCurveTable
+{
+ /**
+ * return a parameter spec representing the passed in named
+ * curve. The routine returns null if the curve is not present.
+ *
+ * @param name the name of the curve requested
+ * @return a parameter spec for the curve, null if it is not available.
+ */
+ public static ECNamedCurveParameterSpec getParameterSpec(
+ String name)
+ {
+ X9ECParameters ecP = X962NamedCurves.getByName(name);
+ if (ecP == null)
+ {
+ try
+ {
+ ecP = X962NamedCurves.getByOID(new ASN1ObjectIdentifier(name));
+ }
+ catch (IllegalArgumentException e)
+ {
+ // ignore - not an oid
+ }
+ }
+
+ if (ecP == null)
+ {
+ ecP = SECNamedCurves.getByName(name);
+ if (ecP == null)
+ {
+ try
+ {
+ ecP = SECNamedCurves.getByOID(new ASN1ObjectIdentifier(name));
+ }
+ catch (IllegalArgumentException e)
+ {
+ // ignore - not an oid
+ }
+ }
+ }
+
+ // BEGIN android-removed
+ // if (ecP == null)
+ // {
+ // ecP = TeleTrusTNamedCurves.getByName(name);
+ // if (ecP == null)
+ // {
+ // try
+ // {
+ // ecP = TeleTrusTNamedCurves.getByOID(new ASN1ObjectIdentifier(name));
+ // }
+ // catch (IllegalArgumentException e)
+ // {
+ // // ignore - not an oid
+ // }
+ // }
+ // }
+ // END android-removed
+
+ if (ecP == null)
+ {
+ ecP = NISTNamedCurves.getByName(name);
+ }
+
+ if (ecP == null)
+ {
+ return null;
+ }
+
+ return new ECNamedCurveParameterSpec(
+ name,
+ ecP.getCurve(),
+ ecP.getG(),
+ ecP.getN(),
+ ecP.getH(),
+ ecP.getSeed());
+ }
+
+ /**
+ * return an enumeration of the names of the available curves.
+ *
+ * @return an enumeration of the names of the available curves.
+ */
+ public static Enumeration getNames()
+ {
+ Vector v = new Vector();
+
+ addEnumeration(v, X962NamedCurves.getNames());
+ addEnumeration(v, SECNamedCurves.getNames());
+ addEnumeration(v, NISTNamedCurves.getNames());
+ // BEGIN android-removed
+ // addEnumeration(v, TeleTrusTNamedCurves.getNames());
+ // END android-removed
+
+ return v.elements();
+ }
+
+ private static void addEnumeration(
+ Vector v,
+ Enumeration e)
+ {
+ while (e.hasMoreElements())
+ {
+ v.addElement(e.nextElement());
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java b/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
new file mode 100644
index 0000000..e09bb65
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
@@ -0,0 +1,687 @@
+package org.bouncycastle.jce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PSSParameterSpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
+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
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.CertificationRequest;
+import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Strings;
+
+/**
+ * A class for verifying and creating PKCS10 Certification requests.
+ * <pre>
+ * CertificationRequest ::= SEQUENCE {
+ * certificationRequestInfo CertificationRequestInfo,
+ * signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
+ * signature BIT STRING
+ * }
+ *
+ * CertificationRequestInfo ::= SEQUENCE {
+ * version INTEGER { v1(0) } (v1,...),
+ * subject Name,
+ * subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+ * attributes [0] Attributes{{ CRIAttributes }}
+ * }
+ *
+ * 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})
+ * }
+ * </pre>
+ * @deprecated use classes in org.bouncycastle.pkcs.
+ */
+public class PKCS10CertificationRequest
+ extends CertificationRequest
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable params = new Hashtable();
+ private static Hashtable keyAlgorithms = new Hashtable();
+ private static Hashtable oids = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ // 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"));
+ // 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"));
+ // BEGIN android-removed
+ // algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ // algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ // END android-removed
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ // BEGIN android-removed
+ // algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ // END android-removed
+ 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"));
+ // BEGIN android-removed
+ // algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ // algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ // algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ // algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ // 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"));
+ // BEGIN android-removed
+ // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ // END android-removed
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ // BEGIN android-removed
+ // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ // END android-removed
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ // BEGIN android-removed
+ // algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ // algorithms.put("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ // 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);
+ // END android-removed
+
+ //
+ // reverse mappings
+ //
+ oids.put(new DERObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+ // BEGIN android-removed
+ // oids.put(PKCSObjectIdentifiers.sha224WithRSAEncryption, "SHA224WITHRSA");
+ // END android-removed
+ oids.put(PKCSObjectIdentifiers.sha256WithRSAEncryption, "SHA256WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha384WithRSAEncryption, "SHA384WITHRSA");
+ oids.put(PKCSObjectIdentifiers.sha512WithRSAEncryption, "SHA512WITHRSA");
+ // BEGIN android-removed
+ // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94, "GOST3411WITHGOST3410");
+ // oids.put(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001, "GOST3411WITHECGOST3410");
+ // END android-removed
+
+ oids.put(new DERObjectIdentifier("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");
+ // END android-removed
+ oids.put(new DERObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA1, "SHA1WITHECDSA");
+ // BEGIN android-removed
+ // oids.put(X9ObjectIdentifiers.ecdsa_with_SHA224, "SHA224WITHECDSA");
+ // END android-removed
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA256, "SHA256WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA384, "SHA384WITHECDSA");
+ oids.put(X9ObjectIdentifiers.ecdsa_with_SHA512, "SHA512WITHECDSA");
+ oids.put(OIWObjectIdentifiers.sha1WithRSA, "SHA1WITHRSA");
+ oids.put(OIWObjectIdentifiers.dsaWithSHA1, "SHA1WITHDSA");
+ // BEGIN android-removed
+ // oids.put(NISTObjectIdentifiers.dsa_with_sha224, "SHA224WITHDSA");
+ // END android-removed
+ oids.put(NISTObjectIdentifiers.dsa_with_sha256, "SHA256WITHDSA");
+
+ //
+ // key types
+ //
+ keyAlgorithms.put(PKCSObjectIdentifiers.rsaEncryption, "RSA");
+ keyAlgorithms.put(X9ObjectIdentifiers.id_dsa, "DSA");
+
+ //
+ // 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.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ // BEGIN android-removed
+ // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ // END android-removed
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ // BEGIN android-removed
+ // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ // END android-removed
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+
+ //
+ // RFC 4491
+ //
+ // BEGIN android-removed
+ // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ // END android-removed
+ //
+ // explicit params
+ //
+ // BEGIN android-changed
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+ // END android-changed
+ params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+ // BEGIN android-removed
+ // // BEGIN android-changed
+ // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+ // // END android-changed
+ // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+ // END android-removed
+
+ // BEGIN android-changed
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+ // END android-changed
+ params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+ // BEGIN android-changed
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
+ // END android-changed
+ params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+ // BEGIN android-changed
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
+ // END android-changed
+ params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+ }
+
+ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ private static ASN1Sequence toDERSequence(
+ byte[] bytes)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+
+ return (ASN1Sequence)dIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("badly encoded request");
+ }
+ }
+
+ /**
+ * construct a PKCS10 certification request from a DER encoded
+ * byte stream.
+ */
+ public PKCS10CertificationRequest(
+ byte[] bytes)
+ {
+ super(toDERSequence(bytes));
+ }
+
+ public PKCS10CertificationRequest(
+ ASN1Sequence sequence)
+ {
+ super(sequence);
+ }
+
+ /**
+ * create a PKCS10 certfication request using the BC provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X509Name subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ this(signatureAlgorithm, subject, key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ private static X509Name convertName(
+ X500Principal name)
+ {
+ try
+ {
+ return new X509Principal(name.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't convert name");
+ }
+ }
+
+ /**
+ * create a PKCS10 certfication request using the BC provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X500Principal subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ /**
+ * create a PKCS10 certfication request using the named provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X500Principal subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ this(signatureAlgorithm, convertName(subject), key, attributes, signingKey, provider);
+ }
+
+ /**
+ * create a PKCS10 certfication request using the named provider.
+ */
+ public PKCS10CertificationRequest(
+ String signatureAlgorithm,
+ X509Name subject,
+ PublicKey key,
+ ASN1Set attributes,
+ PrivateKey signingKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ String algorithmName = Strings.toUpperCase(signatureAlgorithm);
+ DERObjectIdentifier sigOID = (DERObjectIdentifier)algorithms.get(algorithmName);
+
+ if (sigOID == null)
+ {
+ try
+ {
+ sigOID = new DERObjectIdentifier(algorithmName);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+ }
+
+ if (subject == null)
+ {
+ throw new IllegalArgumentException("subject must not be null");
+ }
+
+ if (key == null)
+ {
+ throw new IllegalArgumentException("public key must not be null");
+ }
+
+ if (noParams.contains(sigOID))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID);
+ }
+ else if (params.containsKey(algorithmName))
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ this.sigAlgId = new AlgorithmIdentifier(sigOID, DERNull.INSTANCE);
+ }
+
+ try
+ {
+ ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(key.getEncoded());
+ this.reqInfo = new CertificationRequestInfo(subject, new SubjectPublicKeyInfo(seq), attributes);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't encode public key");
+ }
+
+ Signature sig;
+ if (provider == null)
+ {
+ sig = Signature.getInstance(signatureAlgorithm);
+ }
+ else
+ {
+ sig = Signature.getInstance(signatureAlgorithm, provider);
+ }
+
+ sig.initSign(signingKey);
+
+ try
+ {
+ sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("exception encoding TBS cert request - " + e);
+ }
+
+ this.sigBits = new DERBitString(sig.sign());
+ }
+
+ /**
+ * return the public key associated with the certification request -
+ * the public key is created using the BC provider.
+ */
+ public PublicKey getPublicKey()
+ throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException
+ {
+ return getPublicKey(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public PublicKey getPublicKey(
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException
+ {
+ SubjectPublicKeyInfo subjectPKInfo = reqInfo.getSubjectPublicKeyInfo();
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(subjectPKInfo).getBytes());
+ AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithmId();
+
+ try
+ {
+ try
+ {
+ if (provider == null)
+ {
+ return KeyFactory.getInstance(keyAlg.getObjectId().getId()).generatePublic(xspec);
+ }
+ else
+ {
+ return KeyFactory.getInstance(keyAlg.getObjectId().getId(), provider).generatePublic(xspec);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (keyAlgorithms.get(keyAlg.getObjectId()) != null)
+ {
+ String keyAlgorithm = (String)keyAlgorithms.get(keyAlg.getObjectId());
+
+ if (provider == null)
+ {
+ return KeyFactory.getInstance(keyAlgorithm).generatePublic(xspec);
+ }
+ else
+ {
+ return KeyFactory.getInstance(keyAlgorithm, provider).generatePublic(xspec);
+ }
+ }
+
+ throw e;
+ }
+ }
+ catch (InvalidKeySpecException e)
+ {
+ throw new InvalidKeyException("error decoding public key");
+ }
+ }
+
+ /**
+ * verify the request using the BC provider.
+ */
+ public boolean verify()
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ return verify(BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ /**
+ * verify the request using the passed in provider.
+ */
+ public boolean verify(
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ return verify(this.getPublicKey(provider), provider);
+ }
+
+ /**
+ * verify the request using the passed in public key and the provider..
+ */
+ public boolean verify(
+ PublicKey pubKey,
+ String provider)
+ throws NoSuchAlgorithmException, NoSuchProviderException,
+ InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ try
+ {
+ if (provider == null)
+ {
+ sig = Signature.getInstance(getSignatureName(sigAlgId));
+ }
+ else
+ {
+ sig = Signature.getInstance(getSignatureName(sigAlgId), provider);
+ }
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ //
+ // try an alternate
+ //
+ if (oids.get(sigAlgId.getObjectId()) != null)
+ {
+ String signatureAlgorithm = (String)oids.get(sigAlgId.getObjectId());
+
+ if (provider == null)
+ {
+ sig = Signature.getInstance(signatureAlgorithm);
+ }
+ else
+ {
+ sig = Signature.getInstance(signatureAlgorithm, provider);
+ }
+ }
+ else
+ {
+ throw e;
+ }
+ }
+
+ setSignatureParameters(sig, sigAlgId.getParameters());
+
+ sig.initVerify(pubKey);
+
+ try
+ {
+ sig.update(reqInfo.getEncoded(ASN1Encoding.DER));
+ }
+ catch (Exception e)
+ {
+ throw new SignatureException("exception encoding TBS cert request - " + e);
+ }
+
+ return sig.verify(sigBits.getBytes());
+ }
+
+ /**
+ * return a DER encoded byte array representing this object
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ return this.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ private void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+
+ try
+ {
+ sigParams.init(params.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+
+ if (signature.getAlgorithm().endsWith("MGF1"))
+ {
+ try
+ {
+ signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !DERNull.INSTANCE.equals(params))
+ {
+ if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ {
+ RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+ return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+ }
+ }
+
+ return sigAlgId.getObjectId().getId();
+ }
+
+ private static String getDigestAlgName(
+ DERObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ // BEGIN android-removed
+ // else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ // {
+ // return "SHA224";
+ // }
+ // END android-removed
+ 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/bcprov/src/main/java/org/bouncycastle/jce/PrincipalUtil.java b/bcprov/src/main/java/org/bouncycastle/jce/PrincipalUtil.java
new file mode 100644
index 0000000..4bf65a0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/PrincipalUtil.java
@@ -0,0 +1,81 @@
+package org.bouncycastle.jce;
+
+import java.io.IOException;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.x509.TBSCertList;
+import org.bouncycastle.asn1.x509.TBSCertificateStructure;
+import org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * a utility class that will extract X509Principal objects from X.509 certificates.
+ * <p>
+ * Use this in preference to trying to recreate a principal from a String, not all
+ * DNs are what they should be, so it's best to leave them encoded where they
+ * can be.
+ */
+public class PrincipalUtil
+{
+ /**
+ * return the issuer of the given cert as an X509PrincipalObject.
+ */
+ public static X509Principal getIssuerX509Principal(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ TBSCertificateStructure tbsCert = TBSCertificateStructure.getInstance(
+ ASN1Primitive.fromByteArray(cert.getTBSCertificate()));
+
+ return new X509Principal(X509Name.getInstance(tbsCert.getIssuer()));
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ /**
+ * return the subject of the given cert as an X509PrincipalObject.
+ */
+ public static X509Principal getSubjectX509Principal(
+ X509Certificate cert)
+ throws CertificateEncodingException
+ {
+ try
+ {
+ TBSCertificateStructure tbsCert = TBSCertificateStructure.getInstance(
+ ASN1Primitive.fromByteArray(cert.getTBSCertificate()));
+ return new X509Principal(X509Name.getInstance(tbsCert.getSubject()));
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ /**
+ * return the issuer of the given CRL as an X509PrincipalObject.
+ */
+ public static X509Principal getIssuerX509Principal(
+ X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ TBSCertList tbsCertList = TBSCertList.getInstance(
+ ASN1Primitive.fromByteArray(crl.getTBSCertList()));
+
+ return new X509Principal(X509Name.getInstance(tbsCertList.getIssuer()));
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java b/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java
new file mode 100644
index 0000000..efa0f66
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/X509Principal.java
@@ -0,0 +1,164 @@
+package org.bouncycastle.jce;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.X509Name;
+
+/**
+ * a general extension of X509Name with a couple of extra methods and
+ * constructors.
+ * <p>
+ * Objects of this type can be created from certificates and CRLs using the
+ * PrincipalUtil class.
+ * </p>
+ * @see org.bouncycastle.jce.PrincipalUtil
+ */
+public class X509Principal
+ extends X509Name
+ implements Principal
+{
+ private static ASN1Sequence readSequence(
+ ASN1InputStream aIn)
+ throws IOException
+ {
+ try
+ {
+ return ASN1Sequence.getInstance(aIn.readObject());
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IOException("not an ASN.1 Sequence: " + e);
+ }
+ }
+
+ /**
+ * Constructor from an encoded byte array.
+ */
+ public X509Principal(
+ byte[] bytes)
+ throws IOException
+ {
+ super(readSequence(new ASN1InputStream(bytes)));
+ }
+
+ /**
+ * Constructor from an X509Name object.
+ */
+ public X509Principal(
+ X509Name name)
+ {
+ super((ASN1Sequence)name.toASN1Primitive());
+ }
+
+ /**
+ * Constructor from an X509Name object.
+ */
+ public X509Principal(
+ X500Name name)
+ {
+ super((ASN1Sequence)name.toASN1Primitive());
+ }
+
+ /**
+ * constructor from a table of attributes.
+ * <p>
+ * it's is assumed the table contains OID/String pairs.
+ */
+ public X509Principal(
+ Hashtable attributes)
+ {
+ super(attributes);
+ }
+
+ /**
+ * constructor from a table of attributes and a vector giving the
+ * specific ordering required for encoding or conversion to a string.
+ * <p>
+ * it's is assumed the table contains OID/String pairs.
+ */
+ public X509Principal(
+ Vector ordering,
+ Hashtable attributes)
+ {
+ super(ordering, attributes);
+ }
+
+ /**
+ * constructor from a vector of attribute values and a vector of OIDs.
+ */
+ public X509Principal(
+ Vector oids,
+ Vector values)
+ {
+ super(oids, values);
+ }
+
+ /**
+ * 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.
+ */
+ public X509Principal(
+ String dirName)
+ {
+ super(dirName);
+ }
+
+ /**
+ * 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. If reverse
+ * is false the dir name will be encoded in the order of the (name, value) pairs
+ * presented, otherwise the encoding will start with the last (name, value) pair
+ * and work back.
+ */
+ public X509Principal(
+ boolean reverse,
+ String dirName)
+ {
+ super(reverse, dirName);
+ }
+
+ /**
+ * 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
+ * will be processed automatically.
+ * <p>
+ * If reverse is true, create the encoded version of the sequence starting
+ * from the last element in the string.
+ */
+ public X509Principal(
+ boolean reverse,
+ Hashtable lookUp,
+ String dirName)
+ {
+ super(reverse, lookUp, dirName);
+ }
+
+ public String getName()
+ {
+ return this.toString();
+ }
+
+ /**
+ * return a DER encoded byte array representing this object
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ return this.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/exception/ExtCertPathBuilderException.java b/bcprov/src/main/java/org/bouncycastle/jce/exception/ExtCertPathBuilderException.java
new file mode 100644
index 0000000..a0b2d90
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/exception/ExtCertPathBuilderException.java
@@ -0,0 +1,29 @@
+package org.bouncycastle.jce.exception;
+
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilderException;
+
+public class ExtCertPathBuilderException
+ extends CertPathBuilderException
+ implements ExtException
+{
+ private Throwable cause;
+
+ public ExtCertPathBuilderException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathBuilderException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/exception/ExtCertPathValidatorException.java b/bcprov/src/main/java/org/bouncycastle/jce/exception/ExtCertPathValidatorException.java
new file mode 100644
index 0000000..e36848f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/exception/ExtCertPathValidatorException.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.jce.exception;
+
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+
+public class ExtCertPathValidatorException
+ extends CertPathValidatorException
+ implements ExtException
+{
+
+ private Throwable cause;
+
+ public ExtCertPathValidatorException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public ExtCertPathValidatorException(String msg, Throwable cause,
+ CertPath certPath, int index)
+ {
+ super(msg, cause, certPath, index);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/exception/ExtException.java b/bcprov/src/main/java/org/bouncycastle/jce/exception/ExtException.java
new file mode 100644
index 0000000..52c60de
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/exception/ExtException.java
@@ -0,0 +1,21 @@
+package org.bouncycastle.jce.exception;
+
+/**
+ *
+ * This is an extended exception. Java before version 1.4 did not offer the
+ * possibility the attach a cause to an exception. The cause of an exception is
+ * the <code>Throwable</code> object which was thrown and caused the
+ * exception. This interface must be implemented by all exceptions to accomplish
+ * this additional functionality.
+ *
+ */
+public interface ExtException
+{
+
+ /**
+ * Returns the cause of the exception.
+ *
+ * @return The cause of the exception.
+ */
+ Throwable getCause();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/interfaces/BCKeyStore.java b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/BCKeyStore.java
new file mode 100644
index 0000000..a36abbb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/BCKeyStore.java
@@ -0,0 +1,14 @@
+package org.bouncycastle.jce.interfaces;
+
+import java.security.SecureRandom;
+
+/**
+ * all BC provider keystores implement this interface.
+ */
+public interface BCKeyStore
+{
+ /**
+ * set the random source for the key store
+ */
+ public void setRandom(SecureRandom random);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECKey.java b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECKey.java
new file mode 100644
index 0000000..0812c12
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECKey.java
@@ -0,0 +1,15 @@
+package org.bouncycastle.jce.interfaces;
+
+import org.bouncycastle.jce.spec.ECParameterSpec;
+
+/**
+ * generic interface for an Elliptic Curve Key.
+ */
+public interface ECKey
+{
+ /**
+ * return a parameter specification representing the EC domain parameters
+ * for the key.
+ */
+ public ECParameterSpec getParameters();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPointEncoder.java b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPointEncoder.java
new file mode 100644
index 0000000..001dab3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPointEncoder.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.jce.interfaces;
+
+/**
+ * All BC elliptic curve keys implement this interface. You need to
+ * cast the key to get access to it.
+ * <p>
+ * By default BC keys produce encodings without point compression,
+ * to turn this on call setPointFormat() with "COMPRESSED".
+ */
+public interface ECPointEncoder
+{
+ /**
+ * Set the formatting for encoding of points. If the String "UNCOMPRESSED" is passed
+ * in point compression will not be used. If the String "COMPRESSED" is passed point
+ * compression will be used. The default is "UNCOMPRESSED".
+ *
+ * @param style the style to use.
+ */
+ public void setPointFormat(String style);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPrivateKey.java
new file mode 100644
index 0000000..39d80c3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPrivateKey.java
@@ -0,0 +1,16 @@
+package org.bouncycastle.jce.interfaces;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+
+/**
+ * interface for Elliptic Curve Private keys.
+ */
+public interface ECPrivateKey
+ extends ECKey, PrivateKey
+{
+ /**
+ * return the private value D.
+ */
+ public BigInteger getD();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPublicKey.java
new file mode 100644
index 0000000..db2ecdc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/ECPublicKey.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.jce.interfaces;
+
+import java.security.PublicKey;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * interface for elliptic curve public keys.
+ */
+public interface ECPublicKey
+ extends ECKey, PublicKey
+{
+ /**
+ * return the public point Q
+ */
+ public ECPoint getQ();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
new file mode 100644
index 0000000..cbc9f44
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/interfaces/PKCS12BagAttributeCarrier.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.jce.interfaces;
+
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+
+/**
+ * allow us to set attributes on objects that can go into a PKCS12 store.
+ */
+public interface PKCS12BagAttributeCarrier
+{
+ void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute);
+
+ ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid);
+
+ Enumeration getBagAttributeKeys();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java b/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
new file mode 100644
index 0000000..4bfb9d9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
@@ -0,0 +1,296 @@
+package org.bouncycastle.jce.netscape;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+/**
+ *
+ *
+ * Handles NetScape certificate request (KEYGEN), these are constructed as:
+ * <pre><code>
+ * SignedPublicKeyAndChallenge ::= SEQUENCE {
+ * publicKeyAndChallenge PublicKeyAndChallenge,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * </pre>
+ *
+ * PublicKey's encoded-format has to be X.509.
+ *
+ **/
+public class NetscapeCertRequest
+ extends ASN1Object
+{
+ AlgorithmIdentifier sigAlg;
+ AlgorithmIdentifier keyAlg;
+ byte sigBits [];
+ String challenge;
+ DERBitString content;
+ PublicKey pubkey ;
+
+ private static ASN1Sequence getReq(
+ byte[] r)
+ throws IOException
+ {
+ ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(r));
+
+ return ASN1Sequence.getInstance(aIn.readObject());
+ }
+
+ public NetscapeCertRequest(
+ byte[] req)
+ throws IOException
+ {
+ this(getReq(req));
+ }
+
+ public NetscapeCertRequest (ASN1Sequence spkac)
+ {
+ try
+ {
+
+ //
+ // SignedPublicKeyAndChallenge ::= SEQUENCE {
+ // publicKeyAndChallenge PublicKeyAndChallenge,
+ // signatureAlgorithm AlgorithmIdentifier,
+ // signature BIT STRING
+ // }
+ //
+ if (spkac.size() != 3)
+ {
+ throw new IllegalArgumentException("invalid SPKAC (size):"
+ + spkac.size());
+ }
+
+ sigAlg = new AlgorithmIdentifier((ASN1Sequence)spkac
+ .getObjectAt(1));
+ sigBits = ((DERBitString)spkac.getObjectAt(2)).getBytes();
+
+ //
+ // PublicKeyAndChallenge ::= SEQUENCE {
+ // spki SubjectPublicKeyInfo,
+ // challenge IA5STRING
+ // }
+ //
+ ASN1Sequence pkac = (ASN1Sequence)spkac.getObjectAt(0);
+
+ if (pkac.size() != 2)
+ {
+ throw new IllegalArgumentException("invalid PKAC (len): "
+ + pkac.size());
+ }
+
+ challenge = ((DERIA5String)pkac.getObjectAt(1)).getString();
+
+ //this could be dangerous, as ASN.1 decoding/encoding
+ //could potentially alter the bytes
+ content = new DERBitString(pkac);
+
+ SubjectPublicKeyInfo pubkeyinfo = new SubjectPublicKeyInfo(
+ (ASN1Sequence)pkac.getObjectAt(0));
+
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(
+ pubkeyinfo).getBytes());
+
+ keyAlg = pubkeyinfo.getAlgorithmId();
+ pubkey = KeyFactory.getInstance(keyAlg.getObjectId().getId(), "BC")
+ .generatePublic(xspec);
+
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException(e.toString());
+ }
+ }
+
+ public NetscapeCertRequest(
+ String challenge,
+ AlgorithmIdentifier signing_alg,
+ PublicKey pub_key) throws NoSuchAlgorithmException,
+ InvalidKeySpecException, NoSuchProviderException
+ {
+
+ this.challenge = challenge;
+ sigAlg = signing_alg;
+ pubkey = pub_key;
+
+ ASN1EncodableVector content_der = new ASN1EncodableVector();
+ content_der.add(getKeySpec());
+ //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject()));
+ content_der.add(new DERIA5String(challenge));
+
+ content = new DERBitString(new DERSequence(content_der));
+ }
+
+ public String getChallenge()
+ {
+ return challenge;
+ }
+
+ public void setChallenge(String value)
+ {
+ challenge = value;
+ }
+
+ public AlgorithmIdentifier getSigningAlgorithm()
+ {
+ return sigAlg;
+ }
+
+ public void setSigningAlgorithm(AlgorithmIdentifier value)
+ {
+ sigAlg = value;
+ }
+
+ public AlgorithmIdentifier getKeyAlgorithm()
+ {
+ return keyAlg;
+ }
+
+ public void setKeyAlgorithm(AlgorithmIdentifier value)
+ {
+ keyAlg = value;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ return pubkey;
+ }
+
+ public void setPublicKey(PublicKey value)
+ {
+ pubkey = value;
+ }
+
+ public boolean verify(String challenge) throws NoSuchAlgorithmException,
+ InvalidKeyException, SignatureException, NoSuchProviderException
+ {
+ if (!challenge.equals(this.challenge))
+ {
+ return false;
+ }
+
+ //
+ // Verify the signature .. shows the response was generated
+ // by someone who knew the associated private key
+ //
+ Signature sig = Signature.getInstance(sigAlg.getObjectId().getId(),
+ "BC");
+ sig.initVerify(pubkey);
+ sig.update(content.getBytes());
+
+ return sig.verify(sigBits);
+ }
+
+ public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException,
+ InvalidKeyException, SignatureException, NoSuchProviderException,
+ InvalidKeySpecException
+ {
+ sign(priv_key, null);
+ }
+
+ public void sign(PrivateKey priv_key, SecureRandom rand)
+ throws NoSuchAlgorithmException, InvalidKeyException,
+ SignatureException, NoSuchProviderException,
+ InvalidKeySpecException
+ {
+ Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(),
+ "BC");
+
+ if (rand != null)
+ {
+ sig.initSign(priv_key, rand);
+ }
+ else
+ {
+ sig.initSign(priv_key);
+ }
+
+ ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+ pkac.add(getKeySpec());
+ pkac.add(new DERIA5String(challenge));
+
+ try
+ {
+ sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER));
+ }
+ catch (IOException ioe)
+ {
+ throw new SignatureException(ioe.getMessage());
+ }
+
+ sigBits = sig.sign();
+ }
+
+ private ASN1Primitive getKeySpec() throws NoSuchAlgorithmException,
+ InvalidKeySpecException, NoSuchProviderException
+ {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ ASN1Primitive obj = null;
+ try
+ {
+
+ baos.write(pubkey.getEncoded());
+ baos.close();
+
+ ASN1InputStream derin = new ASN1InputStream(
+ new ByteArrayInputStream(baos.toByteArray()));
+
+ obj = derin.readObject();
+ }
+ catch (IOException ioe)
+ {
+ throw new InvalidKeySpecException(ioe.getMessage());
+ }
+ return obj;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector spkac = new ASN1EncodableVector();
+ ASN1EncodableVector pkac = new ASN1EncodableVector();
+
+ try
+ {
+ pkac.add(getKeySpec());
+ }
+ catch (Exception e)
+ {
+ //ignore
+ }
+
+ pkac.add(new DERIA5String(challenge));
+
+ spkac.add(new DERSequence(pkac));
+ spkac.add(sigAlg);
+ spkac.add(new DERBitString(sigBits));
+
+ return new DERSequence(spkac);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java
new file mode 100644
index 0000000..c9ac46e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/AnnotatedException.java
@@ -0,0 +1,32 @@
+package org.bouncycastle.jce.provider;
+
+import org.bouncycastle.jce.exception.ExtException;
+
+public class AnnotatedException
+ extends Exception
+ implements ExtException
+{
+ private Throwable _underlyingException;
+
+ AnnotatedException(String string, Throwable e)
+ {
+ super(string);
+
+ _underlyingException = e;
+ }
+
+ AnnotatedException(String string)
+ {
+ this(string, null);
+ }
+
+ Throwable getUnderlyingException()
+ {
+ return _underlyingException;
+ }
+
+ public Throwable getCause()
+ {
+ return _underlyingException;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
new file mode 100644
index 0000000..5ed4df9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -0,0 +1,628 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.AccessController;
+import java.security.PrivateKey;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jcajce.provider.util.AlgorithmProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+
+/**
+ * To add the provider at runtime use:
+ * <pre>
+ * import java.security.Security;
+ * import org.bouncycastle.jce.provider.BouncyCastleProvider;
+ *
+ * Security.addProvider(new BouncyCastleProvider());
+ * </pre>
+ * The provider can also be configured as part of your environment via
+ * static registration by adding an entry to the java.security properties
+ * file (found in $JAVA_HOME/jre/lib/security/java.security, where
+ * $JAVA_HOME is the location of your JDK/JRE distribution). You'll find
+ * detailed instructions in the file but basically it comes down to adding
+ * a line:
+ * <pre>
+ * <code>
+ * security.provider.&lt;n&gt;=org.bouncycastle.jce.provider.BouncyCastleProvider
+ * </code>
+ * </pre>
+ * Where &lt;n&gt; is the preference you want the provider at (1 being the
+ * most preferred).
+ * <p>Note: JCE algorithm names should be upper-case only so the case insensitive
+ * test for getInstance works.
+ */
+public final class BouncyCastleProvider extends Provider
+ implements ConfigurableProvider
+{
+ private static String info = "BouncyCastle Security Provider v1.47";
+
+ // BEGIN android-changed
+ // this constant should be final
+ public static final String PROVIDER_NAME = "BC";
+ // END android-changed
+
+ public static final ProviderConfiguration CONFIGURATION = new BouncyCastleProviderConfiguration();
+
+
+ private static final Map keyInfoConverters = new HashMap();
+
+ /*
+ * Configurable symmetric ciphers
+ */
+ private static final String SYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jcajce.provider.symmetric.";
+ private static final String[] SYMMETRIC_CIPHERS =
+ {
+ // BEGIN android-removed
+ // "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DES", "DESede", "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
+ // "Noekeon", "RC2", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
+ // END android-removed
+ // BEGIN android-added
+ "AES", "ARC4", "Blowfish", "DES", "DESede",
+ // END android-added
+ };
+
+ /*
+ * Configurable asymmetric ciphers
+ */
+ private static final String ASYMMETRIC_CIPHER_PACKAGE = "org.bouncycastle.jcajce.provider.asymmetric.";
+
+ // this one is required for GNU class path - it needs to be loaded first as the
+ // later ones configure it.
+ private static final String[] ASYMMETRIC_GENERIC =
+ {
+ "X509"
+ };
+
+ private static final String[] ASYMMETRIC_CIPHERS =
+ {
+ // BEGIN android-removed
+ // "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal"
+ // END android-removed
+ // BEGIN android-added
+ "DSA", "DH", "EC", "RSA",
+ // END android-added
+ };
+
+ /*
+ * Configurable digests
+ */
+ private static final String DIGEST_PACKAGE = "org.bouncycastle.jcajce.provider.digest.";
+ private static final String[] DIGESTS =
+ {
+ // BEGIN android-removed
+ // "GOST3411", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", "SHA256", "SHA384", "SHA512", "Tiger", "Whirlpool"
+ // END android-removed
+ // BEGIN android-added
+ "MD5", "SHA1", "SHA256", "SHA384", "SHA512",
+ // END android-added
+ };
+
+ /**
+ * Construct a new provider. This should only be required when
+ * using runtime registration of the provider using the
+ * <code>Security.addProvider()</code> mechanism.
+ */
+ public BouncyCastleProvider()
+ {
+ super(PROVIDER_NAME, 1.47, info);
+
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ setup();
+ return null;
+ }
+ });
+ }
+
+ private void setup()
+ {
+ loadAlgorithms(DIGEST_PACKAGE, DIGESTS);
+
+ loadAlgorithms(SYMMETRIC_CIPHER_PACKAGE, SYMMETRIC_CIPHERS);
+
+ loadAlgorithms(ASYMMETRIC_CIPHER_PACKAGE, ASYMMETRIC_GENERIC);
+
+ loadAlgorithms(ASYMMETRIC_CIPHER_PACKAGE, ASYMMETRIC_CIPHERS);
+
+ // BEGIN android-removed
+ // //
+ // // X509Store
+ // //
+ // put("X509Store.CERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertCollection");
+ // put("X509Store.ATTRIBUTECERTIFICATE/COLLECTION", "org.bouncycastle.jce.provider.X509StoreAttrCertCollection");
+ // put("X509Store.CRL/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCRLCollection");
+ // put("X509Store.CERTIFICATEPAIR/COLLECTION", "org.bouncycastle.jce.provider.X509StoreCertPairCollection");
+ //
+ // put("X509Store.CERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCerts");
+ // put("X509Store.CRL/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCRLs");
+ // put("X509Store.ATTRIBUTECERTIFICATE/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPAttrCerts");
+ // put("X509Store.CERTIFICATEPAIR/LDAP", "org.bouncycastle.jce.provider.X509StoreLDAPCertPairs");
+ //
+ // //
+ // // X509StreamParser
+ // //
+ // put("X509StreamParser.CERTIFICATE", "org.bouncycastle.jce.provider.X509CertParser");
+ // put("X509StreamParser.ATTRIBUTECERTIFICATE", "org.bouncycastle.jce.provider.X509AttrCertParser");
+ // put("X509StreamParser.CRL", "org.bouncycastle.jce.provider.X509CRLParser");
+ // put("X509StreamParser.CERTIFICATEPAIR", "org.bouncycastle.jce.provider.X509CertPairParser");
+ // END android-removed
+
+
+ //
+ // KeyStore
+ //
+ put("KeyStore.BKS", "org.bouncycastle.jce.provider.JDKKeyStore");
+ put("KeyStore.BouncyCastle", "org.bouncycastle.jce.provider.JDKKeyStore$BouncyCastleStore");
+ put("KeyStore.PKCS12", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$BCPKCS12KeyStore");
+ // BEGIN android-changed
+ put("Alg.Alias.KeyStore.BCPKCS12", "PKCS12");
+ // END android-changed
+ // BEGIN android-removed
+ // put("KeyStore.PKCS12-DEF", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$DefPKCS12KeyStore");
+ // END android-removed
+
+ // BEGIN android-changed
+ put("Alg.Alias.KeyStore.PKCS12-3DES-40RC2", "PKCS12");
+ // END android-changed
+ // BEGIN android-removed
+ // put("KeyStore.PKCS12-3DES-3DES", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$BCPKCS12KeyStore3DES");
+ // END android-removed
+
+ // BEGIN android-removed
+ // put("KeyStore.PKCS12-DEF-3DES-40RC2", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$DefPKCS12KeyStore");
+ // put("KeyStore.PKCS12-DEF-3DES-3DES", "org.bouncycastle.jce.provider.JDKPKCS12KeyStore$DefPKCS12KeyStore3DES");
+ // END android-removed
+
+ put("Alg.Alias.KeyStore.UBER", "BouncyCastle");
+ put("Alg.Alias.KeyStore.BOUNCYCASTLE", "BouncyCastle");
+ put("Alg.Alias.KeyStore.bouncycastle", "BouncyCastle");
+
+ //
+ // algorithm parameters
+ //
+ // BEGIN android-removed
+ // put("AlgorithmParameters.IES", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$IES");
+ // END android-removed
+ put("AlgorithmParameters.PKCS12PBE", "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PKCS12PBE");
+
+ // BEGIN android-removed
+ // put("AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "org.bouncycastle.jce.provider.JDKAlgorithmParameters$PBKDF2");
+ // END android-removed
+
+
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2", "PKCS12PBE");
+ // BEGIN android-removed
+ // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES", "PKCS12PBE");
+ // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES", "PKCS12PBE");
+ // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDRC2", "PKCS12PBE");
+ // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDRC4", "PKCS12PBE");
+ // END android-removed
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH", "PKCS12PBE");
+ // BEGIN android-removed
+ // put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1ANDRC2-CBC", "PKCS12PBE");
+ // END android-removed
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PKCS12PBE");
+ // BEGIN android-removed
+ // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES3KEY-CBC", "PKCS12PBE");
+ // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES2KEY-CBC", "PKCS12PBE");
+ // END android-removed
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC2-CBC", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND40BITRC4", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC2-CBC", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITRC4", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH", "PKCS12PBE");
+ // BEGIN android-removed
+ // put("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDTWOFISH-CBC", "PKCS12PBE");
+ // END android-removed
+ put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.1", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.2", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.3", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.4", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.5", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.1.2.840.113549.1.12.1.6", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWithSHAAnd3KeyTripleDES", "PKCS12PBE");
+
+ put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PKCS12PBE");
+
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND128BITAES-CBC-BC", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND192BITAES-CBC-BC", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND256BITAES-CBC-BC", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND128BITAES-CBC-BC", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND192BITAES-CBC-BC", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA256AND256BITAES-CBC-BC", "PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND128BITAES-CBC-BC","PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND192BITAES-CBC-BC","PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA1AND256BITAES-CBC-BC","PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND128BITAES-CBC-BC","PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND192BITAES-CBC-BC","PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-1AND256BITAES-CBC-BC","PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND128BITAES-CBC-BC","PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND192BITAES-CBC-BC","PKCS12PBE");
+ put("Alg.Alias.AlgorithmParameters.PBEWITHSHA-256AND256BITAES-CBC-BC","PKCS12PBE");
+
+ // BEGIN android-removed
+ // put("AlgorithmParameters.SHA1WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+ // put("AlgorithmParameters.SHA224WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+ // put("AlgorithmParameters.SHA256WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+ // put("AlgorithmParameters.SHA384WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+ // put("AlgorithmParameters.SHA512WITHECDSA", "org.bouncycastle.jce.provider.JDKECDSAAlgParameters$SigAlgParameters");
+ // END android-removed
+
+ //
+ // key agreement
+ //
+
+
+ //
+ // cipher engines
+ //
+ put("Alg.Alias.Cipher.PBEWithSHAAnd3KeyTripleDES", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+
+
+ // BEGIN android-removed
+ // put("Cipher.ECIES", "org.bouncycastle.jce.provider.JCEIESCipher$ECIES");
+ // put("Cipher.BrokenECIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenECIES");
+ // put("Cipher.IES", "org.bouncycastle.jce.provider.JCEIESCipher$IES");
+ // put("Cipher.BrokenIES", "org.bouncycastle.jce.provider.JCEIESCipher$BrokenIES");
+ // END android-removed
+
+ put("Cipher.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithMD5AndDES");
+ // BEGIN android-removed
+ // put("Cipher.BROKENPBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithMD5AndDES");
+ // END android-removed
+ put("Cipher.PBEWITHMD5ANDRC2", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithMD5AndRC2");
+ put("Cipher.PBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHA1AndDES");
+ // BEGIN android-removed
+ // put("Cipher.BROKENPBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$BrokePBEWithSHA1AndDES");
+ // END android-removed
+ put("Cipher.PBEWITHSHA1ANDRC2", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHA1AndRC2");
+
+ put("Cipher.PBEWITHSHAAND128BITRC2-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd128BitRC2");
+ put("Cipher.PBEWITHSHAAND40BITRC2-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAnd40BitRC2");
+ put("Cipher.PBEWITHSHAAND128BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd128BitRC4");
+ put("Cipher.PBEWITHSHAAND40BITRC4", "org.bouncycastle.jce.provider.JCEStreamCipher$PBEWithSHAAnd40BitRC4");
+
+
+ put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC2-CBC", "PBEWITHSHAAND128BITRC2-CBC");
+ put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC2-CBC", "PBEWITHSHAAND40BITRC2-CBC");
+ put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITRC4", "PBEWITHSHAAND128BITRC4");
+ put("Alg.Alias.Cipher.PBEWITHSHA1AND40BITRC4", "PBEWITHSHAAND40BITRC4");
+
+ put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
+ put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
+ put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PBEWITHSHAAND256BITAES-CBC-BC");
+ put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
+ put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
+ put("Alg.Alias.Cipher." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
+
+ put("Cipher.PBEWITHSHAAND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+ put("Cipher.PBEWITHSHAAND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+ put("Cipher.PBEWITHSHAAND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+ put("Cipher.PBEWITHSHA256AND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+ put("Cipher.PBEWITHSHA256AND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+ put("Cipher.PBEWITHSHA256AND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+ put("Alg.Alias.Cipher.PBEWITHSHA1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+ put("Alg.Alias.Cipher.PBEWITHSHA1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+ put("Alg.Alias.Cipher.PBEWITHSHA1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+ put("Alg.Alias.Cipher.PBEWITHSHA-1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+ put("Alg.Alias.Cipher.PBEWITHSHA-1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+ put("Alg.Alias.Cipher.PBEWITHSHA-1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+ put("Alg.Alias.Cipher.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+ put("Alg.Alias.Cipher.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+ put("Alg.Alias.Cipher.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+
+ put("Cipher.PBEWITHMD5AND128BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+ put("Cipher.PBEWITHMD5AND192BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+ put("Cipher.PBEWITHMD5AND256BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithAESCBC");
+
+ put("Cipher.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCEBlockCipher$PBEWithSHAAndTwofish");
+ // BEGIN android-removed
+ // put("Cipher.OLDPBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.BrokenJCEBlockCipher$OldPBEWithSHAAndTwofish");
+ //
+ // put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+ // put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
+ // END android-removed
+ put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+ put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDDES");
+ put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+ put("Alg.Alias.Cipher." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
+
+ put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.1", "PBEWITHSHAAND128BITRC4");
+ put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.2", "PBEWITHSHAAND40BITRC4");
+
+ put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
+ put("Alg.Alias.Cipher.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
+
+ //
+ // key generators.
+ //
+
+
+ //
+ // key pair generators.
+ //
+
+
+
+ //
+ // key factories
+ //
+
+
+
+
+ //
+ // Algorithm parameters
+ //
+
+ //
+ // secret key factories.
+ //
+ // BEGIN android-removed
+ // put("SecretKeyFactory.PBEWITHMD2ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndDES");
+ //
+ // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+ // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
+ // END android-removed
+ put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+ put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDDES");
+ put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+ put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
+
+ // BEGIN android-removed
+ // put("SecretKeyFactory.PBEWITHMD2ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD2AndRC2");
+ // END android-removed
+ put("SecretKeyFactory.PBEWITHMD5ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndDES");
+ put("SecretKeyFactory.PBEWITHMD5ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5AndRC2");
+ put("SecretKeyFactory.PBEWITHSHA1ANDDES", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA1AndDES");
+ put("SecretKeyFactory.PBEWITHSHA1ANDRC2", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA1AndRC2");
+ put("SecretKeyFactory.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndDES3Key");
+ put("SecretKeyFactory.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndDES2Key");
+ put("SecretKeyFactory.PBEWITHSHAAND128BITRC4", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd128BitRC4");
+ put("SecretKeyFactory.PBEWITHSHAAND40BITRC4", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd40BitRC4");
+ put("SecretKeyFactory.PBEWITHSHAAND128BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd128BitRC2");
+ put("SecretKeyFactory.PBEWITHSHAAND40BITRC2-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd40BitRC2");
+ put("SecretKeyFactory.PBEWITHSHAANDTWOFISH-CBC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAndTwofish");
+ // BEGIN android-removed
+ // put("SecretKeyFactory.PBEWITHHMACRIPEMD160", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithRIPEMD160");
+ // END android-removed
+ put("SecretKeyFactory.PBEWITHHMACSHA1", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA");
+ // BEGIN android-removed
+ // put("SecretKeyFactory.PBEWITHHMACTIGER", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithTiger");
+ // END android-removed
+
+ put("SecretKeyFactory.PBEWITHMD5AND128BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5And128BitAESCBCOpenSSL");
+ put("SecretKeyFactory.PBEWITHMD5AND192BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5And192BitAESCBCOpenSSL");
+ put("SecretKeyFactory.PBEWITHMD5AND256BITAES-CBC-OPENSSL", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithMD5And256BitAESCBCOpenSSL");
+
+ // BEGIN android-removed
+ // put("Alg.Alias.SecretKeyFactory.PBE", "PBE/PKCS5");
+ //
+ // put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHMD5ANDDES", "PBE/PKCS5");
+ // put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHA1ANDDES", "PBE/PKCS5");
+ // put("Alg.Alias.SecretKeyFactory.OLDPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PBE/PKCS12");
+ // put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHAAND3-KEYTRIPLEDES-CBC", "PBE/PKCS12");
+ // put("Alg.Alias.SecretKeyFactory.BROKENPBEWITHSHAAND2-KEYTRIPLEDES-CBC", "PBE/PKCS12");
+ // put("Alg.Alias.SecretKeyFactory.OLDPBEWITHSHAANDTWOFISH-CBC", "PBE/PKCS12");
+ //
+ // put("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDDES-CBC", "PBEWITHMD2ANDDES");
+ // put("Alg.Alias.SecretKeyFactory.PBEWITHMD2ANDRC2-CBC", "PBEWITHMD2ANDRC2");
+ // END android-removed
+ put("Alg.Alias.SecretKeyFactory.PBEWITHMD5ANDDES-CBC", "PBEWITHMD5ANDDES");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHMD5ANDRC2-CBC", "PBEWITHMD5ANDRC2");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDDES-CBC", "PBEWITHSHA1ANDDES");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDRC2-CBC", "PBEWITHSHA1ANDRC2");
+ // BEGIN android-removed
+ // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, "PBEWITHMD2ANDDES");
+ // put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, "PBEWITHMD2ANDRC2");
+ // END android-removed
+ put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, "PBEWITHMD5ANDDES");
+ put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, "PBEWITHMD5ANDRC2");
+ put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, "PBEWITHSHA1ANDDES");
+ put("Alg.Alias.SecretKeyFactory." + PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, "PBEWITHSHA1ANDRC2");
+
+ put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.1", "PBEWITHSHAAND128BITRC4");
+ put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.2", "PBEWITHSHAAND40BITRC4");
+ put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.3", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+ put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.4", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC");
+ put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.5", "PBEWITHSHAAND128BITRC2-CBC");
+ put("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.6", "PBEWITHSHAAND40BITRC2-CBC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHHMACSHA", "PBEWITHHMACSHA1");
+ put("Alg.Alias.SecretKeyFactory.1.3.14.3.2.26", "PBEWITHHMACSHA1");
+ put("Alg.Alias.SecretKeyFactory.PBEWithSHAAnd3KeyTripleDES", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC");
+
+ put("SecretKeyFactory.PBEWITHSHAAND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd128BitAESBC");
+ put("SecretKeyFactory.PBEWITHSHAAND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd192BitAESBC");
+ put("SecretKeyFactory.PBEWITHSHAAND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHAAnd256BitAESBC");
+ put("SecretKeyFactory.PBEWITHSHA256AND128BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA256And128BitAESBC");
+ put("SecretKeyFactory.PBEWITHSHA256AND192BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA256And192BitAESBC");
+ put("SecretKeyFactory.PBEWITHSHA256AND256BITAES-CBC-BC", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA256And256BitAESBC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND128BITAES-CBC-BC","PBEWITHSHAAND128BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND192BITAES-CBC-BC","PBEWITHSHAAND192BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-1AND256BITAES-CBC-BC","PBEWITHSHAAND256BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND128BITAES-CBC-BC","PBEWITHSHA256AND128BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND192BITAES-CBC-BC","PBEWITHSHA256AND192BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory.PBEWITHSHA-256AND256BITAES-CBC-BC","PBEWITHSHA256AND256BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), "PBEWITHSHAAND128BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), "PBEWITHSHAAND192BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), "PBEWITHSHAAND256BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), "PBEWITHSHA256AND128BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), "PBEWITHSHA256AND192BITAES-CBC-BC");
+ put("Alg.Alias.SecretKeyFactory." + BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), "PBEWITHSHA256AND256BITAES-CBC-BC");
+ // BEGIN android-added
+
+ put("SecretKeyFactory.PBKDF2WithHmacSHA1", "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBKDF2WithHmacSHA1");
+ // END android-added
+
+ addMacAlgorithms();
+
+ // Certification Path API
+ // BEGIN android-removed
+ // put("CertPathValidator.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathValidatorSpi");
+ // put("CertPathBuilder.RFC3281", "org.bouncycastle.jce.provider.PKIXAttrCertPathBuilderSpi");
+ // END android-removed
+ // BEGIN android-changed
+ // Use Alg.Alias so RFC3280 doesn't show up when iterating provider services, only PKIX
+ put("Alg.Alias.CertPathValidator.RFC3280", "PKIX");
+ put("Alg.Alias.CertPathBuilder.RFC3280", "PKIX");
+ // END android-changed
+ put("CertPathValidator.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi");
+ put("CertPathBuilder.PKIX", "org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi");
+ put("CertStore.Collection", "org.bouncycastle.jce.provider.CertStoreCollectionSpi");
+ // BEGIN android-removed
+ // put("CertStore.LDAP", "org.bouncycastle.jce.provider.X509LDAPCertStoreSpi");
+ // put("CertStore.Multi", "org.bouncycastle.jce.provider.MultiCertStoreSpi");
+ // put("Alg.Alias.CertStore.X509LDAP", "LDAP");
+ // END android-removed
+ }
+
+ private void loadAlgorithms(String packageName, String[] names)
+ {
+ for (int i = 0; i != names.length; i++)
+ {
+ Class clazz = null;
+ try
+ {
+ ClassLoader loader = this.getClass().getClassLoader();
+
+ if (loader != null)
+ {
+ clazz = loader.loadClass(packageName + names[i] + "$Mappings");
+ }
+ else
+ {
+ clazz = Class.forName(packageName + names[i] + "$Mappings");
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ // ignore
+ }
+
+ if (clazz != null)
+ {
+ try
+ {
+ ((AlgorithmProvider)clazz.newInstance()).configure(this);
+ }
+ catch (Exception e)
+ { // this should never ever happen!!
+e.printStackTrace();
+ throw new InternalError("cannot create instance of "
+ + packageName + names[i] + "$Mappings : " + e);
+ }
+ }
+ }
+ }
+
+ //
+ // macs
+ //
+ private void addMacAlgorithms()
+ {
+
+ // BEGIN android-removed
+ // put("Mac.DESWITHISO9797", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
+ // put("Alg.Alias.Mac.DESISO9797MAC", "DESWITHISO9797");
+ //
+ // put("Mac.ISO9797ALG3MAC", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3");
+ // put("Alg.Alias.Mac.ISO9797ALG3", "ISO9797ALG3MAC");
+ // put("Mac.ISO9797ALG3WITHISO7816-4PADDING", "org.bouncycastle.jce.provider.JCEMac$DES9797Alg3with7816d4");
+ // put("Alg.Alias.Mac.ISO9797ALG3MACWITHISO7816-4PADDING", "ISO9797ALG3WITHISO7816-4PADDING");
+ //
+ // put("Mac.OLDHMACSHA384", "org.bouncycastle.jce.provider.JCEMac$OldSHA384");
+ //
+ // put("Mac.OLDHMACSHA512", "org.bouncycastle.jce.provider.JCEMac$OldSHA512");
+ // END android-removed
+
+ put("Mac.PBEWITHHMACSHA", "org.bouncycastle.jce.provider.JCEMac$PBEWithSHA");
+ put("Mac.PBEWITHHMACSHA1", "org.bouncycastle.jce.provider.JCEMac$PBEWithSHA");
+ // BEGIN android-removed
+ // put("Mac.PBEWITHHMACRIPEMD160", "org.bouncycastle.jce.provider.JCEMac$PBEWithRIPEMD160");
+ // END android-removed
+ put("Alg.Alias.Mac.1.3.14.3.2.26", "PBEWITHHMACSHA");
+ }
+
+
+ public void setParameter(String parameterName, Object parameter)
+ {
+ synchronized (CONFIGURATION)
+ {
+ ((BouncyCastleProviderConfiguration)CONFIGURATION).setParameter(parameterName, parameter);
+ }
+ }
+
+ public boolean hasAlgorithm(String type, String name)
+ {
+ return containsKey(type + "." + name) || containsKey("Alg.Alias." + type + "." + name);
+ }
+
+ public void addAlgorithm(String key, String value)
+ {
+ if (containsKey(key))
+ {
+ throw new IllegalStateException("duplicate provider key (" + key + ") found");
+ }
+
+ put(key, value);
+ }
+
+ public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter)
+ {
+ keyInfoConverters.put(oid, keyInfoConverter);
+ }
+
+ public AsymmetricKeyInfoConverter getConverter(ASN1ObjectIdentifier oid)
+ {
+ return (AsymmetricKeyInfoConverter)keyInfoConverters.get(oid);
+ }
+
+ public static PublicKey getPublicKey(SubjectPublicKeyInfo publicKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(publicKeyInfo.getAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePublic(publicKeyInfo);
+ }
+
+ public static PrivateKey getPrivateKey(PrivateKeyInfo privateKeyInfo)
+ throws IOException
+ {
+ AsymmetricKeyInfoConverter converter = (AsymmetricKeyInfoConverter)keyInfoConverters.get(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm());
+
+ if (converter == null)
+ {
+ return null;
+ }
+
+ return converter.generatePrivate(privateKeyInfo);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java
new file mode 100644
index 0000000..b370ea9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java
@@ -0,0 +1,146 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.Permission;
+
+import javax.crypto.spec.DHParameterSpec;
+
+import org.bouncycastle.jcajce.provider.asymmetric.ec.EC5Util;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
+import org.bouncycastle.jcajce.provider.config.ProviderConfigurationPermission;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+
+class BouncyCastleProviderConfiguration
+ implements ProviderConfiguration
+{
+ private static Permission BC_EC_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA);
+ private static Permission BC_EC_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.EC_IMPLICITLY_CA);
+ private static Permission BC_DH_LOCAL_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS);
+ private static Permission BC_DH_PERMISSION = new ProviderConfigurationPermission(
+ BouncyCastleProvider.PROVIDER_NAME, ConfigurableProvider.DH_DEFAULT_PARAMS);
+
+ private ThreadLocal ecThreadSpec = new ThreadLocal();
+ private ThreadLocal dhThreadSpec = new ThreadLocal();
+
+ private volatile ECParameterSpec ecImplicitCaParams;
+ private volatile DHParameterSpec dhDefaultParams;
+
+ void setParameter(String parameterName, Object parameter)
+ {
+ SecurityManager securityManager = System.getSecurityManager();
+
+ if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA))
+ {
+ ECParameterSpec curveSpec;
+
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_LOCAL_PERMISSION);
+ }
+
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ curveSpec = (ECParameterSpec)parameter;
+ }
+ else // assume java.security.spec
+ {
+ curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+ }
+
+ if (curveSpec == null)
+ {
+ ecThreadSpec.remove();
+ }
+ else
+ {
+ ecThreadSpec.set(curveSpec);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.EC_IMPLICITLY_CA))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_EC_PERMISSION);
+ }
+
+ if (parameter instanceof ECParameterSpec || parameter == null)
+ {
+ ecImplicitCaParams = (ECParameterSpec)parameter;
+ }
+ else // assume java.security.spec
+ {
+ ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS))
+ {
+ DHParameterSpec dhSpec;
+
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_DH_LOCAL_PERMISSION);
+ }
+
+ if (parameter instanceof DHParameterSpec || parameter == null)
+ {
+ dhSpec = (DHParameterSpec)parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec");
+ }
+
+ if (dhSpec == null)
+ {
+ dhThreadSpec.remove();
+ }
+ else
+ {
+ dhThreadSpec.set(dhSpec);
+ }
+ }
+ else if (parameterName.equals(ConfigurableProvider.DH_DEFAULT_PARAMS))
+ {
+ if (securityManager != null)
+ {
+ securityManager.checkPermission(BC_DH_PERMISSION);
+ }
+
+ if (parameter instanceof DHParameterSpec || parameter == null)
+ {
+ dhDefaultParams = (DHParameterSpec)parameter;
+ }
+ else
+ {
+ throw new IllegalArgumentException("not a valid DHParameterSpec");
+ }
+ }
+ }
+
+ public ECParameterSpec getEcImplicitlyCa()
+ {
+ ECParameterSpec spec = (ECParameterSpec)ecThreadSpec.get();
+
+ if (spec != null)
+ {
+ return spec;
+ }
+
+ return ecImplicitCaParams;
+ }
+
+ public DHParameterSpec getDHDefaultParameters()
+ {
+ DHParameterSpec spec = (DHParameterSpec)dhThreadSpec.get();
+
+ if (spec != null)
+ {
+ return spec;
+ }
+
+ return dhDefaultParams;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java
new file mode 100644
index 0000000..fee3ea8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertBlacklist.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2012 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 org.bouncycastle.jce.provider;
+
+import java.io.Closeable;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+import org.bouncycastle.util.encoders.Hex;
+
+public class CertBlacklist {
+
+ private static final String ANDROID_DATA = System.getenv("ANDROID_DATA");
+ private static final String BLACKLIST_ROOT = ANDROID_DATA + "/misc/keychain/";
+ public static final String DEFAULT_PUBKEY_BLACKLIST_PATH = BLACKLIST_ROOT + "pubkey_blacklist.txt";
+ public static final String DEFAULT_SERIAL_BLACKLIST_PATH = BLACKLIST_ROOT + "serial_blacklist.txt";
+
+ private static final Logger logger = Logger.getLogger(CertBlacklist.class.getName());
+
+ // public for testing
+ public final Set<BigInteger> serialBlacklist;
+ public final Set<byte[]> pubkeyBlacklist;
+
+ public CertBlacklist() {
+ this(DEFAULT_PUBKEY_BLACKLIST_PATH, DEFAULT_SERIAL_BLACKLIST_PATH);
+ }
+
+ /** Test only interface, not for public use */
+ public CertBlacklist(String pubkeyBlacklistPath, String serialBlacklistPath) {
+ serialBlacklist = readSerialBlackList(serialBlacklistPath);
+ pubkeyBlacklist = readPublicKeyBlackList(pubkeyBlacklistPath);
+ }
+
+ private static boolean isHex(String value) {
+ try {
+ new BigInteger(value, 16);
+ return true;
+ } catch (NumberFormatException e) {
+ logger.log(Level.WARNING, "Could not parse hex value " + value, e);
+ return false;
+ }
+ }
+
+ private static boolean isPubkeyHash(String value) {
+ if (value.length() != 40) {
+ logger.log(Level.WARNING, "Invalid pubkey hash length: " + value.length());
+ return false;
+ }
+ return isHex(value);
+ }
+
+ private static String readBlacklist(String path) {
+ try {
+ return readFileAsString(path);
+ } catch (FileNotFoundException ignored) {
+ } catch (IOException e) {
+ logger.log(Level.WARNING, "Could not read blacklist", e);
+ }
+ return "";
+ }
+
+ // From IoUtils.readFileAsString
+ private static String readFileAsString(String path) throws IOException {
+ return readFileAsBytes(path).toString("UTF-8");
+ }
+
+ // Based on IoUtils.readFileAsBytes
+ private static ByteArrayOutputStream readFileAsBytes(String path) throws IOException {
+ RandomAccessFile f = null;
+ try {
+ f = new RandomAccessFile(path, "r");
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream((int) f.length());
+ byte[] buffer = new byte[8192];
+ while (true) {
+ int byteCount = f.read(buffer);
+ if (byteCount == -1) {
+ return bytes;
+ }
+ bytes.write(buffer, 0, byteCount);
+ }
+ } finally {
+ closeQuietly(f);
+ }
+ }
+
+ // Base on IoUtils.closeQuietly
+ private static void closeQuietly(Closeable closeable) {
+ if (closeable != null) {
+ try {
+ closeable.close();
+ } catch (RuntimeException rethrown) {
+ throw rethrown;
+ } catch (Exception ignored) {
+ }
+ }
+ }
+
+ private static final Set<BigInteger> readSerialBlackList(String path) {
+
+ // start out with a base set of known bad values
+ Set<BigInteger> bl = new HashSet<BigInteger>(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.
+ new BigInteger("077a59bcd53459601ca6907267a6dd1c", 16),
+ new BigInteger("047ecbe9fca55f7bd09eae36e10cae1e", 16),
+ new BigInteger("d8f35f4eb7872b2dab0692e315382fb0", 16),
+ new BigInteger("b0b7133ed096f9b56fae91c874bd3ac0", 16),
+ new BigInteger("9239d5348f40d1695a745470e1f23f43", 16),
+ new BigInteger("e9028b9578e415dc1a710a2b88154447", 16),
+ new BigInteger("d7558fdaf5f1105bb213282b707729a3", 16),
+ new BigInteger("f5c86af36162f13a64f54f6dc9587c06", 16),
+ new BigInteger("392a434f0e07df1f8aa305de34e0c229", 16),
+ new BigInteger("3e75ced46b693021218830ae86a82a71", 16)
+ ));
+
+ // attempt to augment it with values taken from gservices
+ String serialBlacklist = readBlacklist(path);
+ if (!serialBlacklist.equals("")) {
+ for(String value : serialBlacklist.split(",")) {
+ try {
+ bl.add(new BigInteger(value, 16));
+ } catch (NumberFormatException e) {
+ logger.log(Level.WARNING, "Tried to blacklist invalid serial number " + value, e);
+ }
+ }
+ }
+
+ // whether that succeeds or fails, send it on its merry way
+ return Collections.unmodifiableSet(bl);
+ }
+
+ private static final Set<byte[]> readPublicKeyBlackList(String path) {
+
+ // start out with a base set of known bad values
+ Set<byte[]> bl = new HashSet<byte[]>(Arrays.asList(
+ // From http://src.chromium.org/viewvc/chrome/branches/782/src/net/base/x509_certificate.cc?r1=98750&r2=98749&pathrev=98750
+ // C=NL, O=DigiNotar, CN=DigiNotar Root CA/emailAddress=info@diginotar.nl
+ "410f36363258f30b347d12ce4863e433437806a8".getBytes(),
+ // Subject: CN=DigiNotar Cyber CA
+ // Issuer: CN=GTE CyberTrust Global Root
+ "ba3e7bd38cd7e1e6b9cd4c219962e59d7a2f4e37".getBytes(),
+ // Subject: CN=DigiNotar Services 1024 CA
+ // Issuer: CN=Entrust.net
+ "e23b8d105f87710a68d9248050ebefc627be4ca6".getBytes(),
+ // Subject: CN=DigiNotar PKIoverheid CA Organisatie - G2
+ // Issuer: CN=Staat der Nederlanden Organisatie CA - G2
+ "7b2e16bc39bcd72b456e9f055d1de615b74945db".getBytes(),
+ // Subject: CN=DigiNotar PKIoverheid CA Overheid en Bedrijven
+ // Issuer: CN=Staat der Nederlanden Overheid CA
+ "e8f91200c65cee16e039b9f883841661635f81c5".getBytes(),
+ // From http://src.chromium.org/viewvc/chrome?view=rev&revision=108479
+ // Subject: O=Digicert Sdn. Bhd.
+ // Issuer: CN=GTE CyberTrust Global Root
+ "0129bcd5b448ae8d2496d1c3e19723919088e152".getBytes()
+ ));
+
+ // attempt to augment it with values taken from gservices
+ String pubkeyBlacklist = readBlacklist(path);
+ if (!pubkeyBlacklist.equals("")) {
+ for (String value : pubkeyBlacklist.split(",")) {
+ value = value.trim();
+ if (isPubkeyHash(value)) {
+ bl.add(value.getBytes());
+ } else {
+ logger.log(Level.WARNING, "Tried to blacklist invalid pubkey " + value);
+ }
+ }
+ }
+
+ return bl;
+ }
+
+ public boolean isPublicKeyBlackListed(PublicKey publicKey) {
+ byte[] encoded = publicKey.getEncoded();
+ Digest digest = AndroidDigestFactory.getSHA1();
+ digest.update(encoded, 0, encoded.length);
+ byte[] out = new byte[digest.getDigestSize()];
+ digest.doFinal(out, 0);
+ for (byte[] blacklisted : pubkeyBlacklist) {
+ if (Arrays.equals(blacklisted, Hex.encode(out))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isSerialNumberBlackListed(BigInteger serial) {
+ return serialBlacklist.contains(serial);
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
new file mode 100644
index 0000000..f8f6cb4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java
@@ -0,0 +1,1435 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.cert.CRLException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+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;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CRLSelector;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+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 javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
+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.DERSequence;
+import org.bouncycastle.asn1.isismtt.ISISMTTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+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.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;
+import org.bouncycastle.asn1.x509.X509Extensions;
+// BEGIN android-removed
+// import org.bouncycastle.jce.X509LDAPCertStoreParameters;
+// END android-removed
+import org.bouncycastle.jce.exception.ExtCertPathValidatorException;
+import org.bouncycastle.util.Selector;
+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;
+import org.bouncycastle.x509.X509Store;
+
+public class CertPathValidatorUtilities
+{
+ protected static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+ protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+ protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+ protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+ protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+ protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+ protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+ protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+ protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+ protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+ protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+ protected static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
+ protected static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
+ protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
+
+ protected static final String ANY_POLICY = "2.5.29.32.0";
+
+ protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ /*
+ * key usage bits
+ */
+ protected static final int KEY_CERT_SIGN = 5;
+ protected static final int CRL_SIGN = 6;
+
+ protected static final String[] crlReasons = new String[]{
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"};
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the default provider
+ * for signature verification.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors)
+ throws AnnotatedException
+ {
+ return findTrustAnchor(cert, trustAnchors, null);
+ }
+
+ /**
+ * Search the given Set of TrustAnchor's for one that is the
+ * issuer of the given X509 certificate. Uses the specified
+ * provider for signature verification, or the default provider
+ * if null.
+ *
+ * @param cert the X509 certificate
+ * @param trustAnchors a Set of TrustAnchor's
+ * @param sigProvider the provider to use for signature verification
+ * @return the <code>TrustAnchor</code> object if found or
+ * <code>null</code> if not.
+ * @throws AnnotatedException if a TrustAnchor was found but the signature verification
+ * on the given certificate has thrown an exception.
+ */
+ protected static TrustAnchor findTrustAnchor(
+ X509Certificate cert,
+ Set trustAnchors,
+ String sigProvider)
+ throws AnnotatedException
+ {
+ TrustAnchor trust = null;
+ PublicKey trustPublicKey = null;
+ Exception invalidKeyEx = null;
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+ X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
+
+ try
+ {
+ certSelectX509.setSubject(certIssuer.getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex);
+ }
+
+ Iterator iter = trustAnchors.iterator();
+ while (iter.hasNext() && trust == null)
+ {
+ trust = (TrustAnchor)iter.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ else if (trust.getCAName() != null
+ && trust.getCAPublicKey() != null)
+ {
+ try
+ {
+ X500Principal caName = new X500Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ else
+ {
+ trust = null;
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ trust = null;
+ }
+ }
+ else
+ {
+ trust = null;
+ }
+
+ if (trustPublicKey != null)
+ {
+ try
+ {
+ verifyX509Certificate(cert, trustPublicKey, sigProvider);
+ }
+ catch (Exception ex)
+ {
+ invalidKeyEx = ex;
+ trust = null;
+ trustPublicKey = null;
+ }
+ }
+ }
+
+ if (trust == null && invalidKeyEx != null)
+ {
+ throw new AnnotatedException("TrustAnchor found but certificate validation failed.", invalidKeyEx);
+ }
+
+ return trust;
+ }
+
+ protected static void addAdditionalStoresFromAltNames(
+ X509Certificate cert,
+ ExtendedPKIXParameters pkixParams)
+ throws CertificateParsingException
+ {
+ // if in the IssuerAltName extension an URI
+ // is given, add an additinal X.509 store
+ if (cert.getIssuerAlternativeNames() != null)
+ {
+ Iterator it = cert.getIssuerAlternativeNames().iterator();
+ while (it.hasNext())
+ {
+ // look for URI
+ List list = (List)it.next();
+ // BEGIN android-changed
+ if (list.get(0).equals(Integer.valueOf(GeneralName.uniformResourceIdentifier)))
+ // END android-changed
+ {
+ // found
+ String temp = (String)list.get(1);
+ CertPathValidatorUtilities.addAdditionalStoreFromLocation(temp, pkixParams);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the issuer of an attribute certificate or certificate.
+ *
+ * @param cert The attribute certificate or certificate.
+ * @return The issuer as <code>X500Principal</code>.
+ */
+ protected static X500Principal getEncodedIssuerPrincipal(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+ return ((X509Certificate)cert).getIssuerX500Principal();
+ }
+ else
+ {
+ return (X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0];
+ }
+ }
+
+ protected static Date getValidDate(PKIXParameters paramsPKIX)
+ {
+ Date validDate = paramsPKIX.getDate();
+
+ if (validDate == null)
+ {
+ validDate = new Date();
+ }
+
+ return validDate;
+ }
+
+ protected static X500Principal getSubjectPrincipal(X509Certificate cert)
+ {
+ return cert.getSubjectX500Principal();
+ }
+
+ protected static boolean isSelfIssued(X509Certificate cert)
+ {
+ return cert.getSubjectDN().equals(cert.getIssuerDN());
+ }
+
+
+ /**
+ * Extract the value of the given extension, if it exists.
+ *
+ * @param ext The extension object.
+ * @param oid The object identifier to obtain.
+ * @throws AnnotatedException if the extension cannot be read.
+ */
+ protected static ASN1Primitive getExtensionValue(
+ java.security.cert.X509Extension ext,
+ String oid)
+ throws AnnotatedException
+ {
+ byte[] bytes = ext.getExtensionValue(oid);
+ if (bytes == null)
+ {
+ return null;
+ }
+
+ return getObject(oid, bytes);
+ }
+
+ private static ASN1Primitive getObject(
+ String oid,
+ byte[] ext)
+ throws AnnotatedException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(ext);
+ ASN1OctetString octs = (ASN1OctetString)aIn.readObject();
+
+ aIn = new ASN1InputStream(octs.getOctets());
+ return aIn.readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("exception processing extension " + oid, e);
+ }
+ }
+
+ protected static X500Principal getIssuerPrincipal(X509CRL crl)
+ {
+ return crl.getIssuerX500Principal();
+ }
+
+ protected static AlgorithmIdentifier getAlgorithmIdentifier(
+ PublicKey key)
+ throws CertPathValidatorException
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(key.getEncoded());
+
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(aIn.readObject());
+
+ return info.getAlgorithmId();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Subject public key cannot be decoded.", e);
+ }
+ }
+
+ // crl checking
+
+
+ //
+ // policy checking
+ //
+
+ protected static final Set getQualifierSet(ASN1Sequence qualifiers)
+ throws CertPathValidatorException
+ {
+ Set pq = new HashSet();
+
+ if (qualifiers == null)
+ {
+ return pq;
+ }
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ Enumeration e = qualifiers.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ try
+ {
+ aOut.writeObject((ASN1Encodable)e.nextElement());
+
+ pq.add(new PolicyQualifierInfo(bOut.toByteArray()));
+ }
+ catch (IOException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
+ }
+
+ bOut.reset();
+ }
+
+ return pq;
+ }
+
+ protected static PKIXPolicyNode removePolicyNode(
+ PKIXPolicyNode validPolicyTree,
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent();
+
+ if (validPolicyTree == null)
+ {
+ return null;
+ }
+
+ if (_parent == null)
+ {
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ return null;
+ }
+ else
+ {
+ _parent.removeChild(_node);
+ removePolicyNodeRecurse(policyNodes, _node);
+
+ return validPolicyTree;
+ }
+ }
+
+ private static void removePolicyNodeRecurse(
+ List[] policyNodes,
+ PKIXPolicyNode _node)
+ {
+ policyNodes[_node.getDepth()].remove(_node);
+
+ if (_node.hasChildren())
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_iter.next();
+ removePolicyNodeRecurse(policyNodes, _child);
+ }
+ }
+ }
+
+
+ protected static boolean processCertD1i(
+ int index,
+ List[] policyNodes,
+ DERObjectIdentifier pOid,
+ Set pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)policyNodeVec.get(j);
+ Set expectedPolicies = node.getExpectedPolicies();
+
+ if (expectedPolicies.contains(pOid.getId()))
+ {
+ Set childExpectedPolicies = new HashSet();
+ childExpectedPolicies.add(pOid.getId());
+
+ PKIXPolicyNode child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ childExpectedPolicies,
+ node,
+ pq,
+ pOid.getId(),
+ false);
+ node.addChild(child);
+ policyNodes[index].add(child);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ protected static void processCertD1ii(
+ int index,
+ List[] policyNodes,
+ DERObjectIdentifier _poid,
+ Set _pq)
+ {
+ List policyNodeVec = policyNodes[index - 1];
+
+ for (int j = 0; j < policyNodeVec.size(); j++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Set _childExpectedPolicies = new HashSet();
+ _childExpectedPolicies.add(_poid.getId());
+
+ PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(),
+ index,
+ _childExpectedPolicies,
+ _node,
+ _pq,
+ _poid.getId(),
+ false);
+ _node.addChild(_child);
+ policyNodes[index].add(_child);
+ return;
+ }
+ }
+ }
+
+ protected static void prepareNextCertB1(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ Map m_idp,
+ X509Certificate cert
+ )
+ throws AnnotatedException, CertPathValidatorException
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = null;
+ try
+ {
+ policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Certificate policies cannot be decoded.", e);
+ }
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = null;
+
+ try
+ {
+ pinfo = PolicyInformation.getInstance(e.nextElement());
+ }
+ catch (Exception ex)
+ {
+ throw new AnnotatedException("Policy information cannot be decoded.", ex);
+ }
+ if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ try
+ {
+ pq = getQualifierSet(pinfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Policy qualifier info set could not be built.", ex);
+ }
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(
+ new ArrayList(), i,
+ (Set)m_idp.get(id_p),
+ p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ protected static PKIXPolicyNode prepareNextCertB2(
+ int i,
+ List[] policyNodes,
+ String id_p,
+ PKIXPolicyNode validPolicyTree)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2);
+ if (validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ return validPolicyTree;
+ }
+
+ protected static boolean isAnyPolicy(
+ Set policySet)
+ {
+ 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
+ * are used to search for certificates.
+ * @return a Collection of all found {@link X509Certificate} or
+ * {@link org.bouncycastle.x509.X509AttributeCertificate} objects.
+ * May be empty but never <code>null</code>.
+ */
+ protected static Collection findCertificates(X509CertStoreSelector 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);
+ }
+ }
+ else
+ {
+ CertStore certStore = (CertStore)obj;
+
+ try
+ {
+ certs.addAll(certStore.getCertificates(certSelect));
+ }
+ catch (CertStoreException e)
+ {
+ throw new AnnotatedException(
+ "Problem while picking certificates from certificate store.",
+ e);
+ }
+ }
+ }
+ 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)
+ throws AnnotatedException
+ {
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Distribution points could not be read.", e);
+ }
+ for (int i = 0; i < dps.length; i++)
+ {
+ DistributionPointName dpn = dps[i].getDistributionPoint();
+ // look for URIs in fullName
+ if (dpn != null)
+ {
+ if (dpn.getType() == DistributionPointName.FULL_NAME)
+ {
+ 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)
+ {
+ String location = DERIA5String.getInstance(
+ genNames[j].getName()).getString();
+ CertPathValidatorUtilities
+ .addAdditionalStoreFromLocation(location,
+ pkixParams);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 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
+ * <code>selector</code>.
+ * <p/>
+ * The <code>issuerPrincipals</code> are a collection with a single
+ * <code>X500Principal</code> for <code>X509Certificate</code>s. For
+ * {@link X509AttributeCertificate}s the issuer may contain more than one
+ * <code>X500Principal</code>.
+ *
+ * @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 <code>issuerPrincipals</code> does not
+ * contain only <code>X500Principal</code>s.
+ */
+ protected static void getCRLIssuersFromDistributionPoint(
+ DistributionPoint dp,
+ Collection issuerPrincipals,
+ X509CRLSelector selector,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ List issuers = new ArrayList();
+ // indirect CRL
+ if (dp.getCRLIssuer() != null)
+ {
+ GeneralName genNames[] = dp.getCRLIssuer().getNames();
+ // look for a DN
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ issuers.add(new X500Principal(genNames[j].getName()
+ .toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "CRL issuer information from distribution point cannot be decoded.",
+ e);
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * certificate issuer is CRL issuer, distributionPoint field MUST be
+ * present.
+ */
+ if (dp.getDistributionPoint() == null)
+ {
+ throw new AnnotatedException(
+ "CRL issuer is omitted from distribution point but no distributionPoint field present.");
+ }
+ // add and check issuer principals
+ for (Iterator it = issuerPrincipals.iterator(); it.hasNext(); )
+ {
+ issuers.add((X500Principal)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
+ // distributionPoint
+// if (dp.getDistributionPoint() != null)
+// {
+// // look for nameRelativeToCRLIssuer
+// if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+// {
+// // append fragment to issuer, only one
+// // issuer can be there, if this is given
+// if (issuers.size() != 1)
+// {
+// throw new AnnotatedException(
+// "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
+// }
+// ASN1Encodable relName = dp.getDistributionPoint().getName();
+// Iterator it = issuers.iterator();
+// List issuersTemp = new ArrayList(issuers.size());
+// while (it.hasNext())
+// {
+// Enumeration e = null;
+// try
+// {
+// e = ASN1Sequence.getInstance(
+// new ASN1InputStream(((X500Principal) it.next())
+// .getEncoded()).readObject()).getObjects();
+// }
+// catch (IOException ex)
+// {
+// throw new AnnotatedException(
+// "Cannot decode CRL issuer information.", ex);
+// }
+// ASN1EncodableVector v = new ASN1EncodableVector();
+// while (e.hasMoreElements())
+// {
+// v.add((ASN1Encodable) e.nextElement());
+// }
+// v.add(relName);
+// issuersTemp.add(new X500Principal(new DERSequence(v)
+// .getDEREncoded()));
+// }
+// issuers.clear();
+// issuers.addAll(issuersTemp);
+// }
+// }
+ Iterator it = issuers.iterator();
+ while (it.hasNext())
+ {
+ try
+ {
+ selector.addIssuerName(((X500Principal)it.next()).getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException(
+ "Cannot decode CRL issuer information.", ex);
+ }
+ }
+ }
+
+ private static BigInteger getSerialNumber(
+ Object cert)
+ {
+ if (cert instanceof X509Certificate)
+ {
+ return ((X509Certificate)cert).getSerialNumber();
+ }
+ else
+ {
+ return ((X509AttributeCertificate)cert).getSerialNumber();
+ }
+ }
+
+ protected static void getCertStatus(
+ Date validDate,
+ X509CRL crl,
+ Object cert,
+ CertStatus certStatus)
+ throws AnnotatedException
+ {
+ X509CRLEntry crl_entry = null;
+
+ boolean isIndirect;
+ try
+ {
+ isIndirect = X509CRLObject.isIndirectCRL(crl);
+ }
+ catch (CRLException exception)
+ {
+ throw new AnnotatedException("Failed check for indirect CRL.", exception);
+ }
+
+ if (isIndirect)
+ {
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+
+ X500Principal certIssuer = crl_entry.getCertificateIssuer();
+
+ if (certIssuer == null)
+ {
+ certIssuer = getIssuerPrincipal(crl);
+ }
+
+ if (!getEncodedIssuerPrincipal(cert).equals(certIssuer))
+ {
+ return;
+ }
+ }
+ else if (!getEncodedIssuerPrincipal(cert).equals(getIssuerPrincipal(crl)))
+ {
+ return; // not for our issuer, ignore
+ }
+ else
+ {
+ crl_entry = crl.getRevokedCertificate(getSerialNumber(cert));
+
+ if (crl_entry == null)
+ {
+ return;
+ }
+ }
+
+ DEREnumerated reasonCode = null;
+ if (crl_entry.hasExtensions())
+ {
+ try
+ {
+ reasonCode = DEREnumerated
+ .getInstance(CertPathValidatorUtilities
+ .getExtensionValue(crl_entry,
+ X509Extension.reasonCode.getId()));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Reason code CRL entry extension could not be decoded.",
+ e);
+ }
+ }
+
+ // for reason keyCompromise, caCompromise, aACompromise or
+ // unspecified
+ if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime())
+ || reasonCode == null
+ || reasonCode.getValue().intValue() == 0
+ || reasonCode.getValue().intValue() == 1
+ || reasonCode.getValue().intValue() == 2
+ || reasonCode.getValue().intValue() == 8)
+ {
+
+ // (i) or (j) (1)
+ if (reasonCode != null)
+ {
+ certStatus.setCertStatus(reasonCode.getValue().intValue());
+ }
+ // (i) or (j) (2)
+ else
+ {
+ certStatus.setCertStatus(CRLReason.unspecified);
+ }
+ certStatus.setRevocationDate(crl_entry.getRevocationDate());
+ }
+ }
+
+ /**
+ * 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 completeCRL The complete CRL the delta CRL is for.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the delta
+ * CRLs.
+ */
+ protected static Set getDeltaCRLs(Date currentDate,
+ ExtendedPKIXParameters paramsPKIX, X509CRL completeCRL)
+ throws AnnotatedException
+ {
+
+ X509CRLStoreSelector deltaSelect = new X509CRLStoreSelector();
+
+ // 5.2.4 (a)
+ try
+ {
+ deltaSelect.addIssuerName(CertPathValidatorUtilities
+ .getIssuerPrincipal(completeCRL).getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Cannot extract issuer from CRL.", e);
+ }
+
+ BigInteger completeCRLNumber = null;
+ try
+ {
+ ASN1Primitive derObject = CertPathValidatorUtilities.getExtensionValue(completeCRL,
+ CRL_NUMBER);
+ if (derObject != null)
+ {
+ completeCRLNumber = ASN1Integer.getInstance(derObject).getPositiveValue();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "CRL number extension could not be extracted from CRL.", e);
+ }
+
+ // 5.2.4 (b)
+ byte[] idp = null;
+ try
+ {
+ idp = completeCRL.getExtensionValue(ISSUING_DISTRIBUTION_POINT);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension value could not be read.",
+ e);
+ }
+
+ // 5.2.4 (d)
+
+ deltaSelect.setMinCRLNumber(completeCRLNumber == null ? null : completeCRLNumber
+ .add(BigInteger.valueOf(1)));
+
+ deltaSelect.setIssuingDistributionPoint(idp);
+ deltaSelect.setIssuingDistributionPointEnabled(true);
+
+ // 5.2.4 (c)
+ deltaSelect.setMaxBaseCRLNumber(completeCRLNumber);
+
+ // find delta CRLs
+ Set temp = CRL_UTIL.findCRLs(deltaSelect, paramsPKIX, currentDate);
+
+ Set result = new HashSet();
+
+ for (Iterator it = temp.iterator(); it.hasNext(); )
+ {
+ X509CRL crl = (X509CRL)it.next();
+
+ if (isDeltaCRL(crl))
+ {
+ result.add(crl);
+ }
+ }
+
+ return result;
+ }
+
+ private static boolean isDeltaCRL(X509CRL crl)
+ {
+ Set critical = crl.getCriticalExtensionOIDs();
+
+ if (critical == null)
+ {
+ return false;
+ }
+
+ return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ }
+
+ /**
+ * Fetches complete CRLs according to RFC 3280.
+ *
+ * @param dp The distribution point for which the complete CRL
+ * @param cert The <code>X509Certificate</code> or
+ * {@link org.bouncycastle.x509.X509AttributeCertificate} 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.
+ * @return A <code>Set</code> of <code>X509CRL</code>s with complete
+ * CRLs.
+ * @throws AnnotatedException if an exception occurs while picking the CRLs
+ * or no CRLs are found.
+ */
+ protected static Set getCompleteCRLs(DistributionPoint dp, Object cert,
+ Date currentDate, ExtendedPKIXParameters paramsPKIX)
+ throws AnnotatedException
+ {
+ X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
+ 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);
+ }
+ 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);
+ }
+
+
+ crlselect.setCompleteCRLEnabled(true);
+
+ Set crls = CRL_UTIL.findCRLs(crlselect, paramsPKIX, currentDate);
+
+ 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 \"" + xCert.getIssuerX500Principal() + "\"");
+ }
+ }
+ return crls;
+ }
+
+ protected static Date getValidCertDateFromValidityModel(
+ ExtendedPKIXParameters paramsPKIX, CertPath certPath, int index)
+ throws AnnotatedException
+ {
+ if (paramsPKIX.getValidityModel() == ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ // if end cert use given signing/encryption/... time
+ if (index <= 0)
+ {
+ return CertPathValidatorUtilities.getValidDate(paramsPKIX);
+ // else use time when previous cert was created
+ }
+ else
+ {
+ if (index - 1 == 0)
+ {
+ DERGeneralizedTime 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));
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new AnnotatedException(
+ "Date of cert gen extension could not be read.");
+ }
+ if (dateOfCertgen != null)
+ {
+ try
+ {
+ return dateOfCertgen.getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new AnnotatedException(
+ "Date from date of cert gen extension could not be parsed.",
+ e);
+ }
+ }
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ else
+ {
+ return ((X509Certificate)certPath.getCertificates().get(
+ index - 1)).getNotBefore();
+ }
+ }
+ }
+ else
+ {
+ return getValidDate(paramsPKIX);
+ }
+ }
+
+ /**
+ * Return the next working key inheriting DSA parameters if necessary.
+ * <p>
+ * This methods inherits DSA parameters from the indexed certificate or
+ * previous certificates in the certificate chain to the returned
+ * <code>PublicKey</code>. The list is searched upwards, meaning the end
+ * certificate is at position 0 and previous certificates are following.
+ * </p>
+ * <p>
+ * If the indexed certificate does not contain a DSA key this method simply
+ * returns the public key. If the DSA key already contains DSA parameters
+ * the key is also only returned.
+ * </p>
+ *
+ * @param certs The certification path.
+ * @param index The index of the certificate which contains the public key
+ * which should be extended with DSA parameters.
+ * @return The public key of the certificate in list position
+ * <code>index</code> extended with DSA parameters if applicable.
+ * @throws AnnotatedException if DSA parameters cannot be inherited.
+ */
+ protected static PublicKey getNextWorkingKey(List certs, int index)
+ throws CertPathValidatorException
+ {
+ Certificate cert = (Certificate)certs.get(index);
+ PublicKey pubKey = cert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ return pubKey;
+ }
+ DSAPublicKey dsaPubKey = (DSAPublicKey)pubKey;
+ if (dsaPubKey.getParams() != null)
+ {
+ return dsaPubKey;
+ }
+ for (int i = index + 1; i < certs.size(); i++)
+ {
+ X509Certificate parentCert = (X509Certificate)certs.get(i);
+ pubKey = parentCert.getPublicKey();
+ if (!(pubKey instanceof DSAPublicKey))
+ {
+ throw new CertPathValidatorException(
+ "DSA parameters cannot be inherited from previous certificate.");
+ }
+ DSAPublicKey prevDSAPubKey = (DSAPublicKey)pubKey;
+ if (prevDSAPubKey.getParams() == null)
+ {
+ continue;
+ }
+ DSAParams dsaParams = prevDSAPubKey.getParams();
+ DSAPublicKeySpec dsaPubKeySpec = new DSAPublicKeySpec(
+ dsaPubKey.getY(), dsaParams.getP(), dsaParams.getQ(), dsaParams.getG());
+ try
+ {
+ KeyFactory keyFactory = KeyFactory.getInstance("DSA", BouncyCastleProvider.PROVIDER_NAME);
+ return keyFactory.generatePublic(dsaPubKeySpec);
+ }
+ catch (Exception exception)
+ {
+ throw new RuntimeException(exception.getMessage());
+ }
+ }
+ throw new CertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
+ }
+
+ /**
+ * Find the issuer certificates of a given certificate.
+ *
+ * @param cert The certificate for which an issuer should be found.
+ * @param pkixParams
+ * @return A <code>Collection</code> object containing the issuer
+ * <code>X509Certificate</code>s. Never <code>null</code>.
+ * @throws AnnotatedException if an error occurs.
+ */
+ protected static Collection findIssuerCerts(
+ X509Certificate cert,
+ ExtendedPKIXBuilderParameters pkixParams)
+ throws AnnotatedException
+ {
+ X509CertStoreSelector certSelect = new X509CertStoreSelector();
+ Set certs = new HashSet();
+ try
+ {
+ certSelect.setSubject(cert.getIssuerX500Principal().getEncoded());
+ }
+ catch (IOException ex)
+ {
+ throw new AnnotatedException(
+ "Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
+ }
+
+ 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()));
+
+ iter = matches.iterator();
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Issuer certificate cannot be searched.", e);
+ }
+
+ X509Certificate issuer = null;
+ while (iter.hasNext())
+ {
+ issuer = (X509Certificate)iter.next();
+ // issuer cannot be verified because possible DSA inheritance
+ // parameters are missing
+ certs.add(issuer);
+ }
+ return certs;
+ }
+
+ protected static void verifyX509Certificate(X509Certificate cert, PublicKey publicKey,
+ String sigProvider)
+ throws GeneralSecurityException
+ {
+ if (sigProvider == null)
+ {
+ cert.verify(publicKey);
+ }
+ else
+ {
+ cert.verify(publicKey, sigProvider);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/CertStatus.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertStatus.java
new file mode 100644
index 0000000..ba3da16
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertStatus.java
@@ -0,0 +1,46 @@
+package org.bouncycastle.jce.provider;
+
+import java.util.Date;
+
+class CertStatus
+{
+ public static final int UNREVOKED = 11;
+
+ public static final int UNDETERMINED = 12;
+
+ int certStatus = UNREVOKED;
+
+ Date revocationDate = null;
+
+ /**
+ * @return Returns the revocationDate.
+ */
+ public Date getRevocationDate()
+ {
+ return revocationDate;
+ }
+
+ /**
+ * @param revocationDate The revocationDate to set.
+ */
+ public void setRevocationDate(Date revocationDate)
+ {
+ this.revocationDate = revocationDate;
+ }
+
+ /**
+ * @return Returns the certStatus.
+ */
+ public int getCertStatus()
+ {
+ return certStatus;
+ }
+
+ /**
+ * @param certStatus The certStatus to set.
+ */
+ public void setCertStatus(int certStatus)
+ {
+ this.certStatus = certStatus;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java
new file mode 100644
index 0000000..210d986
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/CertStoreCollectionSpi.java
@@ -0,0 +1,104 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CRL;
+import java.security.cert.CRLSelector;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStoreException;
+import java.security.cert.CertStoreParameters;
+import java.security.cert.CertStoreSpi;
+import java.security.cert.Certificate;
+import java.security.cert.CollectionCertStoreParameters;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+public class CertStoreCollectionSpi extends CertStoreSpi
+{
+ private CollectionCertStoreParameters params;
+
+ public CertStoreCollectionSpi(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ super(params);
+
+ if (!(params instanceof CollectionCertStoreParameters))
+ {
+ throw new InvalidAlgorithmParameterException("org.bouncycastle.jce.provider.CertStoreCollectionSpi: parameter must be a CollectionCertStoreParameters object\n" + params.toString());
+ }
+
+ this.params = (CollectionCertStoreParameters)params;
+ }
+
+ public Collection engineGetCertificates(
+ CertSelector selector)
+ throws CertStoreException
+ {
+ List col = new ArrayList();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof Certificate)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof Certificate) && selector.match((Certificate)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+
+
+ public Collection engineGetCRLs(
+ CRLSelector selector)
+ throws CertStoreException
+ {
+ List col = new ArrayList();
+ Iterator iter = params.getCollection().iterator();
+
+ if (selector == null)
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof CRL)
+ {
+ col.add(obj);
+ }
+ }
+ }
+ else
+ {
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if ((obj instanceof CRL) && selector.match((CRL)obj))
+ {
+ col.add(obj);
+ }
+ }
+ }
+
+ return col;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/DHUtil.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/DHUtil.java
new file mode 100644
index 0000000..2470af9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/DHUtil.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.DHParameters;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+
+/**
+ * utility class for converting jce/jca DH objects
+ * objects into their org.bouncycastle.crypto counterparts.
+ */
+public class DHUtil
+{
+ static public AsymmetricKeyParameter generatePublicKeyParameter(
+ PublicKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPublicKey)
+ {
+ DHPublicKey k = (DHPublicKey)key;
+
+ return new DHPublicKeyParameters(k.getY(),
+ new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+ }
+
+ throw new InvalidKeyException("can't identify DH public key.");
+ }
+
+ static public AsymmetricKeyParameter generatePrivateKeyParameter(
+ PrivateKey key)
+ throws InvalidKeyException
+ {
+ if (key instanceof DHPrivateKey)
+ {
+ DHPrivateKey k = (DHPrivateKey)key;
+
+ return new DHPrivateKeyParameters(k.getX(),
+ new DHParameters(k.getParams().getP(), k.getParams().getG(), null, k.getParams().getL()));
+ }
+
+ throw new InvalidKeyException("can't identify DH private key.");
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/ExtCRLException.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/ExtCRLException.java
new file mode 100644
index 0000000..3bc820f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/ExtCRLException.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.cert.CRLException;
+
+class ExtCRLException
+ extends CRLException
+{
+ Throwable cause;
+
+ ExtCRLException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
new file mode 100644
index 0000000..2205a26
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEBlockCipher.java
@@ -0,0 +1,1103 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+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 org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.engines.AESFastEngine;
+import org.bouncycastle.crypto.engines.DESEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.GOST28147Engine;
+// END android-removed
+import org.bouncycastle.crypto.engines.RC2Engine;
+import org.bouncycastle.crypto.engines.TwofishEngine;
+import org.bouncycastle.crypto.modes.AEADBlockCipher;
+import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.crypto.modes.CCMBlockCipher;
+import org.bouncycastle.crypto.modes.CFBBlockCipher;
+import org.bouncycastle.crypto.modes.CTSBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.EAXBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.GCMBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.GOFBBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.OFBBlockCipher;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
+// import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
+// END android-removed
+import org.bouncycastle.crypto.modes.SICBlockCipher;
+import org.bouncycastle.crypto.paddings.BlockCipherPadding;
+import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.paddings.TBCPadding;
+import org.bouncycastle.crypto.paddings.X923Padding;
+import org.bouncycastle.crypto.paddings.ZeroBytePadding;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.params.ParametersWithSBox;
+// import org.bouncycastle.crypto.params.RC2Parameters;
+// import org.bouncycastle.crypto.params.RC5Parameters;
+// END android-removed
+import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.bouncycastle.jcajce.provider.symmetric.util.PBE;
+// BEGIN android-removed
+// import org.bouncycastle.jce.spec.GOST28147ParameterSpec;
+// END android-removed
+import org.bouncycastle.jce.spec.RepeatedSecretKeySpec;
+import org.bouncycastle.util.Strings;
+
+public class JCEBlockCipher
+ 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,
+ // BEGIN android-removed
+ // GOST28147ParameterSpec.class
+ // END android-removed
+ };
+
+ private BlockCipher baseEngine;
+ private GenericBlockCipher cipher;
+ private ParametersWithIV ivParam;
+
+ private int ivLength = 0;
+
+ private boolean padded;
+
+ private PBEParameterSpec pbeSpec = null;
+ private String pbeAlgorithm = null;
+
+ private String modeName = null;
+
+ private AlgorithmParameters engineParams;
+
+ protected JCEBlockCipher(
+ BlockCipher engine)
+ {
+ baseEngine = engine;
+
+ cipher = new BufferedGenericBlockCipher(engine);
+ }
+
+ protected JCEBlockCipher(
+ BlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine;
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected JCEBlockCipher(
+ BufferedBlockCipher engine,
+ int ivLength)
+ {
+ baseEngine = engine.getUnderlyingCipher();
+
+ this.cipher = new BufferedGenericBlockCipher(engine);
+ this.ivLength = ivLength / 8;
+ }
+
+ protected int engineGetBlockSize()
+ {
+ return baseEngine.getBlockSize();
+ }
+
+ 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 cipher.getOutputSize(inputLen);
+ }
+
+ protected AlgorithmParameters engineGetParameters()
+ {
+ if (engineParams == null)
+ {
+ if (pbeSpec != null)
+ {
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(pbeAlgorithm, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(pbeSpec);
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ else if (ivParam != null)
+ {
+ String name = cipher.getUnderlyingCipher().getAlgorithmName();
+
+ if (name.indexOf('/') >= 0)
+ {
+ name = name.substring(0, name.indexOf('/'));
+ }
+
+ try
+ {
+ engineParams = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME);
+ engineParams.init(ivParam.getIV());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+ }
+
+ return engineParams;
+ }
+
+ protected void engineSetMode(
+ String mode)
+ throws NoSuchAlgorithmException
+ {
+ modeName = Strings.toUpperCase(mode);
+
+ if (modeName.equals("ECB"))
+ {
+ ivLength = 0;
+ cipher = new BufferedGenericBlockCipher(baseEngine);
+ }
+ else if (modeName.equals("CBC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(
+ new CBCBlockCipher(baseEngine));
+ }
+ else if (modeName.startsWith("OFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new OFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ else if (modeName.startsWith("CFB"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (modeName.length() != 3)
+ {
+ int wordSize = Integer.parseInt(modeName.substring(3));
+
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, wordSize));
+ }
+ else
+ {
+ cipher = new BufferedGenericBlockCipher(
+ new CFBBlockCipher(baseEngine, 8 * baseEngine.getBlockSize()));
+ }
+ }
+ // BEGIN android-removed
+ // else if (modeName.startsWith("PGP"))
+ // {
+ // boolean inlineIV = modeName.equalsIgnoreCase("PGPCFBwithIV");
+ //
+ // ivLength = baseEngine.getBlockSize();
+ // cipher = new BufferedGenericBlockCipher(
+ // new PGPCFBBlockCipher(baseEngine, inlineIV));
+ // }
+ // else if (modeName.equalsIgnoreCase("OpenPGPCFB"))
+ // {
+ // ivLength = 0;
+ // cipher = new BufferedGenericBlockCipher(
+ // new OpenPGPCFBBlockCipher(baseEngine));
+ // }
+ // END android-removed
+ else if (modeName.startsWith("SIC"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ if (ivLength < 16)
+ {
+ 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)");
+ }
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CTR"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ new SICBlockCipher(baseEngine)));
+ }
+ // BEGIN android-removed
+ // else if (modeName.startsWith("GOFB"))
+ // {
+ // ivLength = baseEngine.getBlockSize();
+ // cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(
+ // new GOFBBlockCipher(baseEngine)));
+ // }
+ // END android-removed
+ else if (modeName.startsWith("CTS"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(new CBCBlockCipher(baseEngine)));
+ }
+ else if (modeName.startsWith("CCM"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new CCMBlockCipher(baseEngine));
+ }
+ // BEGIN android-removed
+ // else if (modeName.startsWith("EAX"))
+ // {
+ // ivLength = baseEngine.getBlockSize();
+ // cipher = new AEADGenericBlockCipher(new EAXBlockCipher(baseEngine));
+ // }
+ // END android-removed
+ else if (modeName.startsWith("GCM"))
+ {
+ ivLength = baseEngine.getBlockSize();
+ cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine));
+ }
+ else
+ {
+ throw new NoSuchAlgorithmException("can't support mode " + mode);
+ }
+ }
+
+ protected void engineSetPadding(
+ String padding)
+ throws NoSuchPaddingException
+ {
+ String paddingName = Strings.toUpperCase(padding);
+
+ if (paddingName.equals("NOPADDING"))
+ {
+ if (cipher.wrapOnNoPadding())
+ {
+ cipher = new BufferedGenericBlockCipher(new BufferedBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ }
+ else if (paddingName.equals("WITHCTS"))
+ {
+ cipher = new BufferedGenericBlockCipher(new CTSBlockCipher(cipher.getUnderlyingCipher()));
+ }
+ else
+ {
+ padded = true;
+
+ if (isAEADModeName(modeName))
+ {
+ throw new NoSuchPaddingException("Only NoPadding can be used with AEAD modes.");
+ }
+ else if (paddingName.equals("PKCS5PADDING") || paddingName.equals("PKCS7PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher());
+ }
+ else if (paddingName.equals("ZEROBYTEPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ZeroBytePadding());
+ }
+ else if (paddingName.equals("ISO10126PADDING") || paddingName.equals("ISO10126-2PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO10126d2Padding());
+ }
+ else if (paddingName.equals("X9.23PADDING") || paddingName.equals("X923PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new X923Padding());
+ }
+ else if (paddingName.equals("ISO7816-4PADDING") || paddingName.equals("ISO9797-1PADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new ISO7816d4Padding());
+ }
+ else if (paddingName.equals("TBCPADDING"))
+ {
+ cipher = new BufferedGenericBlockCipher(cipher.getUnderlyingCipher(), new TBCPadding());
+ }
+ else
+ {
+ 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.");
+ }
+
+ // BEGIN android-removed
+ // //
+ // // for RC5-64 we must have some default parameters
+ // //
+ // if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64"))
+ // {
+ // throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in.");
+ // }
+ // END android-removed
+
+ //
+ // a note on iv's - if ivLength is zero the IV gets ignored (we don't use it).
+ //
+ 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)
+ {
+ pbeSpec = (PBEParameterSpec)params;
+ param = PBE.Util.makePBEParameters(k, params, cipher.getUnderlyingCipher().getAlgorithmName());
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+
+ if (param instanceof ParametersWithIV)
+ {
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ if (ivLength != 0)
+ {
+ IvParameterSpec p = (IvParameterSpec)params;
+
+ if (p.getIV().length != ivLength && !isAEADModeName(modeName))
+ {
+ throw new InvalidAlgorithmParameterException("IV must be " + ivLength + " bytes long.");
+ }
+
+ if (key instanceof RepeatedSecretKeySpec)
+ {
+ param = new ParametersWithIV(null, p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ else
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), p.getIV());
+ ivParam = (ParametersWithIV)param;
+ }
+ }
+ else
+ {
+ if (modeName != null && modeName.equals("ECB"))
+ {
+ throw new InvalidAlgorithmParameterException("ECB mode does not use an IV");
+ }
+
+ param = new KeyParameter(key.getEncoded());
+ }
+ }
+ // BEGIN android-removed
+ // else if (params instanceof GOST28147ParameterSpec)
+ // {
+ // GOST28147ParameterSpec gost28147Param = (GOST28147ParameterSpec)params;
+ //
+ // param = new ParametersWithSBox(
+ // new KeyParameter(key.getEncoded()), ((GOST28147ParameterSpec)params).getSbox());
+ //
+ // if (gost28147Param.getIV() != null && ivLength != 0)
+ // {
+ // param = new ParametersWithIV(param, gost28147Param.getIV());
+ // ivParam = (ParametersWithIV)param;
+ // }
+ // }
+ // else if (params instanceof RC2ParameterSpec)
+ // {
+ // RC2ParameterSpec rc2Param = (RC2ParameterSpec)params;
+ //
+ // param = new RC2Parameters(key.getEncoded(), ((RC2ParameterSpec)params).getEffectiveKeyBits());
+ //
+ // if (rc2Param.getIV() != null && ivLength != 0)
+ // {
+ // param = new ParametersWithIV(param, rc2Param.getIV());
+ // ivParam = (ParametersWithIV)param;
+ // }
+ // }
+ // else if (params instanceof RC5ParameterSpec)
+ // {
+ // RC5ParameterSpec rc5Param = (RC5ParameterSpec)params;
+ //
+ // param = new RC5Parameters(key.getEncoded(), ((RC5ParameterSpec)params).getRounds());
+ // if (baseEngine.getAlgorithmName().startsWith("RC5"))
+ // {
+ // if (baseEngine.getAlgorithmName().equals("RC5-32"))
+ // {
+ // if (rc5Param.getWordSize() != 32)
+ // {
+ // throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 32 not " + rc5Param.getWordSize() + ".");
+ // }
+ // }
+ // else if (baseEngine.getAlgorithmName().equals("RC5-64"))
+ // {
+ // if (rc5Param.getWordSize() != 64)
+ // {
+ // throw new InvalidAlgorithmParameterException("RC5 already set up for a word size of 64 not " + rc5Param.getWordSize() + ".");
+ // }
+ // }
+ // }
+ // else
+ // {
+ // throw new InvalidAlgorithmParameterException("RC5 parameters passed to a cipher that is not RC5.");
+ // }
+ // if ((rc5Param.getIV() != null) && (ivLength != 0))
+ // {
+ // param = new ParametersWithIV(param, rc5Param.getIV());
+ // ivParam = (ParametersWithIV)param;
+ // }
+ // }
+ // END android-removed
+ else
+ {
+ throw new InvalidAlgorithmParameterException("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 if (cipher.getUnderlyingCipher().getAlgorithmName().indexOf("PGPCFB") < 0)
+ {
+ throw new InvalidAlgorithmParameterException("no IV set when one expected");
+ }
+ }
+
+ if (random != null && padded)
+ {
+ param = new ParametersWithRandom(param, random);
+ }
+
+ try
+ {
+ switch (opmode)
+ {
+ case Cipher.ENCRYPT_MODE:
+ case Cipher.WRAP_MODE:
+ cipher.init(true, param);
+ break;
+ case Cipher.DECRYPT_MODE:
+ case Cipher.UNWRAP_MODE:
+ cipher.init(false, param);
+ break;
+ default:
+ throw new InvalidParameterException("unknown opmode " + opmode + " passed");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException(e.getMessage());
+ }
+ }
+
+ 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)
+ {
+ // try again if possible
+ }
+ }
+
+ 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)
+ {
+ int length = cipher.getUpdateOutputSize(inputLen);
+
+ if (length > 0)
+ {
+ byte[] out = new byte[length];
+
+ int len = cipher.processBytes(input, inputOffset, inputLen, out, 0);
+
+ if (len == 0)
+ {
+ return null;
+ }
+ else if (len != out.length)
+ {
+ byte[] tmp = new byte[len];
+
+ System.arraycopy(out, 0, tmp, 0, len);
+
+ return tmp;
+ }
+
+ return out;
+ }
+
+ cipher.processBytes(input, inputOffset, inputLen, null, 0);
+
+ return null;
+ }
+
+ protected int engineUpdate(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws ShortBufferException
+ {
+ try
+ {
+ return cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+ catch (DataLengthException e)
+ {
+ throw new ShortBufferException(e.getMessage());
+ }
+ }
+
+ protected byte[] engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen)
+ throws IllegalBlockSizeException, BadPaddingException
+ {
+ int len = 0;
+ byte[] tmp = new byte[engineGetOutputSize(inputLen)];
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, tmp, 0);
+ }
+
+ try
+ {
+ len += cipher.doFinal(tmp, len);
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+
+ if (len == tmp.length)
+ {
+ return tmp;
+ }
+
+ byte[] out = new byte[len];
+
+ System.arraycopy(tmp, 0, out, 0, len);
+
+ return out;
+ }
+
+ protected int engineDoFinal(
+ byte[] input,
+ int inputOffset,
+ int inputLen,
+ byte[] output,
+ int outputOffset)
+ throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
+ {
+ // BEGIN android-note
+ // added ShortBufferException to the throws statement
+ // END android-note
+ int len = 0;
+
+ // BEGIN android-added
+ int outputLen = cipher.getOutputSize(inputLen);
+
+ if (outputLen + outputOffset > output.length) {
+ throw new ShortBufferException("need at least " + outputLen + " bytes");
+ }
+ // BEGIN android-added
+
+ if (inputLen != 0)
+ {
+ len = cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ try
+ {
+ return (len + cipher.doFinal(output, outputOffset + len));
+ }
+ catch (DataLengthException e)
+ {
+ throw new IllegalBlockSizeException(e.getMessage());
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new BadPaddingException(e.getMessage());
+ }
+ }
+
+ private boolean isAEADModeName(
+ String modeName)
+ {
+ return "CCM".equals(modeName) || "EAX".equals(modeName) || "GCM".equals(modeName);
+ }
+
+ /*
+ * The ciphers that inherit from us.
+ */
+
+ /**
+ * DES
+ */
+ static public class DES
+ extends JCEBlockCipher
+ {
+ public DES()
+ {
+ super(new DESEngine());
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * DESCBC
+ // */
+ // static public class DESCBC
+ // extends JCEBlockCipher
+ // {
+ // public DESCBC()
+ // {
+ // super(new CBCBlockCipher(new DESEngine()), 64);
+ // }
+ // }
+ //
+ // /**
+ // * GOST28147
+ // */
+ // static public class GOST28147
+ // extends JCEBlockCipher
+ // {
+ // public GOST28147()
+ // {
+ // super(new GOST28147Engine());
+ // }
+ // }
+ //
+ // static public class GOST28147cbc
+ // extends JCEBlockCipher
+ // {
+ // public GOST28147cbc()
+ // {
+ // super(new CBCBlockCipher(new GOST28147Engine()), 64);
+ // }
+ // }
+ //
+ // /**
+ // * RC2
+ // */
+ // static public class RC2
+ // extends JCEBlockCipher
+ // {
+ // public RC2()
+ // {
+ // super(new RC2Engine());
+ // }
+ // }
+ //
+ // /**
+ // * RC2CBC
+ // */
+ // static public class RC2CBC
+ // extends JCEBlockCipher
+ // {
+ // public RC2CBC()
+ // {
+ // super(new CBCBlockCipher(new RC2Engine()), 64);
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * PBEWithMD5AndDES
+ */
+ static public class PBEWithMD5AndDES
+ extends JCEBlockCipher
+ {
+ public PBEWithMD5AndDES()
+ {
+ super(new CBCBlockCipher(new DESEngine()));
+ }
+ }
+
+ /**
+ * PBEWithMD5AndRC2
+ */
+ static public class PBEWithMD5AndRC2
+ extends JCEBlockCipher
+ {
+ public PBEWithMD5AndRC2()
+ {
+ super(new CBCBlockCipher(new RC2Engine()));
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndDES
+ */
+ static public class PBEWithSHA1AndDES
+ extends JCEBlockCipher
+ {
+ public PBEWithSHA1AndDES()
+ {
+ super(new CBCBlockCipher(new DESEngine()));
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndRC2
+ */
+ static public class PBEWithSHA1AndRC2
+ extends JCEBlockCipher
+ {
+ public PBEWithSHA1AndRC2()
+ {
+ super(new CBCBlockCipher(new RC2Engine()));
+ }
+ }
+
+
+
+ /**
+ * PBEWithSHAAnd128BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd128BitRC2
+ extends JCEBlockCipher
+ {
+ public PBEWithSHAAnd128BitRC2()
+ {
+ super(new CBCBlockCipher(new RC2Engine()));
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd40BitRC2
+ extends JCEBlockCipher
+ {
+ public PBEWithSHAAnd40BitRC2()
+ {
+ super(new CBCBlockCipher(new RC2Engine()));
+ }
+ }
+
+ /**
+ * PBEWithSHAAndTwofish-CBC
+ */
+ static public class PBEWithSHAAndTwofish
+ extends JCEBlockCipher
+ {
+ public PBEWithSHAAndTwofish()
+ {
+ super(new CBCBlockCipher(new TwofishEngine()));
+ }
+ }
+
+ /**
+ * PBEWithAES-CBC
+ */
+ static public class PBEWithAESCBC
+ extends JCEBlockCipher
+ {
+ public PBEWithAESCBC()
+ {
+ super(new CBCBlockCipher(new AESFastEngine()));
+ }
+ }
+
+ static private interface GenericBlockCipher
+ {
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException;
+
+ public boolean wrapOnNoPadding();
+
+ public String getAlgorithmName();
+
+ public BlockCipher getUnderlyingCipher();
+
+ public int getOutputSize(int len);
+
+ public int getUpdateOutputSize(int len);
+
+ public int processByte(byte in, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff)
+ throws DataLengthException;
+
+ public int doFinal(byte[] out, int outOff)
+ throws IllegalStateException, InvalidCipherTextException;
+ }
+
+ private static class BufferedGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private BufferedBlockCipher cipher;
+
+ BufferedGenericBlockCipher(BufferedBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ BufferedGenericBlockCipher(BlockCipher cipher)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher);
+ }
+
+ BufferedGenericBlockCipher(BlockCipher cipher, BlockCipherPadding padding)
+ {
+ this.cipher = new PaddedBufferedBlockCipher(cipher, padding);
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return !(cipher instanceof CTSBlockCipher);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+
+ private static class AEADGenericBlockCipher
+ implements GenericBlockCipher
+ {
+ private AEADBlockCipher cipher;
+
+ AEADGenericBlockCipher(AEADBlockCipher cipher)
+ {
+ this.cipher = cipher;
+ }
+
+ public void init(boolean forEncryption, CipherParameters params)
+ throws IllegalArgumentException
+ {
+ cipher.init(forEncryption, params);
+ }
+
+ public String getAlgorithmName()
+ {
+ return cipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ public boolean wrapOnNoPadding()
+ {
+ return false;
+ }
+
+ public BlockCipher getUnderlyingCipher()
+ {
+ return cipher.getUnderlyingCipher();
+ }
+
+ public int getOutputSize(int len)
+ {
+ return cipher.getOutputSize(len);
+ }
+
+ public int getUpdateOutputSize(int len)
+ {
+ return cipher.getUpdateOutputSize(len);
+ }
+
+ public int processByte(byte in, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processByte(in, out, outOff);
+ }
+
+ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException
+ {
+ return cipher.processBytes(in, inOff, len, out, outOff);
+ }
+
+ public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException
+ {
+ return cipher.doFinal(out, outOff);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
new file mode 100644
index 0000000..46295c5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPrivateKey.java
@@ -0,0 +1,188 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+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;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.DHDomainParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DHPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class JCEDHPrivateKey
+ implements DHPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 311058815616901812L;
+
+ BigInteger x;
+
+ private DHParameterSpec dhSpec;
+ private PrivateKeyInfo info;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected JCEDHPrivateKey()
+ {
+ }
+
+ JCEDHPrivateKey(
+ DHPrivateKey key)
+ {
+ this.x = key.getX();
+ this.dhSpec = key.getParams();
+ }
+
+ JCEDHPrivateKey(
+ DHPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+ }
+
+ JCEDHPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters());
+ DERInteger derX = DERInteger.getInstance(info.parsePrivateKey());
+ DERObjectIdentifier id = info.getAlgorithmId().getAlgorithm();
+
+ this.info = info;
+ this.x = derX.getValue();
+
+ if (id.equals(PKCSObjectIdentifiers.dhKeyAgreement))
+ {
+ DHParameter params = DHParameter.getInstance(seq);
+
+ if (params.getL() != null)
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+ }
+ else
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+ }
+ }
+ else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+ this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm type: " + id);
+ }
+ }
+
+ JCEDHPrivateKey(
+ DHPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DH";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ if (info != null)
+ {
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+
+ PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new DERInteger(getX()));
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return dhSpec;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ x = (BigInteger)in.readObject();
+
+ this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getX());
+ out.writeObject(dhSpec.getP());
+ out.writeObject(dhSpec.getG());
+ out.writeInt(dhSpec.getL());
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
new file mode 100644
index 0000000..6ff1e08
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEDHPublicKey.java
@@ -0,0 +1,178 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+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;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.DHDomainParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DHPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+public class JCEDHPublicKey
+ implements DHPublicKey
+{
+ static final long serialVersionUID = -216691575254424324L;
+
+ private BigInteger y;
+ private DHParameterSpec dhSpec;
+ private SubjectPublicKeyInfo info;
+
+ JCEDHPublicKey(
+ DHPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.dhSpec = new DHParameterSpec(spec.getP(), spec.getG());
+ }
+
+ JCEDHPublicKey(
+ DHPublicKey key)
+ {
+ this.y = key.getY();
+ this.dhSpec = key.getParams();
+ }
+
+ JCEDHPublicKey(
+ DHPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.dhSpec = new DHParameterSpec(params.getParameters().getP(), params.getParameters().getG(), params.getParameters().getL());
+ }
+
+ JCEDHPublicKey(
+ BigInteger y,
+ DHParameterSpec dhSpec)
+ {
+ this.y = y;
+ this.dhSpec = dhSpec;
+ }
+
+ JCEDHPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ this.info = info;
+
+ DERInteger derY;
+ try
+ {
+ derY = (DERInteger)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DH public key");
+ }
+
+ this.y = derY.getValue();
+
+ ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters());
+ DERObjectIdentifier 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))
+ {
+ DHParameter params = DHParameter.getInstance(seq);
+
+ if (params.getL() != null)
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG(), params.getL().intValue());
+ }
+ else
+ {
+ this.dhSpec = new DHParameterSpec(params.getP(), params.getG());
+ }
+ }
+ else if (id.equals(X9ObjectIdentifiers.dhpublicnumber))
+ {
+ DHDomainParameters params = DHDomainParameters.getInstance(seq);
+
+ this.dhSpec = new DHParameterSpec(params.getP().getValue(), params.getG().getValue());
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown algorithm type: " + id);
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return "DH";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ if (info != null)
+ {
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL())), new DERInteger(y));
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return dhSpec;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ private boolean isPKCSParam(ASN1Sequence seq)
+ {
+ if (seq.size() == 2)
+ {
+ return true;
+ }
+
+ if (seq.size() > 3)
+ {
+ return false;
+ }
+
+ DERInteger l = DERInteger.getInstance(seq.getObjectAt(2));
+ DERInteger p = DERInteger.getInstance(seq.getObjectAt(0));
+
+ if (l.getValue().compareTo(BigInteger.valueOf(p.getValue().bitLength())) > 0)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ this.y = (BigInteger)in.readObject();
+ this.dhSpec = new DHParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), in.readInt());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getY());
+ out.writeObject(dhSpec.getP());
+ out.writeObject(dhSpec.getG());
+ out.writeInt(dhSpec.getL());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
new file mode 100644
index 0000000..1ff5b80
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java
@@ -0,0 +1,484 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.EllipticCurve;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+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;
+// END android-removed
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.sec.ECPrivateKeyStructure;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.EC5Util;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.ECUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.ECPointEncoder;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class JCEECPrivateKey
+ implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder
+{
+ private String algorithm = "EC";
+ private BigInteger d;
+ private ECParameterSpec ecSpec;
+ private boolean withCompression;
+
+ private DERBitString publicKey;
+
+ private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected JCEECPrivateKey()
+ {
+ }
+
+ public JCEECPrivateKey(
+ ECPrivateKey key)
+ {
+ this.d = key.getS();
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ org.bouncycastle.jce.spec.ECPrivateKeySpec spec)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getD();
+
+ if (spec.getParams() != null) // can be null if implicitlyCA
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve;
+
+ ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ this.ecSpec = null;
+ }
+ }
+
+
+ public JCEECPrivateKey(
+ String algorithm,
+ ECPrivateKeySpec spec)
+ {
+ this.algorithm = algorithm;
+ this.d = spec.getS();
+ this.ecSpec = spec.getParams();
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ JCEECPrivateKey key)
+ {
+ this.algorithm = algorithm;
+ this.d = key.d;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ this.attrCarrier = key.attrCarrier;
+ this.publicKey = key.publicKey;
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ JCEECPublicKey pubKey,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getX().toBigInteger(),
+ dp.getG().getY().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params,
+ JCEECPublicKey pubKey,
+ org.bouncycastle.jce.spec.ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.d = params.getD();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getX().toBigInteger(),
+ dp.getG().getY().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ spec.getG().getX().toBigInteger(),
+ spec.getG().getY().toBigInteger()),
+ spec.getN(),
+ spec.getH().intValue());
+ }
+
+ publicKey = getPublicKeyDetails(pubKey);
+ }
+
+ public JCEECPrivateKey(
+ String algorithm,
+ ECPrivateKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.d = params.getD();
+ this.ecSpec = null;
+ }
+
+ JCEECPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ populateFromPrivKeyInfo(info);
+ }
+
+ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
+ throws IOException
+ {
+ X962Parameters params = new X962Parameters((ASN1Primitive)info.getPrivateKeyAlgorithm().getParameters());
+
+ if (params.isNamedCurve())
+ {
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters());
+ X9ECParameters ecP = ECUtil.getNamedCurveByOid(oid);
+
+ // BEGIN android-removed
+ // if (ecP == null) // GOST Curve
+ // {
+ // ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid);
+ // EllipticCurve ellipticCurve = EC5Util.convertCurve(gParam.getCurve(), gParam.getSeed());
+ //
+ // ecSpec = new ECNamedCurveSpec(
+ // ECGOST3410NamedCurves.getName(oid),
+ // ellipticCurve,
+ // new ECPoint(
+ // gParam.getG().getX().toBigInteger(),
+ // gParam.getG().getY().toBigInteger()),
+ // gParam.getN(),
+ // gParam.getH());
+ // }
+ // else
+ // END android-removed
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed());
+
+ ecSpec = new ECNamedCurveSpec(
+ ECUtil.getCurveName(oid),
+ ellipticCurve,
+ new ECPoint(
+ ecP.getG().getX().toBigInteger(),
+ ecP.getG().getY().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().getX().toBigInteger(),
+ ecP.getG().getY().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ ASN1Encodable privKey = info.parsePrivateKey();
+ if (privKey instanceof DERInteger)
+ {
+ DERInteger derD = DERInteger.getInstance(privKey);
+
+ this.d = derD.getValue();
+ }
+ else
+ {
+ ECPrivateKeyStructure ec = new ECPrivateKeyStructure((ASN1Sequence)privKey);
+
+ this.d = ec.getKey();
+ this.publicKey = ec.getPublicKey();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ X962Parameters params;
+
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ DERObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null) // guess it's the OID
+ {
+ curveOid = new DERObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ PrivateKeyInfo info;
+ ECPrivateKeyStructure keyStructure;
+
+ if (publicKey != null)
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getS(), publicKey, params);
+ }
+ else
+ {
+ keyStructure = new ECPrivateKeyStructure(this.getS(), params);
+ }
+
+ try
+ {
+ // BEGIN android-removed
+ // if (algorithm.equals("ECGOST3410"))
+ // {
+ // info = new PrivateKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+ // }
+ // else
+ // END android-removed
+ {
+
+ info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params.toASN1Primitive()), keyStructure.toASN1Primitive());
+ }
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null)
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public BigInteger getS()
+ {
+ return d;
+ }
+
+ public BigInteger getD()
+ {
+ return d;
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof JCEECPrivateKey))
+ {
+ return false;
+ }
+
+ JCEECPrivateKey other = (JCEECPrivateKey)o;
+
+ return getD().equals(other.getD()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return getD().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Private Key").append(nl);
+ buf.append(" S: ").append(this.d.toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ private DERBitString getPublicKeyDetails(JCEECPublicKey pub)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pub.getEncoded()));
+
+ return info.getPublicKeyData();
+ }
+ catch (IOException e)
+ { // should never happen
+ return null;
+ }
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPrivKeyInfo(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.algorithm = (String)in.readObject();
+ this.withCompression = in.readBoolean();
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ attrCarrier.readObject(in);
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getEncoded());
+ out.writeObject(algorithm);
+ out.writeBoolean(withCompression);
+
+ attrCarrier.writeObject(out);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
new file mode 100644
index 0000000..15a2996
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java
@@ -0,0 +1,532 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.EllipticCurve;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
+// import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
+// import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
+// END android-removed
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECPoint;
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.ECDomainParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.EC5Util;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.ECUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+// BEGIN android-removed
+// import org.bouncycastle.jce.ECGOST3410NamedCurveTable;
+// END android-removed
+import org.bouncycastle.jce.interfaces.ECPointEncoder;
+// BEGIN android-removed
+// import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
+// END android-removed
+import org.bouncycastle.jce.spec.ECNamedCurveSpec;
+import org.bouncycastle.math.ec.ECCurve;
+
+public class JCEECPublicKey
+ implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder
+{
+ private String algorithm = "EC";
+ private org.bouncycastle.math.ec.ECPoint q;
+ private ECParameterSpec ecSpec;
+ private boolean withCompression;
+ // BEGIN android-removed
+ // private GOST3410PublicKeyAlgParameters gostParams;
+ // END android-removed
+
+ public JCEECPublicKey(
+ String algorithm,
+ JCEECPublicKey key)
+ {
+ this.algorithm = algorithm;
+ this.q = key.q;
+ this.ecSpec = key.ecSpec;
+ this.withCompression = key.withCompression;
+ // BEGIN android-removed
+ // this.gostParams = key.gostParams;
+ // END android-removed
+ }
+
+ public JCEECPublicKey(
+ String algorithm,
+ ECPublicKeySpec spec)
+ {
+ this.algorithm = algorithm;
+ this.ecSpec = spec.getParams();
+ this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false);
+ }
+
+ public JCEECPublicKey(
+ String algorithm,
+ org.bouncycastle.jce.spec.ECPublicKeySpec spec)
+ {
+ this.algorithm = algorithm;
+ this.q = spec.getQ();
+
+ if (spec.getParams() != null) // can be null if implictlyCa
+ {
+ ECCurve curve = spec.getParams().getCurve();
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getParams().getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec.getParams());
+ }
+ else
+ {
+ if (q.getCurve() == null)
+ {
+ org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+
+ q = s.getCurve().createPoint(q.getX().toBigInteger(), q.getY().toBigInteger(), false);
+ }
+ this.ecSpec = null;
+ }
+ }
+
+ public JCEECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ this.ecSpec = spec;
+ }
+ }
+
+ public JCEECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params,
+ org.bouncycastle.jce.spec.ECParameterSpec spec)
+ {
+ ECDomainParameters dp = params.getParameters();
+
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+
+ if (spec == null)
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed());
+
+ this.ecSpec = createSpec(ellipticCurve, dp);
+ }
+ else
+ {
+ EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed());
+
+ this.ecSpec = EC5Util.convertSpec(ellipticCurve, spec);
+ }
+ }
+
+ /*
+ * called for implicitCA
+ */
+ public JCEECPublicKey(
+ String algorithm,
+ ECPublicKeyParameters params)
+ {
+ this.algorithm = algorithm;
+ this.q = params.getQ();
+ this.ecSpec = null;
+ }
+
+ private ECParameterSpec createSpec(EllipticCurve ellipticCurve, ECDomainParameters dp)
+ {
+ return new ECParameterSpec(
+ ellipticCurve,
+ new ECPoint(
+ dp.getG().getX().toBigInteger(),
+ dp.getG().getY().toBigInteger()),
+ dp.getN(),
+ dp.getH().intValue());
+ }
+
+ public JCEECPublicKey(
+ ECPublicKey key)
+ {
+ this.algorithm = key.getAlgorithm();
+ this.ecSpec = key.getParams();
+ this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false);
+ }
+
+ JCEECPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ populateFromPubKeyInfo(info);
+ }
+
+ private void populateFromPubKeyInfo(SubjectPublicKeyInfo info)
+ {
+ // BEGIN android-removed
+ // if (info.getAlgorithmId().getObjectId().equals(CryptoProObjectIdentifiers.gostR3410_2001))
+ // {
+ // DERBitString bits = info.getPublicKeyData();
+ // ASN1OctetString key;
+ // this.algorithm = "ECGOST3410";
+ //
+ // try
+ // {
+ // key = (ASN1OctetString) ASN1Primitive.fromByteArray(bits.getBytes());
+ // }
+ // catch (IOException ex)
+ // {
+ // throw new IllegalArgumentException("error recovering public key");
+ // }
+ //
+ // byte[] keyEnc = key.getOctets();
+ // byte[] x = new byte[32];
+ // byte[] y = new byte[32];
+ //
+ // for (int i = 0; i != x.length; i++)
+ // {
+ // x[i] = keyEnc[32 - 1 - i];
+ // }
+ //
+ // for (int i = 0; i != y.length; i++)
+ // {
+ // y[i] = keyEnc[64 - 1 - i];
+ // }
+ //
+ // gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters());
+ //
+ // ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()));
+ //
+ // ECCurve curve = spec.getCurve();
+ // EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed());
+ //
+ // this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false);
+ //
+ // ecSpec = new ECNamedCurveSpec(
+ // ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()),
+ // ellipticCurve,
+ // new ECPoint(
+ // spec.getG().getX().toBigInteger(),
+ // spec.getG().getY().toBigInteger()),
+ // spec.getN(), spec.getH());
+ //
+ // }
+ // else
+ // END android-removed
+ {
+ X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithmId().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().getX().toBigInteger(),
+ ecP.getG().getY().toBigInteger()),
+ ecP.getN(),
+ ecP.getH());
+ }
+ else if (params.isImplicitlyCA())
+ {
+ ecSpec = null;
+ curve = BouncyCastleProvider.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().getX().toBigInteger(),
+ ecP.getG().getY().toBigInteger()),
+ ecP.getN(),
+ ecP.getH().intValue());
+ }
+
+ DERBitString bits = info.getPublicKeyData();
+ byte[] data = bits.getBytes();
+ ASN1OctetString key = new DEROctetString(data);
+
+ //
+ // extra octet string - one of our old certs...
+ //
+ if (data[0] == 0x04 && data[1] == data.length - 2
+ && (data[2] == 0x02 || data[2] == 0x03))
+ {
+ int qLength = new X9IntegerConverter().getByteLength(curve);
+
+ if (qLength >= data.length - 3)
+ {
+ try
+ {
+ key = (ASN1OctetString) ASN1Primitive.fromByteArray(data);
+ }
+ catch (IOException ex)
+ {
+ throw new IllegalArgumentException("error recovering public key");
+ }
+ }
+ }
+ X9ECPoint derQ = new X9ECPoint(curve, key);
+
+ this.q = derQ.getPoint();
+ }
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ ASN1Encodable params;
+ SubjectPublicKeyInfo info;
+
+ // BEGIN android-removed
+ // if (algorithm.equals("ECGOST3410"))
+ // {
+ // if (gostParams != null)
+ // {
+ // params = gostParams;
+ // }
+ // else
+ // {
+ // if (ecSpec instanceof ECNamedCurveSpec)
+ // {
+ // params = new GOST3410PublicKeyAlgParameters(
+ // ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
+ // CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet);
+ // }
+ // else
+ // { // strictly speaking this may not be applicable...
+ // ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+ //
+ // X9ECParameters ecP = new X9ECParameters(
+ // curve,
+ // EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ // ecSpec.getOrder(),
+ // BigInteger.valueOf(ecSpec.getCofactor()),
+ // ecSpec.getCurve().getSeed());
+ //
+ // params = new X962Parameters(ecP);
+ // }
+ // }
+ //
+ // BigInteger bX = this.q.getX().toBigInteger();
+ // BigInteger bY = this.q.getY().toBigInteger();
+ // byte[] encKey = new byte[64];
+ //
+ // extractBytes(encKey, 0, bX);
+ // extractBytes(encKey, 32, bY);
+ //
+ // info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3410_2001, params), new DEROctetString(encKey));
+ // }
+ // else
+ // END android-removed
+ {
+ if (ecSpec instanceof ECNamedCurveSpec)
+ {
+ ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec)ecSpec).getName());
+ if (curveOid == null)
+ {
+ curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec)ecSpec).getName());
+ }
+ params = new X962Parameters(curveOid);
+ }
+ else if (ecSpec == null)
+ {
+ params = new X962Parameters(DERNull.INSTANCE);
+ }
+ else
+ {
+ ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
+
+ X9ECParameters ecP = new X9ECParameters(
+ curve,
+ EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
+ ecSpec.getOrder(),
+ BigInteger.valueOf(ecSpec.getCofactor()),
+ ecSpec.getCurve().getSeed());
+
+ params = new X962Parameters(ecP);
+ }
+
+ ECCurve curve = this.engineGetQ().getCurve();
+ ASN1OctetString p = (ASN1OctetString)
+ new X9ECPoint(curve.createPoint(this.getQ().getX().toBigInteger(), this.getQ().getY().toBigInteger(), withCompression)).toASN1Primitive();
+
+ info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets());
+ }
+
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(info);
+ }
+
+ private void extractBytes(byte[] encKey, int offSet, BigInteger bI)
+ {
+ byte[] val = bI.toByteArray();
+ if (val.length < 32)
+ {
+ byte[] tmp = new byte[32];
+ System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length);
+ val = tmp;
+ }
+
+ for (int i = 0; i != 32; i++)
+ {
+ encKey[offSet + i] = val[val.length - 1 - i];
+ }
+ }
+
+ public ECParameterSpec getParams()
+ {
+ return ecSpec;
+ }
+
+ public org.bouncycastle.jce.spec.ECParameterSpec getParameters()
+ {
+ if (ecSpec == null) // implictlyCA
+ {
+ return null;
+ }
+
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ public ECPoint getW()
+ {
+ return new ECPoint(q.getX().toBigInteger(), q.getY().toBigInteger());
+ }
+
+ public org.bouncycastle.math.ec.ECPoint getQ()
+ {
+ if (ecSpec == null)
+ {
+ if (q instanceof org.bouncycastle.math.ec.ECPoint.Fp)
+ {
+ return new org.bouncycastle.math.ec.ECPoint.Fp(null, q.getX(), q.getY());
+ }
+ else
+ {
+ return new org.bouncycastle.math.ec.ECPoint.F2m(null, q.getX(), q.getY());
+ }
+ }
+
+ return q;
+ }
+
+ public org.bouncycastle.math.ec.ECPoint engineGetQ()
+ {
+ return q;
+ }
+
+ org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec()
+ {
+ if (ecSpec != null)
+ {
+ return EC5Util.convertSpec(ecSpec, withCompression);
+ }
+
+ return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("EC Public Key").append(nl);
+ buf.append(" X: ").append(this.q.getX().toBigInteger().toString(16)).append(nl);
+ buf.append(" Y: ").append(this.q.getY().toBigInteger().toString(16)).append(nl);
+
+ return buf.toString();
+
+ }
+
+ public void setPointFormat(String style)
+ {
+ withCompression = !("UNCOMPRESSED".equalsIgnoreCase(style));
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof JCEECPublicKey))
+ {
+ return false;
+ }
+
+ JCEECPublicKey other = (JCEECPublicKey)o;
+
+ return engineGetQ().equals(other.engineGetQ()) && (engineGetSpec().equals(other.engineGetSpec()));
+ }
+
+ public int hashCode()
+ {
+ return engineGetQ().hashCode() ^ engineGetSpec().hashCode();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ byte[] enc = (byte[])in.readObject();
+
+ populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(enc)));
+
+ this.algorithm = (String)in.readObject();
+ this.withCompression = in.readBoolean();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(this.getEncoded());
+ out.writeObject(algorithm);
+ out.writeBoolean(withCompression);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEMac.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
new file mode 100644
index 0000000..6a3df68
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEMac.java
@@ -0,0 +1,455 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.MacSpi;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Mac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.MD2Digest;
+// import org.bouncycastle.crypto.digests.MD4Digest;
+// import org.bouncycastle.crypto.digests.MD5Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD128Digest;
+// import org.bouncycastle.crypto.digests.RIPEMD160Digest;
+// 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;
+// import org.bouncycastle.crypto.digests.TigerDigest;
+// END android-removed
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-added
+import org.bouncycastle.crypto.engines.DESEngine;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.engines.RC2Engine;
+// END android-removed
+import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
+// END android-removed
+import org.bouncycastle.crypto.macs.HMac;
+// BEGIN android-removed
+// import org.bouncycastle.crypto.macs.ISO9797Alg3Mac;
+// import org.bouncycastle.crypto.macs.OldHMac;
+// END android-removed
+import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+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 JCEMac
+ extends MacSpi implements PBE
+{
+ private Mac macEngine;
+
+ private int pbeType = PKCS12;
+ private int pbeHash = SHA1;
+ private int keySize = 160;
+
+ protected JCEMac(
+ Mac macEngine)
+ {
+ this.macEngine = macEngine;
+ }
+
+ protected JCEMac(
+ Mac macEngine,
+ int pbeType,
+ int pbeHash,
+ int keySize)
+ {
+ this.macEngine = macEngine;
+ this.pbeType = pbeType;
+ this.pbeHash = pbeHash;
+ this.keySize = keySize;
+ }
+
+ protected void engineInit(
+ Key key,
+ AlgorithmParameterSpec params)
+ throws InvalidKeyException, InvalidAlgorithmParameterException
+ {
+ CipherParameters param;
+
+ if (key == null)
+ {
+ throw new InvalidKeyException("key is null");
+ }
+
+ if (key instanceof BCPBEKey)
+ {
+ BCPBEKey k = (BCPBEKey)key;
+
+ if (k.getParam() != null)
+ {
+ param = k.getParam();
+ }
+ else if (params instanceof PBEParameterSpec)
+ {
+ param = PBE.Util.makePBEMacParameters(k, params);
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("PBE requires PBE parameters to be set.");
+ }
+ }
+ else if (params instanceof IvParameterSpec)
+ {
+ param = new ParametersWithIV(new KeyParameter(key.getEncoded()), ((IvParameterSpec)params).getIV());
+ }
+ else if (params == null)
+ {
+ param = new KeyParameter(key.getEncoded());
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException("unknown parameter type.");
+ }
+
+ macEngine.init(param);
+ }
+
+ protected int engineGetMacLength()
+ {
+ return macEngine.getMacSize();
+ }
+
+ protected void engineReset()
+ {
+ macEngine.reset();
+ }
+
+ protected void engineUpdate(
+ byte input)
+ {
+ macEngine.update(input);
+ }
+
+ protected void engineUpdate(
+ byte[] input,
+ int offset,
+ int len)
+ {
+ macEngine.update(input, offset, len);
+ }
+
+ protected byte[] engineDoFinal()
+ {
+ byte[] out = new byte[engineGetMacLength()];
+
+ macEngine.doFinal(out, 0);
+
+ return out;
+ }
+
+ /**
+ * the classes that extend directly off us.
+ */
+
+ // BEGIN android-removed
+ // /**
+ // * DES
+ // */
+ // public static class DES
+ // extends JCEMac
+ // {
+ // public DES()
+ // {
+ // super(new CBCBlockCipherMac(new DESEngine()));
+ // }
+ // }
+ //
+ // /**
+ // * DES 64 bit MAC
+ // */
+ // public static class DES64
+ // extends JCEMac
+ // {
+ // public DES64()
+ // {
+ // super(new CBCBlockCipherMac(new DESEngine(), 64));
+ // }
+ // }
+ //
+ // /**
+ // * RC2
+ // */
+ // public static class RC2
+ // extends JCEMac
+ // {
+ // public RC2()
+ // {
+ // super(new CBCBlockCipherMac(new RC2Engine()));
+ // }
+ // }
+ //
+ //
+ //
+ //
+ // /**
+ // * DES
+ // */
+ // public static class DESCFB8
+ // extends JCEMac
+ // {
+ // public DESCFB8()
+ // {
+ // super(new CFBBlockCipherMac(new DESEngine()));
+ // }
+ // }
+ //
+ // /**
+ // * RC2CFB8
+ // */
+ //
+ //
+ // /**
+ // * DES9797Alg3with7816-4Padding
+ // */
+ // public static class DES9797Alg3with7816d4
+ // extends JCEMac
+ // {
+ // public DES9797Alg3with7816d4()
+ // {
+ // super(new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()));
+ // }
+ // }
+ //
+ // /**
+ // * DES9797Alg3
+ // */
+ // public static class DES9797Alg3
+ // extends JCEMac
+ // {
+ // public DES9797Alg3()
+ // {
+ // super(new ISO9797Alg3Mac(new DESEngine()));
+ // }
+ // }
+ //
+ // /**
+ // * MD2 HMac
+ // */
+ // public static class MD2
+ // extends JCEMac
+ // {
+ // public MD2()
+ // {
+ // super(new HMac(new MD2Digest()));
+ // }
+ // }
+ //
+ // /**
+ // * MD4 HMac
+ // */
+ // public static class MD4
+ // extends JCEMac
+ // {
+ // public MD4()
+ // {
+ // super(new HMac(new MD4Digest()));
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * MD5 HMac
+ */
+ public static class MD5
+ extends JCEMac
+ {
+ public MD5()
+ {
+ // BEGIN android-changed
+ super(new HMac(AndroidDigestFactory.getMD5()));
+ // END android-changed
+ }
+ }
+
+ /**
+ * SHA1 HMac
+ */
+ public static class SHA1
+ extends JCEMac
+ {
+ public SHA1()
+ {
+ // BEGIN android-changed
+ super(new HMac(AndroidDigestFactory.getSHA1()));
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * SHA-224 HMac
+ // */
+ // public static class SHA224
+ // extends JCEMac
+ // {
+ // public SHA224()
+ // {
+ // super(new HMac(new SHA224Digest()));
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * SHA-256 HMac
+ */
+ public static class SHA256
+ extends JCEMac
+ {
+ public SHA256()
+ {
+ // BEGIN android-changed
+ super(new HMac(AndroidDigestFactory.getSHA256()));
+ // END android-changed
+ }
+ }
+
+ /**
+ * SHA-384 HMac
+ */
+ public static class SHA384
+ extends JCEMac
+ {
+ public SHA384()
+ {
+ // BEGIN android-changed
+ super(new HMac(AndroidDigestFactory.getSHA384()));
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class OldSHA384
+ // extends JCEMac
+ // {
+ // public OldSHA384()
+ // {
+ // super(new OldHMac(new SHA384Digest()));
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * SHA-512 HMac
+ */
+ public static class SHA512
+ extends JCEMac
+ {
+ public SHA512()
+ {
+ // BEGIN android-changed
+ super(new HMac(AndroidDigestFactory.getSHA512()));
+ // END android-changed
+ }
+ }
+
+
+ // BEGIN android-removed
+ // /**
+ // * SHA-512 HMac
+ // */
+ // public static class OldSHA512
+ // extends JCEMac
+ // {
+ // public OldSHA512()
+ // {
+ // super(new OldHMac(new SHA512Digest()));
+ // }
+ // }
+ //
+ // /**
+ // * RIPEMD128 HMac
+ // */
+ // public static class RIPEMD128
+ // extends JCEMac
+ // {
+ // public RIPEMD128()
+ // {
+ // super(new HMac(new RIPEMD128Digest()));
+ // }
+ // }
+ //
+ // /**
+ // * RIPEMD160 HMac
+ // */
+ // public static class RIPEMD160
+ // extends JCEMac
+ // {
+ // public RIPEMD160()
+ // {
+ // super(new HMac(new RIPEMD160Digest()));
+ // }
+ // }
+ //
+ // /**
+ // * Tiger HMac
+ // */
+ // public static class Tiger
+ // extends JCEMac
+ // {
+ // public Tiger()
+ // {
+ // super(new HMac(new TigerDigest()));
+ // }
+ // }
+ //
+ // //
+ // // PKCS12 states that the same algorithm should be used
+ // // for the key generation as is used in the HMAC, so that
+ // // is what we do here.
+ // //
+ //
+ // /**
+ // * PBEWithHmacRIPEMD160
+ // */
+ // public static class PBEWithRIPEMD160
+ // extends JCEMac
+ // {
+ // public PBEWithRIPEMD160()
+ // {
+ // super(new HMac(new RIPEMD160Digest()), PKCS12, RIPEMD160, 160);
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * PBEWithHmacSHA
+ */
+ public static class PBEWithSHA
+ extends JCEMac
+ {
+ public PBEWithSHA()
+ {
+ // BEGIN android-changed
+ super(new HMac(AndroidDigestFactory.getSHA1()), PKCS12, SHA1, 160);
+ // END android-changed
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * PBEWithHmacTiger
+ // */
+ // public static class PBEWithTiger
+ // extends JCEMac
+ // {
+ // public PBEWithTiger()
+ // {
+ // super(new HMac(new TigerDigest()), PKCS12, TIGER, 192);
+ // }
+ // }
+ // END android-removed
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
new file mode 100644
index 0000000..c4c5b61
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java
@@ -0,0 +1,243 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.RSAPrivateCrtKeySpec;
+
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+
+/**
+ * A provider representation for a RSA private key, with CRT factors included.
+ */
+public class JCERSAPrivateCrtKey
+ extends JCERSAPrivateKey
+ implements RSAPrivateCrtKey
+{
+ static final long serialVersionUID = 7834723820638524718L;
+
+ private BigInteger publicExponent;
+ private BigInteger primeP;
+ private BigInteger primeQ;
+ private BigInteger primeExponentP;
+ private BigInteger primeExponentQ;
+ private BigInteger crtCoefficient;
+
+ /**
+ * construct a private key from it's org.bouncycastle.crypto equivalent.
+ *
+ * @param key the parameters object representing the private key.
+ */
+ JCERSAPrivateCrtKey(
+ RSAPrivateCrtKeyParameters key)
+ {
+ super(key);
+
+ this.publicExponent = key.getPublicExponent();
+ this.primeP = key.getP();
+ this.primeQ = key.getQ();
+ this.primeExponentP = key.getDP();
+ this.primeExponentQ = key.getDQ();
+ this.crtCoefficient = key.getQInv();
+ }
+
+ /**
+ * construct a private key from an RSAPrivateCrtKeySpec
+ *
+ * @param spec the spec to be used in construction.
+ */
+ JCERSAPrivateCrtKey(
+ RSAPrivateCrtKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ this.privateExponent = spec.getPrivateExponent();
+ this.primeP = spec.getPrimeP();
+ this.primeQ = spec.getPrimeQ();
+ this.primeExponentP = spec.getPrimeExponentP();
+ this.primeExponentQ = spec.getPrimeExponentQ();
+ this.crtCoefficient = spec.getCrtCoefficient();
+ }
+
+ /**
+ * construct a private key from another RSAPrivateCrtKey.
+ *
+ * @param key the object implementing the RSAPrivateCrtKey interface.
+ */
+ JCERSAPrivateCrtKey(
+ RSAPrivateCrtKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrimeP();
+ this.primeQ = key.getPrimeQ();
+ this.primeExponentP = key.getPrimeExponentP();
+ this.primeExponentQ = key.getPrimeExponentQ();
+ this.crtCoefficient = key.getCrtCoefficient();
+ }
+
+ /**
+ * construct an RSA key from a private key info object.
+ */
+ JCERSAPrivateCrtKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ this(org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(info.parsePrivateKey()));
+ }
+
+ /**
+ * construct an RSA key from a ASN.1 RSA private key object.
+ */
+ JCERSAPrivateCrtKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ this.privateExponent = key.getPrivateExponent();
+ this.primeP = key.getPrime1();
+ this.primeQ = key.getPrime2();
+ this.primeExponentP = key.getExponent1();
+ this.primeExponentQ = key.getExponent2();
+ this.crtCoefficient = key.getCoefficient();
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the encoding format we produce in getEncoded().
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ // BEGIN android-changed
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(getModulus(), getPublicExponent(), getPrivateExponent(), getPrimeP(), getPrimeQ(), getPrimeExponentP(), getPrimeExponentQ(), getCrtCoefficient()));
+ // END android-changed
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ /**
+ * return the prime P.
+ *
+ * @return the prime P.
+ */
+ public BigInteger getPrimeP()
+ {
+ return primeP;
+ }
+
+ /**
+ * return the prime Q.
+ *
+ * @return the prime Q.
+ */
+ public BigInteger getPrimeQ()
+ {
+ return primeQ;
+ }
+
+ /**
+ * return the prime exponent for P.
+ *
+ * @return the prime exponent for P.
+ */
+ public BigInteger getPrimeExponentP()
+ {
+ return primeExponentP;
+ }
+
+ /**
+ * return the prime exponent for Q.
+ *
+ * @return the prime exponent for Q.
+ */
+ public BigInteger getPrimeExponentQ()
+ {
+ return primeExponentQ;
+ }
+
+ /**
+ * return the CRT coefficient.
+ *
+ * @return the CRT coefficient.
+ */
+ public BigInteger getCrtCoefficient()
+ {
+ return crtCoefficient;
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode()
+ ^ this.getPublicExponent().hashCode()
+ ^ this.getPrivateExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPrivateCrtKey))
+ {
+ return false;
+ }
+
+ RSAPrivateCrtKey key = (RSAPrivateCrtKey)o;
+
+ return this.getModulus().equals(key.getModulus())
+ && this.getPublicExponent().equals(key.getPublicExponent())
+ && this.getPrivateExponent().equals(key.getPrivateExponent())
+ && this.getPrimeP().equals(key.getPrimeP())
+ && this.getPrimeQ().equals(key.getPrimeQ())
+ && this.getPrimeExponentP().equals(key.getPrimeExponentP())
+ && this.getPrimeExponentQ().equals(key.getPrimeExponentQ())
+ && this.getCrtCoefficient().equals(key.getCrtCoefficient());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Private CRT Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+ buf.append(" private exponent: ").append(this.getPrivateExponent().toString(16)).append(nl);
+ buf.append(" primeP: ").append(this.getPrimeP().toString(16)).append(nl);
+ buf.append(" primeQ: ").append(this.getPrimeQ().toString(16)).append(nl);
+ buf.append(" primeExponentP: ").append(this.getPrimeExponentP().toString(16)).append(nl);
+ buf.append(" primeExponentQ: ").append(this.getPrimeExponentQ().toString(16)).append(nl);
+ buf.append(" crtCoefficient: ").append(this.getCrtCoefficient().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
new file mode 100644
index 0000000..6277415
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateKey.java
@@ -0,0 +1,149 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.RSAPrivateKeySpec;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class JCERSAPrivateKey
+ implements RSAPrivateKey, PKCS12BagAttributeCarrier
+{
+ static final long serialVersionUID = 5110188922551353628L;
+
+ private static BigInteger ZERO = BigInteger.valueOf(0);
+
+ protected BigInteger modulus;
+ protected BigInteger privateExponent;
+
+ private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected JCERSAPrivateKey()
+ {
+ }
+
+ JCERSAPrivateKey(
+ RSAKeyParameters key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getExponent();
+ }
+
+ JCERSAPrivateKey(
+ RSAPrivateKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.privateExponent = spec.getPrivateExponent();
+ }
+
+ JCERSAPrivateKey(
+ RSAPrivateKey key)
+ {
+ this.modulus = key.getModulus();
+ this.privateExponent = key.getPrivateExponent();
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPrivateExponent()
+ {
+ return privateExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ public byte[] getEncoded()
+ {
+ // BEGIN android-changed
+ return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO));
+ // END android-changed
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof RSAPrivateKey))
+ {
+ return false;
+ }
+
+ if (o == this)
+ {
+ return true;
+ }
+
+ RSAPrivateKey key = (RSAPrivateKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPrivateExponent().equals(key.getPrivateExponent());
+ }
+
+ public int hashCode()
+ {
+ return getModulus().hashCode() ^ getPrivateExponent().hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ this.modulus = (BigInteger)in.readObject();
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ attrCarrier.readObject(in);
+
+ this.privateExponent = (BigInteger)in.readObject();
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(modulus);
+
+ attrCarrier.writeObject(out);
+
+ out.writeObject(privateExponent);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java
new file mode 100644
index 0000000..8d74351
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java
@@ -0,0 +1,133 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+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;
+
+public class JCERSAPublicKey
+ implements RSAPublicKey
+{
+ static final long serialVersionUID = 2675817738516720772L;
+
+ private BigInteger modulus;
+ private BigInteger publicExponent;
+
+ JCERSAPublicKey(
+ RSAKeyParameters key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getExponent();
+ }
+
+ JCERSAPublicKey(
+ RSAPublicKeySpec spec)
+ {
+ this.modulus = spec.getModulus();
+ this.publicExponent = spec.getPublicExponent();
+ }
+
+ JCERSAPublicKey(
+ RSAPublicKey key)
+ {
+ this.modulus = key.getModulus();
+ this.publicExponent = key.getPublicExponent();
+ }
+
+ JCERSAPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+ try
+ {
+ RSAPublicKeyStructure pubKey = new RSAPublicKeyStructure((ASN1Sequence)info.parsePublicKey());
+
+ this.modulus = pubKey.getModulus();
+ this.publicExponent = pubKey.getPublicExponent();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in RSA public key");
+ }
+ }
+
+ /**
+ * return the modulus.
+ *
+ * @return the modulus.
+ */
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ /**
+ * return the public exponent.
+ *
+ * @return the public exponent.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return publicExponent;
+ }
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ // BEGIN android-changed
+ return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKeyStructure(getModulus(), getPublicExponent()));
+ // END android-changed
+ }
+
+ public int hashCode()
+ {
+ return this.getModulus().hashCode() ^ this.getPublicExponent().hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof RSAPublicKey))
+ {
+ return false;
+ }
+
+ RSAPublicKey key = (RSAPublicKey)o;
+
+ return getModulus().equals(key.getModulus())
+ && getPublicExponent().equals(key.getPublicExponent());
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("RSA Public Key").append(nl);
+ buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl);
+ buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
new file mode 100644
index 0000000..7d70734
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCESecretKeyFactory.java
@@ -0,0 +1,612 @@
+package org.bouncycastle.jce.provider;
+
+import java.lang.reflect.Constructor;
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.DESKeySpec;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.params.DESParameters;
+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 JCESecretKeyFactory
+ extends SecretKeyFactorySpi
+ implements PBE
+{
+ protected String algName;
+ protected DERObjectIdentifier algOid;
+
+ protected JCESecretKeyFactory(
+ String algName,
+ DERObjectIdentifier algOid)
+ {
+ this.algName = algName;
+ this.algOid = algOid;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof SecretKeySpec)
+ {
+ return (SecretKey)keySpec;
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+
+ protected KeySpec engineGetKeySpec(
+ SecretKey key,
+ Class keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec == null)
+ {
+ throw new InvalidKeySpecException("keySpec parameter is null");
+ }
+ if (key == null)
+ {
+ throw new InvalidKeySpecException("key parameter is null");
+ }
+
+ if (SecretKeySpec.class.isAssignableFrom(keySpec))
+ {
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+
+ try
+ {
+ Class[] parameters = { byte[].class };
+
+ Constructor c = keySpec.getConstructor(parameters);
+ Object[] p = new Object[1];
+
+ p[0] = key.getEncoded();
+
+ return (KeySpec)c.newInstance(p);
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeySpecException(e.toString());
+ }
+ }
+
+ protected SecretKey engineTranslateKey(
+ SecretKey key)
+ throws InvalidKeyException
+ {
+ if (key == null)
+ {
+ throw new InvalidKeyException("key parameter is null");
+ }
+
+ if (!key.getAlgorithm().equalsIgnoreCase(algName))
+ {
+ throw new InvalidKeyException("Key not of type " + algName + ".");
+ }
+
+ return new SecretKeySpec(key.getEncoded(), algName);
+ }
+
+ /*
+ * classes that inherit from us
+ */
+
+ static public class PBEKeyFactory
+ extends JCESecretKeyFactory
+ {
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public PBEKeyFactory(
+ String algorithm,
+ DERObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ if (pbeSpec.getSalt() == null)
+ {
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ if (forCipher)
+ {
+ param = Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+ }
+ else
+ {
+ param = Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+ }
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ static public class DESPBEKeyFactory
+ extends JCESecretKeyFactory
+ {
+ private boolean forCipher;
+ private int scheme;
+ private int digest;
+ private int keySize;
+ private int ivSize;
+
+ public DESPBEKeyFactory(
+ String algorithm,
+ DERObjectIdentifier oid,
+ boolean forCipher,
+ int scheme,
+ int digest,
+ int keySize,
+ int ivSize)
+ {
+ super(algorithm, oid);
+
+ this.forCipher = forCipher;
+ this.scheme = scheme;
+ this.digest = digest;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+ CipherParameters param;
+
+ if (pbeSpec.getSalt() == null)
+ {
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, null);
+ }
+
+ if (forCipher)
+ {
+ param = Util.makePBEParameters(pbeSpec, scheme, digest, keySize, ivSize);
+ }
+ else
+ {
+ param = Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+ }
+
+ KeyParameter kParam;
+ if (param instanceof ParametersWithIV)
+ {
+ kParam = (KeyParameter)((ParametersWithIV)param).getParameters();
+ }
+ else
+ {
+ kParam = (KeyParameter)param;
+ }
+
+ DESParameters.setOddParity(kParam.getKey());
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+
+ static public class DES
+ extends JCESecretKeyFactory
+ {
+ public DES()
+ {
+ super("DES", null);
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof DESKeySpec)
+ {
+ DESKeySpec desKeySpec = (DESKeySpec)keySpec;
+ return new SecretKeySpec(desKeySpec.getKey(), "DES");
+ }
+
+ return super.engineGenerateSecret(keySpec);
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * PBEWithMD2AndDES
+ // */
+ // static public class PBEWithMD2AndDES
+ // extends DESPBEKeyFactory
+ // {
+ // public PBEWithMD2AndDES()
+ // {
+ // super("PBEwithMD2andDES", PKCSObjectIdentifiers.pbeWithMD2AndDES_CBC, true, PKCS5S1, MD2, 64, 64);
+ // }
+ // }
+ //
+ // /**
+ // * PBEWithMD2AndRC2
+ // */
+ // static public class PBEWithMD2AndRC2
+ // extends PBEKeyFactory
+ // {
+ // public PBEWithMD2AndRC2()
+ // {
+ // super("PBEwithMD2andRC2", PKCSObjectIdentifiers.pbeWithMD2AndRC2_CBC, true, PKCS5S1, MD2, 64, 64);
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * PBEWithMD5AndDES
+ */
+ static public class PBEWithMD5AndDES
+ extends DESPBEKeyFactory
+ {
+ public PBEWithMD5AndDES()
+ {
+ super("PBEwithMD5andDES", PKCSObjectIdentifiers.pbeWithMD5AndDES_CBC, true, PKCS5S1, MD5, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithMD5AndRC2
+ */
+ static public class PBEWithMD5AndRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5AndRC2()
+ {
+ super("PBEwithMD5andRC2", PKCSObjectIdentifiers.pbeWithMD5AndRC2_CBC, true, PKCS5S1, MD5, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndDES
+ */
+ static public class PBEWithSHA1AndDES
+ extends DESPBEKeyFactory
+ {
+ public PBEWithSHA1AndDES()
+ {
+ super("PBEwithSHA1andDES", PKCSObjectIdentifiers.pbeWithSHA1AndDES_CBC, true, PKCS5S1, SHA1, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHA1AndRC2
+ */
+ static public class PBEWithSHA1AndRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA1AndRC2()
+ {
+ super("PBEwithSHA1andRC2", PKCSObjectIdentifiers.pbeWithSHA1AndRC2_CBC, true, PKCS5S1, SHA1, 64, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd3-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES3Key
+ extends DESPBEKeyFactory
+ {
+ public PBEWithSHAAndDES3Key()
+ {
+ super("PBEwithSHAandDES3Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, true, PKCS12, SHA1, 192, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd2-KeyTripleDES-CBC
+ */
+ static public class PBEWithSHAAndDES2Key
+ extends DESPBEKeyFactory
+ {
+ public PBEWithSHAAndDES2Key()
+ {
+ super("PBEwithSHAandDES2Key-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd2_KeyTripleDES_CBC, true, PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd128BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd128BitRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd128BitRC2()
+ {
+ super("PBEwithSHAand128BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC2_CBC, true, PKCS12, SHA1, 128, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC2-CBC
+ */
+ static public class PBEWithSHAAnd40BitRC2
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd40BitRC2()
+ {
+ super("PBEwithSHAand40BitRC2-CBC", PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, true, PKCS12, SHA1, 40, 64);
+ }
+ }
+
+ /**
+ * PBEWithSHAAndTwofish-CBC
+ */
+ static public class PBEWithSHAAndTwofish
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAndTwofish()
+ {
+ super("PBEwithSHAandTwofish-CBC", null, true, PKCS12, SHA1, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd128BitRC4
+ */
+ static public class PBEWithSHAAnd128BitRC4
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd128BitRC4()
+ {
+ super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 128, 0);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC4
+ */
+ static public class PBEWithSHAAnd40BitRC4
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd40BitRC4()
+ {
+ super("PBEWithSHAAnd128BitRC4", PKCSObjectIdentifiers.pbeWithSHAAnd128BitRC4, true, PKCS12, SHA1, 40, 0);
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * PBEWithHmacRIPEMD160
+ // */
+ // public static class PBEWithRIPEMD160
+ // extends PBEKeyFactory
+ // {
+ // public PBEWithRIPEMD160()
+ // {
+ // super("PBEwithHmacRIPEMD160", null, false, PKCS12, RIPEMD160, 160, 0);
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * PBEWithHmacSHA
+ */
+ public static class PBEWithSHA
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA()
+ {
+ super("PBEwithHmacSHA", null, false, PKCS12, SHA1, 160, 0);
+ }
+ }
+
+ // BEGIN android-removed
+ // /**
+ // * PBEWithHmacTiger
+ // */
+ // public static class PBEWithTiger
+ // extends PBEKeyFactory
+ // {
+ // public PBEWithTiger()
+ // {
+ // super("PBEwithHmacTiger", null, false, PKCS12, TIGER, 192, 0);
+ // }
+ // }
+ // END android-removed
+
+ /**
+ * PBEWithSHA1And128BitAES-BC
+ */
+ static public class PBEWithSHAAnd128BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd128BitAESBC()
+ {
+ super("PBEWithSHA1And128BitAES-CBC-BC", null, true, PKCS12, SHA1, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And192BitAES-BC
+ */
+ static public class PBEWithSHAAnd192BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd192BitAESBC()
+ {
+ super("PBEWithSHA1And192BitAES-CBC-BC", null, true, PKCS12, SHA1, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA1And256BitAES-BC
+ */
+ static public class PBEWithSHAAnd256BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHAAnd256BitAESBC()
+ {
+ super("PBEWithSHA1And256BitAES-CBC-BC", null, true, PKCS12, SHA1, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And128BitAES-BC
+ */
+ static public class PBEWithSHA256And128BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA256And128BitAESBC()
+ {
+ super("PBEWithSHA256And128BitAES-CBC-BC", null, true, PKCS12, SHA256, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And192BitAES-BC
+ */
+ static public class PBEWithSHA256And192BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA256And192BitAESBC()
+ {
+ super("PBEWithSHA256And192BitAES-CBC-BC", null, true, PKCS12, SHA256, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithSHA256And256BitAES-BC
+ */
+ static public class PBEWithSHA256And256BitAESBC
+ extends PBEKeyFactory
+ {
+ public PBEWithSHA256And256BitAESBC()
+ {
+ super("PBEWithSHA256And256BitAES-CBC-BC", null, true, PKCS12, SHA256, 256, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And128BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And128BitAESCBCOpenSSL
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5And128BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And128BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 128, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And192BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And192BitAESCBCOpenSSL
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5And192BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And192BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 192, 128);
+ }
+ }
+
+ /**
+ * PBEWithMD5And256BitAES-OpenSSL
+ */
+ static public class PBEWithMD5And256BitAESCBCOpenSSL
+ extends PBEKeyFactory
+ {
+ public PBEWithMD5And256BitAESCBCOpenSSL()
+ {
+ super("PBEWithMD5And256BitAES-CBC-OpenSSL", null, true, OPENSSL, MD5, 256, 128);
+ }
+ }
+ // BEGIN android-added
+ static public class PBKDF2WithHmacSHA1
+ extends JCESecretKeyFactory
+ {
+ public PBKDF2WithHmacSHA1()
+ {
+ super("PBKDF2WithHmacSHA1", PKCSObjectIdentifiers.id_PBKDF2);
+ }
+
+ protected SecretKey engineGenerateSecret(
+ KeySpec keySpec)
+ throws InvalidKeySpecException
+ {
+ if (keySpec instanceof PBEKeySpec)
+ {
+ PBEKeySpec pbeSpec = (PBEKeySpec)keySpec;
+
+ if (pbeSpec.getSalt() == null)
+ {
+ throw new InvalidKeySpecException("missing required salt");
+ }
+
+ if (pbeSpec.getIterationCount() <= 0)
+ {
+ throw new InvalidKeySpecException("positive iteration count required: "
+ + pbeSpec.getIterationCount());
+ }
+
+ if (pbeSpec.getKeyLength() <= 0)
+ {
+ throw new InvalidKeySpecException("positive key length required: "
+ + pbeSpec.getKeyLength());
+ }
+
+ if (pbeSpec.getPassword().length == 0)
+ {
+ throw new IllegalArgumentException("password empty");
+ }
+
+ int scheme = PKCS5S2;
+ int digest = SHA1;
+ int keySize = pbeSpec.getKeyLength();
+ int ivSize = -1;
+ CipherParameters param = Util.makePBEMacParameters(pbeSpec, scheme, digest, keySize);
+
+ return new BCPBEKey(this.algName, this.algOid, scheme, digest, keySize, ivSize, pbeSpec, param);
+ }
+
+ throw new InvalidKeySpecException("Invalid KeySpec");
+ }
+ }
+ // END android-added
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
new file mode 100644
index 0000000..16a14ec
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JCEStreamCipher.java
@@ -0,0 +1,532 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+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 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)
+ {
+ 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)
+ {
+ if (inputLen != 0)
+ {
+ cipher.processBytes(input, inputOffset, inputLen, output, outputOffset);
+ }
+
+ cipher.reset();
+
+ return inputLen;
+ }
+
+ /*
+ * 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
+
+ /**
+ * PBEWithSHAAnd128BitRC4
+ */
+ static public class PBEWithSHAAnd128BitRC4
+ extends JCEStreamCipher
+ {
+ public PBEWithSHAAnd128BitRC4()
+ {
+ super(new RC4Engine(), 0);
+ }
+ }
+
+ /**
+ * PBEWithSHAAnd40BitRC4
+ */
+ static public class PBEWithSHAAnd40BitRC4
+ extends JCEStreamCipher
+ {
+ public PBEWithSHAAnd40BitRC4()
+ {
+ super(new RC4Engine(), 0);
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
new file mode 100644
index 0000000..9a8cf9b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
@@ -0,0 +1,320 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.AlgorithmParametersSpi;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.pkcs.PBKDF2Params;
+import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+// BEGIN android-removed
+// import org.bouncycastle.jce.spec.IESParameterSpec;
+// END android-removed
+
+public abstract class JDKAlgorithmParameters
+ extends AlgorithmParametersSpi
+{
+ protected boolean isASN1FormatString(String format)
+ {
+ return format == null || format.equals("ASN.1");
+ }
+
+ protected AlgorithmParameterSpec engineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == null)
+ {
+ throw new NullPointerException("argument to getParameterSpec must not be null");
+ }
+
+ return localEngineGetParameterSpec(paramSpec);
+ }
+
+ protected abstract AlgorithmParameterSpec localEngineGetParameterSpec(Class paramSpec)
+ throws InvalidParameterSpecException;
+
+ public static class PBKDF2
+ extends JDKAlgorithmParameters
+ {
+ PBKDF2Params params;
+
+ protected byte[] engineGetEncoded()
+ {
+ try
+ {
+ return params.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Oooops! " + e.toString());
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PBEParameterSpec.class)
+ {
+ return new PBEParameterSpec(params.getSalt(),
+ params.getIterationCount().intValue());
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PBEParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+ }
+
+ PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+ this.params = new PBKDF2Params(pbeSpec.getSalt(),
+ pbeSpec.getIterationCount());
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.params = PBKDF2Params.getInstance(ASN1Primitive.fromByteArray(params));
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in PWRIKEK parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "PBKDF2 Parameters";
+ }
+ }
+
+ public static class PKCS12PBE
+ extends JDKAlgorithmParameters
+ {
+ PKCS12PBEParams params;
+
+ protected byte[] engineGetEncoded()
+ {
+ try
+ {
+ return params.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Oooops! " + e.toString());
+ }
+ }
+
+ protected byte[] engineGetEncoded(
+ String format)
+ {
+ if (isASN1FormatString(format))
+ {
+ return engineGetEncoded();
+ }
+
+ return null;
+ }
+
+ protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ Class paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (paramSpec == PBEParameterSpec.class)
+ {
+ return new PBEParameterSpec(params.getIV(),
+ params.getIterations().intValue());
+ }
+
+ throw new InvalidParameterSpecException("unknown parameter spec passed to PKCS12 PBE parameters object.");
+ }
+
+ protected void engineInit(
+ AlgorithmParameterSpec paramSpec)
+ throws InvalidParameterSpecException
+ {
+ if (!(paramSpec instanceof PBEParameterSpec))
+ {
+ throw new InvalidParameterSpecException("PBEParameterSpec required to initialise a PKCS12 PBE parameters algorithm parameters object");
+ }
+
+ PBEParameterSpec pbeSpec = (PBEParameterSpec)paramSpec;
+
+ this.params = new PKCS12PBEParams(pbeSpec.getSalt(),
+ pbeSpec.getIterationCount());
+ }
+
+ protected void engineInit(
+ byte[] params)
+ throws IOException
+ {
+ this.params = PKCS12PBEParams.getInstance(ASN1Primitive.fromByteArray(params));
+ }
+
+ protected void engineInit(
+ byte[] params,
+ String format)
+ throws IOException
+ {
+ if (isASN1FormatString(format))
+ {
+ engineInit(params);
+ return;
+ }
+
+ throw new IOException("Unknown parameters format in PKCS12 PBE parameters object");
+ }
+
+ protected String engineToString()
+ {
+ return "PKCS12 PBE Parameters";
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class IES
+ // extends JDKAlgorithmParameters
+ // {
+ // IESParameterSpec currentSpec;
+ //
+ // /**
+ // * in the absence of a standard way of doing it this will do for
+ // * now...
+ // */
+ // protected byte[] engineGetEncoded()
+ // {
+ // try
+ // {
+ // ASN1EncodableVector v = new ASN1EncodableVector();
+ //
+ // v.add(new DEROctetString(currentSpec.getDerivationV()));
+ // v.add(new DEROctetString(currentSpec.getEncodingV()));
+ // v.add(new DERInteger(currentSpec.getMacKeySize()));
+ //
+ // return new DERSequence(v).getEncoded(ASN1Encoding.DER);
+ // }
+ // catch (IOException e)
+ // {
+ // throw new RuntimeException("Error encoding IESParameters");
+ // }
+ // }
+ //
+ // protected byte[] engineGetEncoded(
+ // String format)
+ // {
+ // if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ // {
+ // return engineGetEncoded();
+ // }
+ //
+ // return null;
+ // }
+ //
+ // protected AlgorithmParameterSpec localEngineGetParameterSpec(
+ // Class paramSpec)
+ // throws InvalidParameterSpecException
+ // {
+ // if (paramSpec == IESParameterSpec.class)
+ // {
+ // return currentSpec;
+ // }
+ //
+ // throw new InvalidParameterSpecException("unknown parameter spec passed to ElGamal parameters object.");
+ // }
+ //
+ // protected void engineInit(
+ // AlgorithmParameterSpec paramSpec)
+ // throws InvalidParameterSpecException
+ // {
+ // if (!(paramSpec instanceof IESParameterSpec))
+ // {
+ // throw new InvalidParameterSpecException("IESParameterSpec required to initialise a IES algorithm parameters object");
+ // }
+ //
+ // this.currentSpec = (IESParameterSpec)paramSpec;
+ // }
+ //
+ // protected void engineInit(
+ // byte[] params)
+ // throws IOException
+ // {
+ // try
+ // {
+ // ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(params);
+ //
+ // this.currentSpec = new IESParameterSpec(
+ // ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+ // ((ASN1OctetString)s.getObjectAt(0)).getOctets(),
+ // ((DERInteger)s.getObjectAt(0)).getValue().intValue());
+ // }
+ // catch (ClassCastException e)
+ // {
+ // throw new IOException("Not a valid IES Parameter encoding.");
+ // }
+ // catch (ArrayIndexOutOfBoundsException e)
+ // {
+ // throw new IOException("Not a valid IES Parameter encoding.");
+ // }
+ // }
+ //
+ // protected void engineInit(
+ // byte[] params,
+ // String format)
+ // throws IOException
+ // {
+ // if (isASN1FormatString(format) || format.equalsIgnoreCase("X.509"))
+ // {
+ // engineInit(params);
+ // }
+ // else
+ // {
+ // throw new IOException("Unknown parameter format " + format);
+ // }
+ // }
+ //
+ // protected String engineToString()
+ // {
+ // return "IES Parameters";
+ // }
+ // }
+ // END android-removed
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java
new file mode 100644
index 0000000..379120e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPrivateKey.java
@@ -0,0 +1,181 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.spec.DSAParameterSpec;
+import java.security.spec.DSAPrivateKeySpec;
+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.ASN1Sequence;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.DSAParameter;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+
+public class JDKDSAPrivateKey
+ implements DSAPrivateKey, PKCS12BagAttributeCarrier
+{
+ private static final long serialVersionUID = -4677259546958385734L;
+
+ BigInteger x;
+ DSAParams dsaSpec;
+
+ private PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ protected JDKDSAPrivateKey()
+ {
+ }
+
+ JDKDSAPrivateKey(
+ DSAPrivateKey key)
+ {
+ this.x = key.getX();
+ this.dsaSpec = key.getParams();
+ }
+
+ JDKDSAPrivateKey(
+ DSAPrivateKeySpec spec)
+ {
+ this.x = spec.getX();
+ this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+ }
+
+ JDKDSAPrivateKey(
+ PrivateKeyInfo info)
+ throws IOException
+ {
+ DSAParameter params = new DSAParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+ DERInteger derX = ASN1Integer.getInstance(info.parsePrivateKey());
+
+ this.x = derX.getValue();
+ this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+ }
+
+ JDKDSAPrivateKey(
+ DSAPrivateKeyParameters params)
+ {
+ this.x = params.getX();
+ this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+ }
+
+ public String getAlgorithm()
+ {
+ return "DSA";
+ }
+
+ /**
+ * return the encoding format we produce in getEncoded().
+ *
+ * @return the string "PKCS#8"
+ */
+ public String getFormat()
+ {
+ return "PKCS#8";
+ }
+
+ /**
+ * Return a PKCS8 representation of the key. The sequence returned
+ * represents a full PrivateKeyInfo object.
+ *
+ * @return a PKCS8 representation of the key.
+ */
+ public byte[] getEncoded()
+ {
+ try
+ {
+ PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new DERInteger(getX()));
+
+ return info.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public DSAParams getParams()
+ {
+ return dsaSpec;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAPrivateKey))
+ {
+ return false;
+ }
+
+ DSAPrivateKey other = (DSAPrivateKey)o;
+
+ return this.getX().equals(other.getX())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getQ().equals(other.getParams().getQ());
+ }
+
+ public int hashCode()
+ {
+ return this.getX().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ this.x = (BigInteger)in.readObject();
+ this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ this.attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ attrCarrier.readObject(in);
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(x);
+ out.writeObject(dsaSpec.getP());
+ out.writeObject(dsaSpec.getQ());
+ out.writeObject(dsaSpec.getG());
+
+ attrCarrier.writeObject(out);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java
new file mode 100644
index 0000000..16a964d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java
@@ -0,0 +1,177 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.math.BigInteger;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAParameterSpec;
+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.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;
+
+public class JDKDSAPublicKey
+ implements DSAPublicKey
+{
+ private static final long serialVersionUID = 1752452449903495175L;
+
+ private BigInteger y;
+ private DSAParams dsaSpec;
+
+ JDKDSAPublicKey(
+ DSAPublicKeySpec spec)
+ {
+ this.y = spec.getY();
+ this.dsaSpec = new DSAParameterSpec(spec.getP(), spec.getQ(), spec.getG());
+ }
+
+ JDKDSAPublicKey(
+ DSAPublicKey key)
+ {
+ this.y = key.getY();
+ this.dsaSpec = key.getParams();
+ }
+
+ JDKDSAPublicKey(
+ DSAPublicKeyParameters params)
+ {
+ this.y = params.getY();
+ this.dsaSpec = new DSAParameterSpec(params.getParameters().getP(), params.getParameters().getQ(), params.getParameters().getG());
+ }
+
+ JDKDSAPublicKey(
+ BigInteger y,
+ DSAParameterSpec dsaSpec)
+ {
+ this.y = y;
+ this.dsaSpec = dsaSpec;
+ }
+
+ JDKDSAPublicKey(
+ SubjectPublicKeyInfo info)
+ {
+
+ DERInteger derY;
+
+ try
+ {
+ derY = (DERInteger)info.parsePublicKey();
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("invalid info structure in DSA public key");
+ }
+
+ this.y = derY.getValue();
+
+ if (isNotNull(info.getAlgorithmId().getParameters()))
+ {
+ DSAParameter params = new DSAParameter((ASN1Sequence)info.getAlgorithmId().getParameters());
+
+ this.dsaSpec = new DSAParameterSpec(params.getP(), params.getQ(), params.getG());
+ }
+ }
+
+ private boolean isNotNull(ASN1Encodable parameters)
+ {
+ return parameters != null && !DERNull.INSTANCE.equals(parameters);
+ }
+
+ public String getAlgorithm()
+ {
+ return "DSA";
+ }
+
+ public String getFormat()
+ {
+ return "X.509";
+ }
+
+ public byte[] getEncoded()
+ {
+ try
+ {
+ 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 DSAParameter(dsaSpec.getP(), dsaSpec.getQ(), dsaSpec.getG())), new DERInteger(y)).getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public DSAParams getParams()
+ {
+ return dsaSpec;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append("DSA Public Key").append(nl);
+ buf.append(" y: ").append(this.getY().toString(16)).append(nl);
+
+ return buf.toString();
+ }
+
+ public int hashCode()
+ {
+ return this.getY().hashCode() ^ this.getParams().getG().hashCode()
+ ^ this.getParams().getP().hashCode() ^ this.getParams().getQ().hashCode();
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (!(o instanceof DSAPublicKey))
+ {
+ return false;
+ }
+
+ DSAPublicKey other = (DSAPublicKey)o;
+
+ return this.getY().equals(other.getY())
+ && this.getParams().getG().equals(other.getParams().getG())
+ && this.getParams().getP().equals(other.getParams().getP())
+ && this.getParams().getQ().equals(other.getParams().getQ());
+ }
+
+ private void readObject(
+ ObjectInputStream in)
+ throws IOException, ClassNotFoundException
+ {
+ this.y = (BigInteger)in.readObject();
+ this.dsaSpec = new DSAParameterSpec((BigInteger)in.readObject(), (BigInteger)in.readObject(), (BigInteger)in.readObject());
+ }
+
+ private void writeObject(
+ ObjectOutputStream out)
+ throws IOException
+ {
+ out.writeObject(y);
+ out.writeObject(dsaSpec.getP());
+ out.writeObject(dsaSpec.getQ());
+ out.writeObject(dsaSpec.getG());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
new file mode 100644
index 0000000..2c9c012
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKKeyStore.java
@@ -0,0 +1,1048 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.PBEParametersGenerator;
+// BEGIN android-added
+import org.bouncycastle.crypto.digests.AndroidDigestFactory;
+// END android-added
+// BEGIN android-removed
+// import org.bouncycastle.crypto.digests.SHA1Digest;
+// END android-removed
+import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
+import org.bouncycastle.crypto.io.DigestInputStream;
+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.jce.interfaces.BCKeyStore;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.io.Streams;
+import org.bouncycastle.util.io.TeeOutputStream;
+
+public class JDKKeyStore
+ extends KeyStoreSpi
+ implements BCKeyStore
+{
+ private static final int STORE_VERSION = 2;
+
+ private static final int STORE_SALT_SIZE = 20;
+ private static final String STORE_CIPHER = "PBEWithSHAAndTwofish-CBC";
+
+ private static final int KEY_SALT_SIZE = 20;
+ private static final int MIN_ITERATIONS = 1024;
+
+ private static final String KEY_CIPHER = "PBEWithSHAAnd3-KeyTripleDES-CBC";
+
+ //
+ // generic object types
+ //
+ static final int NULL = 0;
+ static final int CERTIFICATE = 1;
+ static final int KEY = 2;
+ static final int SECRET = 3;
+ static final int SEALED = 4;
+
+ //
+ // key types
+ //
+ static final int KEY_PRIVATE = 0;
+ static final int KEY_PUBLIC = 1;
+ static final int KEY_SECRET = 2;
+
+ protected Hashtable table = new Hashtable();
+
+ protected SecureRandom random = new SecureRandom();
+
+ public JDKKeyStore()
+ {
+ }
+
+ private class StoreEntry
+ {
+ int type;
+ String alias;
+ Object obj;
+ Certificate[] certChain;
+ Date date = new Date();
+
+ StoreEntry(
+ String alias,
+ Certificate obj)
+ {
+ this.type = CERTIFICATE;
+ this.alias = alias;
+ this.obj = obj;
+ this.certChain = null;
+ }
+
+ StoreEntry(
+ String alias,
+ byte[] obj,
+ Certificate[] certChain)
+ {
+ this.type = SECRET;
+ this.alias = alias;
+ this.obj = obj;
+ this.certChain = certChain;
+ }
+
+ StoreEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] certChain)
+ throws Exception
+ {
+ this.type = SEALED;
+ this.alias = alias;
+ this.certChain = certChain;
+
+ byte[] salt = new byte[KEY_SALT_SIZE];
+
+ random.setSeed(System.currentTimeMillis());
+ random.nextBytes(salt);
+
+ int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DataOutputStream dOut = new DataOutputStream(bOut);
+
+ dOut.writeInt(salt.length);
+ dOut.write(salt);
+ dOut.writeInt(iterationCount);
+
+ Cipher cipher = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+ CipherOutputStream cOut = new CipherOutputStream(dOut, cipher);
+
+ dOut = new DataOutputStream(cOut);
+
+ encodeKey(key, dOut);
+
+ dOut.close();
+
+ obj = bOut.toByteArray();
+ }
+
+ StoreEntry(
+ String alias,
+ Date date,
+ int type,
+ Object obj)
+ {
+ this.alias = alias;
+ this.date = date;
+ this.type = type;
+ this.obj = obj;
+ }
+
+ StoreEntry(
+ String alias,
+ Date date,
+ int type,
+ Object obj,
+ Certificate[] certChain)
+ {
+ this.alias = alias;
+ this.date = date;
+ this.type = type;
+ this.obj = obj;
+ this.certChain = certChain;
+ }
+
+ int getType()
+ {
+ return type;
+ }
+
+ String getAlias()
+ {
+ return alias;
+ }
+
+ Object getObject()
+ {
+ return obj;
+ }
+
+ Object getObject(
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ if (password == null || password.length == 0)
+ {
+ if (obj instanceof Key)
+ {
+ return obj;
+ }
+ }
+
+ if (type == SEALED)
+ {
+ ByteArrayInputStream bIn = new ByteArrayInputStream((byte[])obj);
+ DataInputStream dIn = new DataInputStream(bIn);
+
+ try
+ {
+ byte[] salt = new byte[dIn.readInt()];
+
+ dIn.readFully(salt);
+
+ int iterationCount = dIn.readInt();
+
+ Cipher cipher = makePBECipher(KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+ CipherInputStream cIn = new CipherInputStream(dIn, cipher);
+
+ try
+ {
+ return decodeKey(new DataInputStream(cIn));
+ }
+ catch (Exception x)
+ {
+ bIn = new ByteArrayInputStream((byte[])obj);
+ dIn = new DataInputStream(bIn);
+
+ salt = new byte[dIn.readInt()];
+
+ dIn.readFully(salt);
+
+ iterationCount = dIn.readInt();
+
+ cipher = makePBECipher("Broken" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+ cIn = new CipherInputStream(dIn, cipher);
+
+ Key k = null;
+
+ try
+ {
+ k = decodeKey(new DataInputStream(cIn));
+ }
+ catch (Exception y)
+ {
+ bIn = new ByteArrayInputStream((byte[])obj);
+ dIn = new DataInputStream(bIn);
+
+ salt = new byte[dIn.readInt()];
+
+ dIn.readFully(salt);
+
+ iterationCount = dIn.readInt();
+
+ cipher = makePBECipher("Old" + KEY_CIPHER, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+
+ cIn = new CipherInputStream(dIn, cipher);
+
+ k = decodeKey(new DataInputStream(cIn));
+ }
+
+ //
+ // reencrypt key with correct cipher.
+ //
+ if (k != null)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DataOutputStream dOut = new DataOutputStream(bOut);
+
+ dOut.writeInt(salt.length);
+ dOut.write(salt);
+ dOut.writeInt(iterationCount);
+
+ Cipher out = makePBECipher(KEY_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+ CipherOutputStream cOut = new CipherOutputStream(dOut, out);
+
+ dOut = new DataOutputStream(cOut);
+
+ encodeKey(k, dOut);
+
+ dOut.close();
+
+ obj = bOut.toByteArray();
+
+ return k;
+ }
+ else
+ {
+ throw new UnrecoverableKeyException("no match");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new UnrecoverableKeyException("no match");
+ }
+ }
+ else
+ {
+ throw new RuntimeException("forget something!");
+ // TODO
+ // if we get to here key was saved as byte data, which
+ // according to the docs means it must be a private key
+ // in EncryptedPrivateKeyInfo (PKCS8 format), later...
+ //
+ }
+ }
+
+ Certificate[] getCertificateChain()
+ {
+ return certChain;
+ }
+
+ Date getDate()
+ {
+ return date;
+ }
+ }
+
+ private void encodeCertificate(
+ Certificate cert,
+ DataOutputStream dOut)
+ throws IOException
+ {
+ try
+ {
+ byte[] cEnc = cert.getEncoded();
+
+ dOut.writeUTF(cert.getType());
+ dOut.writeInt(cEnc.length);
+ dOut.write(cEnc);
+ }
+ catch (CertificateEncodingException ex)
+ {
+ throw new IOException(ex.toString());
+ }
+ }
+
+ private Certificate decodeCertificate(
+ DataInputStream dIn)
+ throws IOException
+ {
+ String type = dIn.readUTF();
+ byte[] cEnc = new byte[dIn.readInt()];
+
+ dIn.readFully(cEnc);
+
+ try
+ {
+ CertificateFactory cFact = CertificateFactory.getInstance(type, BouncyCastleProvider.PROVIDER_NAME);
+ ByteArrayInputStream bIn = new ByteArrayInputStream(cEnc);
+
+ return cFact.generateCertificate(bIn);
+ }
+ catch (NoSuchProviderException ex)
+ {
+ throw new IOException(ex.toString());
+ }
+ catch (CertificateException ex)
+ {
+ throw new IOException(ex.toString());
+ }
+ }
+
+ private void encodeKey(
+ Key key,
+ DataOutputStream dOut)
+ throws IOException
+ {
+ byte[] enc = key.getEncoded();
+
+ if (key instanceof PrivateKey)
+ {
+ dOut.write(KEY_PRIVATE);
+ }
+ else if (key instanceof PublicKey)
+ {
+ dOut.write(KEY_PUBLIC);
+ }
+ else
+ {
+ dOut.write(KEY_SECRET);
+ }
+
+ dOut.writeUTF(key.getFormat());
+ dOut.writeUTF(key.getAlgorithm());
+ dOut.writeInt(enc.length);
+ dOut.write(enc);
+ }
+
+ private Key decodeKey(
+ DataInputStream dIn)
+ throws IOException
+ {
+ int keyType = dIn.read();
+ String format = dIn.readUTF();
+ String algorithm = dIn.readUTF();
+ byte[] enc = new byte[dIn.readInt()];
+ KeySpec spec;
+
+ dIn.readFully(enc);
+
+ if (format.equals("PKCS#8") || format.equals("PKCS8"))
+ {
+ spec = new PKCS8EncodedKeySpec(enc);
+ }
+ else if (format.equals("X.509") || format.equals("X509"))
+ {
+ spec = new X509EncodedKeySpec(enc);
+ }
+ else if (format.equals("RAW"))
+ {
+ return new SecretKeySpec(enc, algorithm);
+ }
+ else
+ {
+ throw new IOException("Key format " + format + " not recognised!");
+ }
+
+ try
+ {
+ switch (keyType)
+ {
+ case KEY_PRIVATE:
+ return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePrivate(spec);
+ case KEY_PUBLIC:
+ return KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generatePublic(spec);
+ case KEY_SECRET:
+ return SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME).generateSecret(spec);
+ default:
+ throw new IOException("Key type " + keyType + " not recognised!");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Exception creating key: " + e.toString());
+ }
+ }
+
+ protected Cipher makePBECipher(
+ String algorithm,
+ int mode,
+ char[] password,
+ byte[] salt,
+ int iterationCount)
+ throws IOException
+ {
+ try
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
+ PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount);
+
+ Cipher cipher = Cipher.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME);
+
+ cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams);
+
+ return cipher;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("Error initialising store of key store: " + e);
+ }
+ }
+
+ public void setRandom(
+ SecureRandom rand)
+ {
+ this.random = rand;
+ }
+
+ public Enumeration engineAliases()
+ {
+ return table.keys();
+ }
+
+ public boolean engineContainsAlias(
+ String alias)
+ {
+ return (table.get(alias) != null);
+ }
+
+ public void engineDeleteEntry(
+ String alias)
+ throws KeyStoreException
+ {
+ Object entry = table.get(alias);
+
+ if (entry == null)
+ {
+ // BEGIN android-removed
+ // Only throw if there is a problem removing, not if missing
+ // throw new KeyStoreException("no such entry as " + alias);
+ // END android-removed
+ // BEGIN android-added
+ return;
+ // END android-added
+ }
+
+ table.remove(alias);
+ }
+
+ public Certificate engineGetCertificate(
+ String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null)
+ {
+ if (entry.getType() == CERTIFICATE)
+ {
+ return (Certificate)entry.getObject();
+ }
+ else
+ {
+ Certificate[] chain = entry.getCertificateChain();
+
+ if (chain != null)
+ {
+ return chain[0];
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String engineGetCertificateAlias(
+ Certificate cert)
+ {
+ Enumeration e = table.elements();
+ while (e.hasMoreElements())
+ {
+ StoreEntry entry = (StoreEntry)e.nextElement();
+
+ if (entry.getObject() instanceof Certificate)
+ {
+ Certificate c = (Certificate)entry.getObject();
+
+ if (c.equals(cert))
+ {
+ return entry.getAlias();
+ }
+ }
+ else
+ {
+ Certificate[] chain = entry.getCertificateChain();
+
+ if (chain != null && chain[0].equals(cert))
+ {
+ return entry.getAlias();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(
+ String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null)
+ {
+ return entry.getCertificateChain();
+ }
+
+ return null;
+ }
+
+ public Date engineGetCreationDate(String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null)
+ {
+ return entry.getDate();
+ }
+
+ return null;
+ }
+
+ public Key engineGetKey(
+ String alias,
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry == null || entry.getType() == CERTIFICATE)
+ {
+ return null;
+ }
+
+ return (Key)entry.getObject(password);
+ }
+
+ public boolean engineIsCertificateEntry(
+ String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null && entry.getType() == CERTIFICATE)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean engineIsKeyEntry(
+ String alias)
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null && entry.getType() != CERTIFICATE)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ public void engineSetCertificateEntry(
+ String alias,
+ Certificate cert)
+ throws KeyStoreException
+ {
+ StoreEntry entry = (StoreEntry)table.get(alias);
+
+ if (entry != null && entry.getType() != CERTIFICATE)
+ {
+ throw new KeyStoreException("key store already has a key entry with alias " + alias);
+ }
+
+ table.put(alias, new StoreEntry(alias, cert));
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ byte[] key,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ table.put(alias, new StoreEntry(alias, key, chain));
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ if ((key instanceof PrivateKey) && (chain == null))
+ {
+ throw new KeyStoreException("no certificate chain for private key");
+ }
+
+ try
+ {
+ table.put(alias, new StoreEntry(alias, key, password, chain));
+ }
+ catch (Exception e)
+ {
+ throw new KeyStoreException(e.toString());
+ }
+ }
+
+ public int engineSize()
+ {
+ return table.size();
+ }
+
+ protected void loadStore(
+ InputStream in)
+ throws IOException
+ {
+ DataInputStream dIn = new DataInputStream(in);
+ int type = dIn.read();
+
+ while (type > NULL)
+ {
+ String alias = dIn.readUTF();
+ Date date = new Date(dIn.readLong());
+ int chainLength = dIn.readInt();
+ Certificate[] chain = null;
+
+ if (chainLength != 0)
+ {
+ chain = new Certificate[chainLength];
+
+ for (int i = 0; i != chainLength; i++)
+ {
+ chain[i] = decodeCertificate(dIn);
+ }
+ }
+
+ switch (type)
+ {
+ case CERTIFICATE:
+ Certificate cert = decodeCertificate(dIn);
+
+ table.put(alias, new StoreEntry(alias, date, CERTIFICATE, cert));
+ break;
+ case KEY:
+ Key key = decodeKey(dIn);
+ table.put(alias, new StoreEntry(alias, date, KEY, key, chain));
+ break;
+ case SECRET:
+ case SEALED:
+ byte[] b = new byte[dIn.readInt()];
+
+ dIn.readFully(b);
+ table.put(alias, new StoreEntry(alias, date, type, b, chain));
+ break;
+ default:
+ throw new RuntimeException("Unknown object type in store.");
+ }
+
+ type = dIn.read();
+ }
+ }
+
+ protected void saveStore(
+ OutputStream out)
+ throws IOException
+ {
+ Enumeration e = table.elements();
+ DataOutputStream dOut = new DataOutputStream(out);
+
+ while (e.hasMoreElements())
+ {
+ StoreEntry entry = (StoreEntry)e.nextElement();
+
+ dOut.write(entry.getType());
+ dOut.writeUTF(entry.getAlias());
+ dOut.writeLong(entry.getDate().getTime());
+
+ Certificate[] chain = entry.getCertificateChain();
+ if (chain == null)
+ {
+ dOut.writeInt(0);
+ }
+ else
+ {
+ dOut.writeInt(chain.length);
+ for (int i = 0; i != chain.length; i++)
+ {
+ encodeCertificate(chain[i], dOut);
+ }
+ }
+
+ switch (entry.getType())
+ {
+ case CERTIFICATE:
+ encodeCertificate((Certificate)entry.getObject(), dOut);
+ break;
+ case KEY:
+ encodeKey((Key)entry.getObject(), dOut);
+ break;
+ case SEALED:
+ case SECRET:
+ byte[] b = (byte[])entry.getObject();
+
+ dOut.writeInt(b.length);
+ dOut.write(b);
+ break;
+ default:
+ throw new RuntimeException("Unknown object type in store.");
+ }
+ }
+
+ dOut.write(NULL);
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ table.clear();
+
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ DataInputStream dIn = new DataInputStream(stream);
+ int version = dIn.readInt();
+
+ if (version != STORE_VERSION)
+ {
+ if (version != 0 && version != 1)
+ {
+ throw new IOException("Wrong version of key store.");
+ }
+ }
+
+ int saltLength = dIn.readInt();
+ if (saltLength <= 0)
+ {
+ throw new IOException("Invalid salt detected");
+ }
+
+ byte[] salt = new byte[saltLength];
+
+ dIn.readFully(salt);
+
+ int iterationCount = dIn.readInt();
+
+ //
+ // we only do an integrity check if the password is provided.
+ //
+ // BEGIN android-changed
+ HMac hMac = new HMac(AndroidDigestFactory.getSHA1());
+ // END android-changed
+ if (password != null && password.length != 0)
+ {
+ byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
+
+ // BEGIN android-changed
+ PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA1());
+ // END android-changed
+ pbeGen.init(passKey, salt, iterationCount);
+
+ CipherParameters macParams;
+
+ if (version != 2)
+ {
+ macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize());
+ }
+ else
+ {
+ macParams = pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8);
+ }
+
+ Arrays.fill(passKey, (byte)0);
+
+ hMac.init(macParams);
+ MacInputStream mIn = new MacInputStream(dIn, hMac);
+
+ loadStore(mIn);
+
+ // Finalise our mac calculation
+ byte[] mac = new byte[hMac.getMacSize()];
+ hMac.doFinal(mac, 0);
+
+ // TODO Should this actually be reading the remainder of the stream?
+ // Read the original mac from the stream
+ byte[] oldMac = new byte[hMac.getMacSize()];
+ dIn.readFully(oldMac);
+
+ if (!Arrays.constantTimeAreEqual(mac, oldMac))
+ {
+ table.clear();
+ throw new IOException("KeyStore integrity check failed.");
+ }
+ }
+ else
+ {
+ loadStore(dIn);
+
+ // TODO Should this actually be reading the remainder of the stream?
+ // Parse the original mac from the stream too
+ byte[] oldMac = new byte[hMac.getMacSize()];
+ dIn.readFully(oldMac);
+ }
+ }
+
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ DataOutputStream dOut = new DataOutputStream(stream);
+ byte[] salt = new byte[STORE_SALT_SIZE];
+ int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+ random.nextBytes(salt);
+
+ dOut.writeInt(STORE_VERSION);
+ dOut.writeInt(salt.length);
+ dOut.write(salt);
+ dOut.writeInt(iterationCount);
+
+ // BEGIN android-changed
+ HMac hMac = new HMac(AndroidDigestFactory.getSHA1());
+ MacOutputStream mOut = new MacOutputStream(hMac);
+ PBEParametersGenerator pbeGen = new PKCS12ParametersGenerator(AndroidDigestFactory.getSHA1());
+ // END android-changed
+ byte[] passKey = PBEParametersGenerator.PKCS12PasswordToBytes(password);
+
+ pbeGen.init(passKey, salt, iterationCount);
+
+ hMac.init(pbeGen.generateDerivedMacParameters(hMac.getMacSize() * 8));
+
+ for (int i = 0; i != passKey.length; i++)
+ {
+ passKey[i] = 0;
+ }
+
+ saveStore(new TeeOutputStream(dOut, mOut));
+
+ byte[] mac = new byte[hMac.getMacSize()];
+
+ hMac.doFinal(mac, 0);
+
+ dOut.write(mac);
+
+ dOut.close();
+ }
+
+ /**
+ * the BouncyCastle store. This wont work with the key tool as the
+ * store is stored encrypted on disk, so the password is mandatory,
+ * however if you hard drive is in a bad part of town and you absolutely,
+ * positively, don't want nobody peeking at your things, this is the
+ * one to use, no problem! After all in a Bouncy Castle nothing can
+ * touch you.
+ *
+ * Also referred to by the alias UBER.
+ */
+ public static class BouncyCastleStore
+ extends JDKKeyStore
+ {
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ table.clear();
+
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ DataInputStream dIn = new DataInputStream(stream);
+ int version = dIn.readInt();
+
+ if (version != STORE_VERSION)
+ {
+ if (version != 0 && version != 1)
+ {
+ throw new IOException("Wrong version of key store.");
+ }
+ }
+
+ byte[] salt = new byte[dIn.readInt()];
+
+ if (salt.length != STORE_SALT_SIZE)
+ {
+ throw new IOException("Key store corrupted.");
+ }
+
+ dIn.readFully(salt);
+
+ int iterationCount = dIn.readInt();
+
+ if ((iterationCount < 0) || (iterationCount > 4 * MIN_ITERATIONS))
+ {
+ throw new IOException("Key store corrupted.");
+ }
+
+ String cipherAlg;
+ if (version == 0)
+ {
+ cipherAlg = "Old" + STORE_CIPHER;
+ }
+ else
+ {
+ cipherAlg = STORE_CIPHER;
+ }
+
+ Cipher cipher = this.makePBECipher(cipherAlg, Cipher.DECRYPT_MODE, password, salt, iterationCount);
+ CipherInputStream cIn = new CipherInputStream(dIn, cipher);
+
+ // BEGIN android-changed
+ Digest dig = AndroidDigestFactory.getSHA1();
+ // END android-changed
+ DigestInputStream dgIn = new DigestInputStream(cIn, dig);
+
+ this.loadStore(dgIn);
+
+ // Finalise our digest calculation
+ byte[] hash = new byte[dig.getDigestSize()];
+ dig.doFinal(hash, 0);
+
+ // TODO Should this actually be reading the remainder of the stream?
+ // Read the original digest from the stream
+ byte[] oldHash = new byte[dig.getDigestSize()];
+ Streams.readFully(cIn, oldHash);
+
+ if (!Arrays.constantTimeAreEqual(hash, oldHash))
+ {
+ table.clear();
+ throw new IOException("KeyStore integrity check failed.");
+ }
+ }
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ Cipher cipher;
+ DataOutputStream dOut = new DataOutputStream(stream);
+ byte[] salt = new byte[STORE_SALT_SIZE];
+ int iterationCount = MIN_ITERATIONS + (random.nextInt() & 0x3ff);
+
+ random.nextBytes(salt);
+
+ dOut.writeInt(STORE_VERSION);
+ dOut.writeInt(salt.length);
+ dOut.write(salt);
+ dOut.writeInt(iterationCount);
+
+ cipher = this.makePBECipher(STORE_CIPHER, Cipher.ENCRYPT_MODE, password, salt, iterationCount);
+
+ CipherOutputStream cOut = new CipherOutputStream(dOut, cipher);
+ // BEGIN android-changed
+ DigestOutputStream dgOut = new DigestOutputStream(AndroidDigestFactory.getSHA1());
+ // END android-changed
+
+ this.saveStore(new TeeOutputStream(cOut, dgOut));
+
+ byte[] dig = dgOut.getDigest();
+
+ cOut.write(dig);
+
+ cOut.close();
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
new file mode 100644
index 0000000..2d9f683
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12KeyStore.java
@@ -0,0 +1,1658 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
+import java.security.KeyStoreException;
+import java.security.KeyStoreSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+import javax.crypto.spec.PBEParameterSpec;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.BERConstructedOctetString;
+import org.bouncycastle.asn1.BEROutputStream;
+import org.bouncycastle.asn1.DERBMPString;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DEROutputStream;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
+import org.bouncycastle.asn1.pkcs.CertBag;
+import org.bouncycastle.asn1.pkcs.ContentInfo;
+import org.bouncycastle.asn1.pkcs.EncryptedData;
+import org.bouncycastle.asn1.pkcs.MacData;
+import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.Pfx;
+import org.bouncycastle.asn1.pkcs.SafeBag;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.DigestInfo;
+import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
+import org.bouncycastle.jce.interfaces.BCKeyStore;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
+
+public class JDKPKCS12KeyStore
+ extends KeyStoreSpi
+ implements PKCSObjectIdentifiers, X509ObjectIdentifiers, BCKeyStore
+{
+ private static final int SALT_SIZE = 20;
+ private static final int MIN_ITERATIONS = 1024;
+
+ private static final Provider bcProvider = new BouncyCastleProvider();
+
+ private IgnoresCaseHashtable keys = new IgnoresCaseHashtable();
+ private Hashtable localIds = new Hashtable();
+ private IgnoresCaseHashtable certs = new IgnoresCaseHashtable();
+ private Hashtable chainCerts = new Hashtable();
+ private Hashtable keyCerts = new Hashtable();
+
+ //
+ // generic object types
+ //
+ static final int NULL = 0;
+ static final int CERTIFICATE = 1;
+ static final int KEY = 2;
+ static final int SECRET = 3;
+ static final int SEALED = 4;
+
+ //
+ // key types
+ //
+ static final int KEY_PRIVATE = 0;
+ static final int KEY_PUBLIC = 1;
+ static final int KEY_SECRET = 2;
+
+ protected SecureRandom random = new SecureRandom();
+
+ // use of final causes problems with JDK 1.2 compiler
+ private CertificateFactory certFact;
+ private ASN1ObjectIdentifier keyAlgorithm;
+ private ASN1ObjectIdentifier certAlgorithm;
+
+ private class CertId
+ {
+ byte[] id;
+
+ CertId(
+ PublicKey key)
+ {
+ this.id = createSubjectKeyId(key).getKeyIdentifier();
+ }
+
+ CertId(
+ byte[] id)
+ {
+ this.id = id;
+ }
+
+ public int hashCode()
+ {
+ return Arrays.hashCode(id);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof CertId))
+ {
+ return false;
+ }
+
+ CertId cId = (CertId)o;
+
+ return Arrays.areEqual(id, cId.id);
+ }
+ }
+
+ public JDKPKCS12KeyStore(
+ Provider provider,
+ ASN1ObjectIdentifier keyAlgorithm,
+ ASN1ObjectIdentifier certAlgorithm)
+ {
+ this.keyAlgorithm = keyAlgorithm;
+ this.certAlgorithm = certAlgorithm;
+
+ try
+ {
+ if (provider != null)
+ {
+ certFact = CertificateFactory.getInstance("X.509", provider);
+ }
+ else
+ {
+ certFact = CertificateFactory.getInstance("X.509");
+ }
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("can't create cert factory - " + e.toString());
+ }
+ }
+
+ private SubjectKeyIdentifier createSubjectKeyId(
+ PublicKey pubKey)
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence) ASN1Primitive.fromByteArray(pubKey.getEncoded()));
+
+ return new SubjectKeyIdentifier(info);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error creating key");
+ }
+ }
+
+ public void setRandom(
+ SecureRandom rand)
+ {
+ this.random = rand;
+ }
+
+ public Enumeration engineAliases()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.keys();
+ }
+
+ public boolean engineContainsAlias(
+ String alias)
+ {
+ return (certs.get(alias) != null || keys.get(alias) != null);
+ }
+
+ /**
+ * this is not quite complete - we should follow up on the chain, a bit
+ * tricky if a certificate appears in more than one chain...
+ */
+ public void engineDeleteEntry(
+ String alias)
+ throws KeyStoreException
+ {
+ Key k = (Key)keys.remove(alias);
+
+ Certificate c = (Certificate)certs.remove(alias);
+
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+
+ if (k != null)
+ {
+ String id = (String)localIds.remove(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.remove(id);
+ }
+ if (c != null)
+ {
+ chainCerts.remove(new CertId(c.getPublicKey()));
+ }
+ }
+
+ // BEGIN android-removed
+ // Only throw if there is a problem removing, not if missing
+ // if (c == null && k == null)
+ // {
+ // throw new KeyStoreException("no such entry as " + alias);
+ // }
+ // END android-removed
+ }
+
+ /**
+ * simply return the cert for the private key
+ */
+ public Certificate engineGetCertificate(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificate.");
+ }
+
+ Certificate c = (Certificate)certs.get(alias);
+
+ //
+ // look up the key table - and try the local key id
+ //
+ if (c == null)
+ {
+ String id = (String)localIds.get(alias);
+ if (id != null)
+ {
+ c = (Certificate)keyCerts.get(id);
+ }
+ else
+ {
+ c = (Certificate)keyCerts.get(alias);
+ }
+ }
+
+ return c;
+ }
+
+ public String engineGetCertificateAlias(
+ Certificate cert)
+ {
+ Enumeration c = certs.elements();
+ Enumeration k = certs.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ c = keyCerts.elements();
+ k = keyCerts.keys();
+
+ while (c.hasMoreElements())
+ {
+ Certificate tc = (Certificate)c.nextElement();
+ String ta = (String)k.nextElement();
+
+ if (tc.equals(cert))
+ {
+ return ta;
+ }
+ }
+
+ return null;
+ }
+
+ public Certificate[] engineGetCertificateChain(
+ String alias)
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getCertificateChain.");
+ }
+
+ if (!engineIsKeyEntry(alias))
+ {
+ return null;
+ }
+
+ Certificate c = engineGetCertificate(alias);
+
+ if (c != null)
+ {
+ Vector cs = new Vector();
+
+ while (c != null)
+ {
+ X509Certificate x509c = (X509Certificate)c;
+ Certificate nextC = null;
+
+ byte[] bytes = x509c.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream aIn = new ASN1InputStream(bytes);
+
+ byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets();
+ aIn = new ASN1InputStream(authBytes);
+
+ AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance((ASN1Sequence)aIn.readObject());
+ if (id.getKeyIdentifier() != null)
+ {
+ nextC = (Certificate)chainCerts.get(new CertId(id.getKeyIdentifier()));
+ }
+
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+ }
+
+ if (nextC == null)
+ {
+ //
+ // no authority key id, try the Issuer DN
+ //
+ Principal i = x509c.getIssuerDN();
+ Principal s = x509c.getSubjectDN();
+
+ if (!i.equals(s))
+ {
+ Enumeration e = chainCerts.keys();
+
+ while (e.hasMoreElements())
+ {
+ X509Certificate crt = (X509Certificate)chainCerts.get(e.nextElement());
+ Principal sub = crt.getSubjectDN();
+ if (sub.equals(i))
+ {
+ try
+ {
+ x509c.verify(crt.getPublicKey());
+ nextC = crt;
+ break;
+ }
+ catch (Exception ex)
+ {
+ // continue
+ }
+ }
+ }
+ }
+ }
+
+ cs.addElement(c);
+ if (nextC != c) // self signed - end of the chain
+ {
+ c = nextC;
+ }
+ else
+ {
+ c = null;
+ }
+ }
+
+ Certificate[] certChain = new Certificate[cs.size()];
+
+ for (int i = 0; i != certChain.length; i++)
+ {
+ certChain[i] = (Certificate)cs.elementAt(i);
+ }
+
+ return certChain;
+ }
+
+ return null;
+ }
+
+ public Date engineGetCreationDate(String alias)
+ {
+ // BEGIN android-added
+ if (alias == null) {
+ throw new NullPointerException("alias == null");
+ }
+ if (keys.get(alias) == null && certs.get(alias) == null) {
+ return null;
+ }
+ // END android-added
+ return new Date();
+ }
+
+ public Key engineGetKey(
+ String alias,
+ char[] password)
+ throws NoSuchAlgorithmException, UnrecoverableKeyException
+ {
+ if (alias == null)
+ {
+ throw new IllegalArgumentException("null alias passed to getKey.");
+ }
+
+ return (Key)keys.get(alias);
+ }
+
+ public boolean engineIsCertificateEntry(
+ String alias)
+ {
+ return (certs.get(alias) != null && keys.get(alias) == null);
+ }
+
+ public boolean engineIsKeyEntry(
+ String alias)
+ {
+ return (keys.get(alias) != null);
+ }
+
+ public void engineSetCertificateEntry(
+ String alias,
+ Certificate cert)
+ throws KeyStoreException
+ {
+ if (keys.get(alias) != null)
+ {
+ throw new KeyStoreException("There is a key entry with the name " + alias + ".");
+ }
+
+ certs.put(alias, cert);
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ byte[] key,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ throw new RuntimeException("operation not supported");
+ }
+
+ public void engineSetKeyEntry(
+ String alias,
+ Key key,
+ char[] password,
+ Certificate[] chain)
+ throws KeyStoreException
+ {
+ // BEGIN android-added
+ if (!(key instanceof PrivateKey)) {
+ throw new KeyStoreException("PKCS12 does not support non-PrivateKeys");
+ }
+ // END android-added
+ if ((key instanceof PrivateKey) && (chain == null))
+ {
+ throw new KeyStoreException("no certificate chain for private key");
+ }
+
+ if (keys.get(alias) != null)
+ {
+ engineDeleteEntry(alias);
+ }
+
+ keys.put(alias, key);
+ // BEGIN android-added
+ if (chain != null) {
+ // END android-added
+ certs.put(alias, chain[0]);
+
+ for (int i = 0; i != chain.length; i++)
+ {
+ chainCerts.put(new CertId(chain[i].getPublicKey()), chain[i]);
+ }
+ // BEGIN android-added
+ }
+ // END android-added
+ }
+
+ public int engineSize()
+ {
+ Hashtable tab = new Hashtable();
+
+ Enumeration e = certs.keys();
+ while (e.hasMoreElements())
+ {
+ tab.put(e.nextElement(), "cert");
+ }
+
+ e = keys.keys();
+ while (e.hasMoreElements())
+ {
+ String a = (String)e.nextElement();
+ if (tab.get(a) == null)
+ {
+ tab.put(a, "key");
+ }
+ }
+
+ return tab.size();
+ }
+
+ protected PrivateKey unwrapKey(
+ AlgorithmIdentifier algId,
+ byte[] data,
+ char[] password,
+ boolean wrongPKCS12Zero)
+ throws IOException
+ {
+ String algorithm = algId.getAlgorithm().getId();
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ PrivateKey out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ SecretKey k = keyFact.generateSecret(pbeSpec);
+
+ ((BCPBEKey)k).setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.UNWRAP_MODE, k, defParams);
+
+ // we pass "" as the key algorithm type as it is unknown at this point
+ out = (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception unwrapping private key - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] wrapKey(
+ String algorithm,
+ Key key,
+ PKCS12PBEParams pbeParams,
+ char[] password)
+ throws IOException
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+ byte[] out;
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(
+ algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+
+ cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), defParams);
+
+ out = cipher.wrap(key);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception encrypting data - " + e.toString());
+ }
+
+ return out;
+ }
+
+ protected byte[] cryptData(
+ boolean forEncryption,
+ AlgorithmIdentifier algId,
+ char[] password,
+ boolean wrongPKCS12Zero,
+ byte[] data)
+ throws IOException
+ {
+ String algorithm = algId.getAlgorithm().getId();
+ PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters());
+ PBEKeySpec pbeSpec = new PBEKeySpec(password);
+
+ try
+ {
+ SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, bcProvider);
+ PBEParameterSpec defParams = new PBEParameterSpec(
+ pbeParams.getIV(),
+ pbeParams.getIterations().intValue());
+ BCPBEKey key = (BCPBEKey) keyFact.generateSecret(pbeSpec);
+
+ key.setTryWrongPKCS12Zero(wrongPKCS12Zero);
+
+ Cipher cipher = Cipher.getInstance(algorithm, bcProvider);
+ int mode = forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+ cipher.init(mode, key, defParams);
+ return cipher.doFinal(data);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decrypting data - " + e.toString());
+ }
+ }
+
+ public void engineLoad(
+ InputStream stream,
+ char[] password)
+ throws IOException
+ {
+ if (stream == null) // just initialising
+ {
+ return;
+ }
+
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ BufferedInputStream bufIn = new BufferedInputStream(stream);
+
+ bufIn.mark(10);
+
+ int head = bufIn.read();
+
+ if (head != 0x30)
+ {
+ throw new IOException("stream does not represent a PKCS12 key store");
+ }
+
+ bufIn.reset();
+
+ ASN1InputStream bIn = new ASN1InputStream(bufIn);
+ ASN1Sequence obj = (ASN1Sequence)bIn.readObject();
+ Pfx bag = Pfx.getInstance(obj);
+ ContentInfo info = bag.getAuthSafe();
+ Vector chain = new Vector();
+ boolean unmarkedKey = false;
+ boolean wrongPKCS12Zero = false;
+
+ if (bag.getMacData() != null) // check the mac code
+ {
+ MacData mData = bag.getMacData();
+ DigestInfo dInfo = mData.getMac();
+ AlgorithmIdentifier algId = dInfo.getAlgorithmId();
+ byte[] salt = mData.getSalt();
+ int itCount = mData.getIterationCount().intValue();
+
+ byte[] data = ((ASN1OctetString)info.getContent()).getOctets();
+
+ try
+ {
+ byte[] res = calculatePbeMac(algId.getObjectId(), salt, itCount, password, false, data);
+ byte[] dig = dInfo.getDigest();
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ if (password.length > 0)
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ // Try with incorrect zero length password
+ res = calculatePbeMac(algId.getObjectId(), salt, itCount, password, true, data);
+
+ if (!Arrays.constantTimeAreEqual(res, dig))
+ {
+ throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file.");
+ }
+
+ wrongPKCS12Zero = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+ }
+
+ keys = new IgnoresCaseHashtable();
+ localIds = new Hashtable();
+
+ if (info.getContentType().equals(data))
+ {
+ bIn = new ASN1InputStream(((ASN1OctetString)info.getContent()).getOctets());
+
+ AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(bIn.readObject());
+ ContentInfo[] c = authSafe.getContentInfo();
+
+ for (int i = 0; i != c.length; i++)
+ {
+ if (c[i].getContentType().equals(data))
+ {
+ ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets());
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+ if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ 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);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // 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(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 (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ unmarkedKey = true;
+ keys.put("unmarked", privKey);
+ }
+ }
+ else if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else
+ {
+ System.out.println("extra in data " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else if (c[i].getContentType().equals(encryptedData))
+ {
+ EncryptedData d = EncryptedData.getInstance(c[i].getContent());
+ byte[] octets = cryptData(false, d.getEncryptionAlgorithm(),
+ password, wrongPKCS12Zero, d.getContent().getOctets());
+ ASN1Sequence seq = (ASN1Sequence) ASN1Primitive.fromByteArray(octets);
+
+ for (int j = 0; j != seq.size(); j++)
+ {
+ SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
+
+ if (b.getBagId().equals(certBag))
+ {
+ chain.addElement(b);
+ }
+ else if (b.getBagId().equals(pkcs8ShroudedKeyBag))
+ {
+ org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo eIn = org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo.getInstance(b.getBagValue());
+ PrivateKey privKey = unwrapKey(eIn.getEncryptionAlgorithm(), eIn.getEncryptedData(), password, wrongPKCS12Zero);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ 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);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // 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(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;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else if (b.getBagId().equals(keyBag))
+ {
+ org.bouncycastle.asn1.pkcs.PrivateKeyInfo kInfo = new org.bouncycastle.asn1.pkcs.PrivateKeyInfo((ASN1Sequence)b.getBagValue());
+ PrivateKey privKey = BouncyCastleProvider.getPrivateKey(kInfo);
+
+ //
+ // set the attributes on the key
+ //
+ PKCS12BagAttributeCarrier bagAttr = (PKCS12BagAttributeCarrier)privKey;
+ String alias = null;
+ ASN1OctetString localId = null;
+
+ 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);
+ ASN1Primitive attr = null;
+
+ if (attrSet.size() > 0)
+ {
+ attr = (ASN1Primitive)attrSet.getObjectAt(0);
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(aOid);
+ if (existing != null)
+ {
+ // 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(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;
+ }
+ }
+
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ if (alias == null)
+ {
+ keys.put(name, privKey);
+ }
+ else
+ {
+ localIds.put(alias, name);
+ }
+ }
+ else
+ {
+ System.out.println("extra in encryptedData " + b.getBagId());
+ System.out.println(ASN1Dump.dumpAsString(b));
+ }
+ }
+ }
+ else
+ {
+ System.out.println("extra " + c[i].getContentType().getId());
+ System.out.println("extra " + ASN1Dump.dumpAsString(c[i].getContent()));
+ }
+ }
+ }
+
+ certs = new IgnoresCaseHashtable();
+ chainCerts = new Hashtable();
+ keyCerts = new Hashtable();
+
+ for (int i = 0; i != chain.size(); i++)
+ {
+ SafeBag b = (SafeBag)chain.elementAt(i);
+ CertBag cb = CertBag.getInstance(b.getBagValue());
+
+ if (!cb.getCertId().equals(x509Certificate))
+ {
+ throw new RuntimeException("Unsupported certificate type: " + cb.getCertId());
+ }
+
+ Certificate cert;
+
+ try
+ {
+ ByteArrayInputStream cIn = new ByteArrayInputStream(
+ ((ASN1OctetString)cb.getCertValue()).getOctets());
+ cert = certFact.generateCertificate(cIn);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.toString());
+ }
+
+ //
+ // set the attributes
+ //
+ ASN1OctetString localId = null;
+ String alias = null;
+
+ if (b.getBagAttributes() != null)
+ {
+ 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;
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ bagAttr = (PKCS12BagAttributeCarrier)cert;
+
+ ASN1Encodable existing = bagAttr.getBagAttribute(oid);
+ if (existing != null)
+ {
+ // 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);
+ }
+ }
+
+ if (oid.equals(pkcs_9_at_friendlyName))
+ {
+ alias = ((DERBMPString)attr).getString();
+ }
+ else if (oid.equals(pkcs_9_at_localKeyId))
+ {
+ localId = (ASN1OctetString)attr;
+ }
+ }
+ }
+
+ chainCerts.put(new CertId(cert.getPublicKey()), cert);
+
+ if (unmarkedKey)
+ {
+ if (keyCerts.isEmpty())
+ {
+ String name = new String(Hex.encode(createSubjectKeyId(cert.getPublicKey()).getKeyIdentifier()));
+
+ keyCerts.put(name, cert);
+ keys.put(name, keys.remove("unmarked"));
+ }
+ }
+ else
+ {
+ //
+ // the local key id needs to override the friendly name
+ //
+ if (localId != null)
+ {
+ String name = new String(Hex.encode(localId.getOctets()));
+
+ keyCerts.put(name, cert);
+ }
+ if (alias != null)
+ {
+ certs.put(alias, cert);
+ }
+ }
+ }
+ }
+
+ public void engineStore(LoadStoreParameter param) throws IOException,
+ NoSuchAlgorithmException, CertificateException
+ {
+ if (param == null)
+ {
+ throw new IllegalArgumentException("'param' arg cannot be null");
+ }
+
+ if (!(param instanceof JDKPKCS12StoreParameter))
+ {
+ throw new IllegalArgumentException(
+ "No support for 'param' of type " + param.getClass().getName());
+ }
+
+ JDKPKCS12StoreParameter bcParam = (JDKPKCS12StoreParameter)param;
+
+ char[] password;
+ ProtectionParameter protParam = param.getProtectionParameter();
+ if (protParam == null)
+ {
+ password = null;
+ }
+ else if (protParam instanceof KeyStore.PasswordProtection)
+ {
+ password = ((KeyStore.PasswordProtection)protParam).getPassword();
+ }
+ else
+ {
+ throw new IllegalArgumentException(
+ "No support for protection parameter of type " + protParam.getClass().getName());
+ }
+
+ doStore(bcParam.getOutputStream(), password, bcParam.isUseDEREncoding());
+ }
+
+ public void engineStore(OutputStream stream, char[] password)
+ throws IOException
+ {
+ doStore(stream, password, false);
+ }
+
+ private void doStore(OutputStream stream, char[] password, boolean useDEREncoding)
+ throws IOException
+ {
+ if (password == null)
+ {
+ throw new NullPointerException("No password supplied for PKCS#12 KeyStore.");
+ }
+
+ //
+ // handle the key
+ //
+ ASN1EncodableVector keyS = new ASN1EncodableVector();
+
+
+ Enumeration ks = keys.keys();
+
+ while (ks.hasMoreElements())
+ {
+ byte[] kSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(kSalt);
+
+ String name = (String)ks.nextElement();
+ PrivateKey privKey = (PrivateKey)keys.get(name);
+ PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+ byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
+ AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
+ org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
+ boolean attrSet = false;
+ ASN1EncodableVector kName = new ASN1EncodableVector();
+
+ if (privKey instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)privKey;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ Certificate ct = engineGetCertificate(name);
+
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(ct.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+
+ kSeq.add(oid);
+ kSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+
+ attrSet = true;
+
+ kName.add(new DERSequence(kSeq));
+ }
+ }
+
+ if (!attrSet)
+ {
+ //
+ // set a default friendly name (from the key id) and local id
+ //
+ ASN1EncodableVector kSeq = new ASN1EncodableVector();
+ Certificate ct = engineGetCertificate(name);
+
+ kSeq.add(pkcs_9_at_localKeyId);
+ kSeq.add(new DERSet(createSubjectKeyId(ct.getPublicKey())));
+
+ kName.add(new DERSequence(kSeq));
+
+ kSeq = new ASN1EncodableVector();
+
+ kSeq.add(pkcs_9_at_friendlyName);
+ kSeq.add(new DERSet(new DERBMPString(name)));
+
+ kName.add(new DERSequence(kSeq));
+ }
+
+ SafeBag kBag = new SafeBag(pkcs8ShroudedKeyBag, kInfo.toASN1Primitive(), new DERSet(kName));
+ keyS.add(kBag);
+ }
+
+ byte[] keySEncoded = new DERSequence(keyS).getEncoded(ASN1Encoding.DER);
+ BERConstructedOctetString keyString = new BERConstructedOctetString(keySEncoded);
+
+ //
+ // certificate processing
+ //
+ byte[] cSalt = new byte[SALT_SIZE];
+
+ random.nextBytes(cSalt);
+
+ ASN1EncodableVector certSeq = new ASN1EncodableVector();
+ PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+ AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
+ Hashtable doneCerts = new Hashtable();
+
+ Enumeration cs = keys.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String name = (String)cs.nextElement();
+ Certificate cert = engineGetCertificate(name);
+ boolean cAttrSet = false;
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(name))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(name));
+ }
+
+ //
+ // make sure we have a local key-id
+ //
+ if (bagAttrs.getBagAttribute(pkcs_9_at_localKeyId) == null)
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_localKeyId, createSubjectKeyId(cert.getPublicKey()));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_localKeyId);
+ fSeq.add(new DERSet(createSubjectKeyId(cert.getPublicKey())));
+ fName.add(new DERSequence(fSeq));
+
+ fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(name)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = certs.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ String certId = (String)cs.nextElement();
+ Certificate cert = (Certificate)certs.get(certId);
+ boolean cAttrSet = false;
+
+ if (keys.get(certId) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ //
+ // make sure we are using the local alias on store
+ //
+ DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName);
+ if (nm == null || !nm.getString().equals(certId))
+ {
+ bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId));
+ }
+
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+
+ cAttrSet = true;
+ }
+ }
+
+ if (!cAttrSet)
+ {
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(pkcs_9_at_friendlyName);
+ fSeq.add(new DERSet(new DERBMPString(certId)));
+
+ fName.add(new DERSequence(fSeq));
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+
+ doneCerts.put(cert, cert);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ cs = chainCerts.keys();
+ while (cs.hasMoreElements())
+ {
+ try
+ {
+ CertId certId = (CertId)cs.nextElement();
+ Certificate cert = (Certificate)chainCerts.get(certId);
+
+ if (doneCerts.get(cert) != null)
+ {
+ continue;
+ }
+
+ CertBag cBag = new CertBag(
+ x509Certificate,
+ new DEROctetString(cert.getEncoded()));
+ ASN1EncodableVector fName = new ASN1EncodableVector();
+
+ if (cert instanceof PKCS12BagAttributeCarrier)
+ {
+ PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert;
+ Enumeration e = bagAttrs.getBagAttributeKeys();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+
+ // a certificate not immediately linked to a key doesn't require
+ // a localKeyID and will confuse some PKCS12 implementations.
+ //
+ // If we find one, we'll prune it out.
+ if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))
+ {
+ continue;
+ }
+
+ ASN1EncodableVector fSeq = new ASN1EncodableVector();
+
+ fSeq.add(oid);
+ fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid)));
+ fName.add(new DERSequence(fSeq));
+ }
+ }
+
+ SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName));
+
+ certSeq.add(sBag);
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new IOException("Error encoding certificate: " + e.toString());
+ }
+ }
+
+ byte[] certSeqEncoded = new DERSequence(certSeq).getEncoded(ASN1Encoding.DER);
+ byte[] certBytes = cryptData(true, cAlgId, password, false, certSeqEncoded);
+ EncryptedData cInfo = new EncryptedData(data, cAlgId, new BERConstructedOctetString(certBytes));
+
+ ContentInfo[] info = new ContentInfo[]
+ {
+ new ContentInfo(data, keyString),
+ new ContentInfo(encryptedData, cInfo.toASN1Primitive())
+ };
+
+ AuthenticatedSafe auth = new AuthenticatedSafe(info);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream asn1Out;
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(bOut);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(bOut);
+ }
+
+ asn1Out.writeObject(auth);
+
+ byte[] pkg = bOut.toByteArray();
+
+ ContentInfo mainInfo = new ContentInfo(data, new BERConstructedOctetString(pkg));
+
+ //
+ // create the mac
+ //
+ byte[] mSalt = new byte[20];
+ int itCount = MIN_ITERATIONS;
+
+ random.nextBytes(mSalt);
+
+ byte[] data = ((ASN1OctetString)mainInfo.getContent()).getOctets();
+
+ MacData mData;
+
+ try
+ {
+ byte[] res = calculatePbeMac(id_SHA1, mSalt, itCount, password, false, data);
+
+ // BEGIN android-changed
+ AlgorithmIdentifier algId = new AlgorithmIdentifier(id_SHA1, DERNull.INSTANCE);
+ // END android-changed
+ DigestInfo dInfo = new DigestInfo(algId, res);
+
+ mData = new MacData(dInfo, mSalt, itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
+
+ //
+ // output the Pfx
+ //
+ Pfx pfx = new Pfx(mainInfo, mData);
+
+ if (useDEREncoding)
+ {
+ asn1Out = new DEROutputStream(stream);
+ }
+ else
+ {
+ asn1Out = new BEROutputStream(stream);
+ }
+
+ asn1Out.writeObject(pfx);
+ }
+
+ private static byte[] calculatePbeMac(
+ ASN1ObjectIdentifier oid,
+ byte[] salt,
+ int itCount,
+ char[] password,
+ boolean wrongPkcs12Zero,
+ 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.update(data);
+ return mac.doFinal();
+ }
+
+ public static class BCPKCS12KeyStore
+ extends JDKPKCS12KeyStore
+ {
+ public BCPKCS12KeyStore()
+ {
+ super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ }
+ }
+
+ // BEGIN android-removed
+ // public static class BCPKCS12KeyStore3DES
+ // extends JDKPKCS12KeyStore
+ // {
+ // public BCPKCS12KeyStore3DES()
+ // {
+ // super(bcProvider, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ // }
+ // }
+ //
+ // public static class DefPKCS12KeyStore
+ // extends JDKPKCS12KeyStore
+ // {
+ // public DefPKCS12KeyStore()
+ // {
+ // super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC);
+ // }
+ // }
+ //
+ // public static class DefPKCS12KeyStore3DES
+ // extends JDKPKCS12KeyStore
+ // {
+ // public DefPKCS12KeyStore3DES()
+ // {
+ // super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC);
+ // }
+ // }
+ // END android-removed
+
+ private static class IgnoresCaseHashtable
+ {
+ private Hashtable orig = new Hashtable();
+ private Hashtable keys = new Hashtable();
+
+ public void put(String key, Object value)
+ {
+ // BEGIN android-changed
+ String lower = (key == null) ? null : Strings.toLowerCase(key);
+ // END android-changed
+ String k = (String)keys.get(lower);
+ if (k != null)
+ {
+ orig.remove(k);
+ }
+
+ keys.put(lower, key);
+ orig.put(key, value);
+ }
+
+ public Enumeration keys()
+ {
+ return orig.keys();
+ }
+
+ public Object remove(String alias)
+ {
+ // BEGIN android-changed
+ String k = (String)keys.remove(alias == null ? null : Strings.toLowerCase(alias));
+ // END android-changed
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.remove(k);
+ }
+
+ public Object get(String alias)
+ {
+ // BEGIN android-changed
+ String k = (String)keys.get(alias == null ? null : Strings.toLowerCase(alias));
+ // END android-changed
+ if (k == null)
+ {
+ return null;
+ }
+
+ return orig.get(k);
+ }
+
+ public Enumeration elements()
+ {
+ return orig.elements();
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java
new file mode 100644
index 0000000..865481f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/JDKPKCS12StoreParameter.java
@@ -0,0 +1,48 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.OutputStream;
+import java.security.KeyStore;
+import java.security.KeyStore.LoadStoreParameter;
+import java.security.KeyStore.ProtectionParameter;
+
+public class JDKPKCS12StoreParameter implements LoadStoreParameter
+{
+ private OutputStream outputStream;
+ private ProtectionParameter protectionParameter;
+ private boolean useDEREncoding;
+
+ public OutputStream getOutputStream()
+ {
+ return outputStream;
+ }
+
+ public ProtectionParameter getProtectionParameter()
+ {
+ return protectionParameter;
+ }
+
+ public boolean isUseDEREncoding()
+ {
+ return useDEREncoding;
+ }
+
+ public void setOutputStream(OutputStream outputStream)
+ {
+ this.outputStream = outputStream;
+ }
+
+ public void setPassword(char[] password)
+ {
+ this.protectionParameter = new KeyStore.PasswordProtection(password);
+ }
+
+ public void setProtectionParameter(ProtectionParameter protectionParameter)
+ {
+ this.protectionParameter = protectionParameter;
+ }
+
+ public void setUseDEREncoding(boolean useDEREncoding)
+ {
+ this.useDEREncoding = useDEREncoding;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PEMUtil.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PEMUtil.java
new file mode 100644
index 0000000..04718ef
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PEMUtil.java
@@ -0,0 +1,94 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.util.encoders.Base64;
+
+public class PEMUtil
+{
+ private final String _header1;
+ private final String _header2;
+ private final String _footer1;
+ private final String _footer2;
+
+ PEMUtil(
+ String type)
+ {
+ _header1 = "-----BEGIN " + type + "-----";
+ _header2 = "-----BEGIN X509 " + type + "-----";
+ _footer1 = "-----END " + type + "-----";
+ _footer2 = "-----END X509 " + type + "-----";
+ }
+
+ private String readLine(
+ InputStream in)
+ throws IOException
+ {
+ int c;
+ StringBuffer l = new StringBuffer();
+
+ do
+ {
+ while (((c = in.read()) != '\r') && c != '\n' && (c >= 0))
+ {
+ if (c == '\r')
+ {
+ continue;
+ }
+
+ l.append((char)c);
+ }
+ }
+ while (c >= 0 && l.length() == 0);
+
+ if (c < 0)
+ {
+ return null;
+ }
+
+ return l.toString();
+ }
+
+ ASN1Sequence readPEMObject(
+ InputStream in)
+ throws IOException
+ {
+ String line;
+ StringBuffer pemBuf = new StringBuffer();
+
+ while ((line = readLine(in)) != null)
+ {
+ if (line.startsWith(_header1) || line.startsWith(_header2))
+ {
+ break;
+ }
+ }
+
+ while ((line = readLine(in)) != null)
+ {
+ if (line.startsWith(_footer1) || line.startsWith(_footer2))
+ {
+ break;
+ }
+
+ pemBuf.append(line);
+ }
+
+ if (pemBuf.length() != 0)
+ {
+ ASN1Primitive o = new ASN1InputStream(Base64.decode(pemBuf.toString())).readObject();
+ if (!(o instanceof ASN1Sequence))
+ {
+ throw new IOException("malformed PEM data encountered");
+ }
+
+ return (ASN1Sequence)o;
+ }
+
+ return null;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java
new file mode 100644
index 0000000..c94016d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCRLUtil.java
@@ -0,0 +1,155 @@
+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;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.bouncycastle.util.StoreException;
+import org.bouncycastle.x509.ExtendedPKIXParameters;
+import org.bouncycastle.x509.X509CRLStoreSelector;
+import org.bouncycastle.x509.X509Store;
+
+public class PKIXCRLUtil
+{
+ public Set findCRLs(X509CRLStoreSelector crlselect, ExtendedPKIXParameters paramsPKIX, Date currentDate)
+ throws AnnotatedException
+ {
+ Set initialSet = new HashSet();
+
+ // get complete CRL(s)
+ try
+ {
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getAdditionalStores()));
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getStores()));
+ initialSet.addAll(findCRLs(crlselect, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining complete CRLs.", e);
+ }
+
+ 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();)
+ {
+ X509CRL crl = (X509CRL)it.next();
+
+ if (crl.getNextUpdate().after(validityDate))
+ {
+ X509Certificate cert = crlselect.getCertificateChecking();
+
+ if (cert != null)
+ {
+ if (crl.getThisUpdate().before(cert.getNotAfter()))
+ {
+ finalSet.add(crl);
+ }
+ }
+ else
+ {
+ finalSet.add(crl);
+ }
+ }
+ }
+
+ 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
+ * to select the CRLs
+ * @param crlStores a List containing only
+ * {@link org.bouncycastle.x509.X509Store X509Store} 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 <code>null</code>.
+ */
+ private final Collection findCRLs(X509CRLStoreSelector crlSelect,
+ List crlStores) throws AnnotatedException
+ {
+ Set crls = new HashSet();
+ Iterator iter = crlStores.iterator();
+
+ AnnotatedException lastException = null;
+ boolean foundValidStore = false;
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (obj instanceof X509Store)
+ {
+ X509Store store = (X509Store)obj;
+
+ try
+ {
+ crls.addAll(store.getMatches(crlSelect));
+ foundValidStore = true;
+ }
+ catch (StoreException e)
+ {
+ lastException = new AnnotatedException(
+ "Exception searching in X.509 CRL store.", e);
+ }
+ }
+ else
+ {
+ CertStore store = (CertStore)obj;
+
+ try
+ {
+ crls.addAll(store.getCRLs(crlSelect));
+ foundValidStore = true;
+ }
+ catch (CertStoreException e)
+ {
+ lastException = new AnnotatedException(
+ "Exception searching in X.509 CRL store.", e);
+ }
+ }
+ }
+ if (!foundValidStore && lastException != null)
+ {
+ throw lastException;
+ }
+ return crls;
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
new file mode 100644
index 0000000..384eb86
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java
@@ -0,0 +1,261 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertPath;
+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;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+
+import org.bouncycastle.jce.exception.ExtCertPathBuilderException;
+import org.bouncycastle.util.Selector;
+import org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
+import org.bouncycastle.x509.X509CertStoreSelector;
+
+/**
+ * Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
+ *
+ * @see CertPathBuilderSpi
+ */
+public class PKIXCertPathBuilderSpi
+ extends CertPathBuilderSpi
+{
+ /**
+ * Build and validate a CertPath using the given parameter.
+ *
+ * @param params PKIXBuilderParameters object containing all information to
+ * build the CertPath
+ */
+ public CertPathBuilderResult engineBuild(CertPathParameters params)
+ throws CertPathBuilderException, InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXBuilderParameters)
+ && !(params instanceof ExtendedPKIXBuilderParameters))
+ {
+ throw new InvalidAlgorithmParameterException(
+ "Parameters must be an instance of "
+ + PKIXBuilderParameters.class.getName() + " or "
+ + ExtendedPKIXBuilderParameters.class.getName() + ".");
+ }
+
+ ExtendedPKIXBuilderParameters pkixParams = null;
+ if (params instanceof ExtendedPKIXBuilderParameters)
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) params;
+ }
+ else
+ {
+ pkixParams = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters
+ .getInstance((PKIXBuilderParameters) params);
+ }
+
+ Collection targets;
+ Iterator targetIter;
+ List certPathList = new ArrayList();
+ X509Certificate cert;
+
+ // 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.");
+ }
+
+ try
+ {
+ targets = CertPathValidatorUtilities.findCertificates((X509CertStoreSelector)certSelect, pkixParams.getStores());
+ targets.addAll(CertPathValidatorUtilities.findCertificates((X509CertStoreSelector)certSelect, pkixParams.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathBuilderException(
+ "Error finding target certificate.", e);
+ }
+
+ if (targets.isEmpty())
+ {
+
+ throw new CertPathBuilderException(
+ "No certificate found matching targetContraints.");
+ }
+
+ CertPathBuilderResult result = null;
+
+ // check all potential target certificates
+ targetIter = targets.iterator();
+ while (targetIter.hasNext() && result == null)
+ {
+ cert = (X509Certificate) targetIter.next();
+ result = build(cert, pkixParams, certPathList);
+ }
+
+ if (result == null && certPathException != null)
+ {
+ if (certPathException instanceof AnnotatedException)
+ {
+ throw new CertPathBuilderException(certPathException.getMessage(), certPathException.getCause());
+ }
+ throw new CertPathBuilderException(
+ "Possible certificate chain could not be validated.",
+ certPathException);
+ }
+
+ if (result == null && certPathException == null)
+ {
+ throw new CertPathBuilderException(
+ "Unable to find certificate chain.");
+ }
+
+ return result;
+ }
+
+ private Exception certPathException;
+
+ protected CertPathBuilderResult build(X509Certificate tbvCert,
+ ExtendedPKIXBuilderParameters pkixParams, List tbvPath)
+ {
+ // If tbvCert is readily present in tbvPath, it indicates having run
+ // into a cycle in the
+ // PKI graph.
+ if (tbvPath.contains(tbvCert))
+ {
+ return null;
+ }
+ // step out, the certificate is not allowed to appear in a certification
+ // chain.
+ if (pkixParams.getExcludedCerts().contains(tbvCert))
+ {
+ return null;
+ }
+ // test if certificate path exceeds maximum length
+ if (pkixParams.getMaxPathLength() != -1)
+ {
+ if (tbvPath.size() - 1 > pkixParams.getMaxPathLength())
+ {
+ return null;
+ }
+ }
+
+ tbvPath.add(tbvCert);
+
+ CertificateFactory cFact;
+ CertPathValidator validator;
+ CertPathBuilderResult builderResult = null;
+
+ try
+ {
+ cFact = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
+ validator = CertPathValidator.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException("Exception creating support classes.");
+ }
+
+ try
+ {
+ // check whether the issuer of <tbvCert> is a TrustAnchor
+ if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getTrustAnchors(),
+ pkixParams.getSigProvider()) != null)
+ {
+ // exception message from possibly later tried certification
+ // chains
+ CertPath certPath = null;
+ PKIXCertPathValidatorResult result = null;
+ try
+ {
+ certPath = cFact.generateCertPath(tbvPath);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Certification path could not be constructed from certificate list.",
+ e);
+ }
+
+ try
+ {
+ result = (PKIXCertPathValidatorResult) validator.validate(
+ certPath, pkixParams);
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Certification path could not be validated.", e);
+ }
+
+ return new PKIXCertPathBuilderResult(certPath, result
+ .getTrustAnchor(), result.getPolicyTree(), result
+ .getPublicKey());
+
+ }
+ else
+ {
+ // add additional X.509 stores from locations in certificate
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromAltNames(
+ tbvCert, pkixParams);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new AnnotatedException(
+ "No additiontal X.509 stores can be added from certificate locations.",
+ e);
+ }
+ Collection issuers = new HashSet();
+ // try to get the issuer certificate from one
+ // of the stores
+ try
+ {
+ issuers.addAll(CertPathValidatorUtilities.findIssuerCerts(tbvCert, pkixParams));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Cannot find issuer certificate for certificate in certification path.",
+ e);
+ }
+ if (issuers.isEmpty())
+ {
+ throw new AnnotatedException(
+ "No issuer certificate for certificate in certification path found.");
+ }
+ Iterator it = issuers.iterator();
+
+ while (it.hasNext() && builderResult == null)
+ {
+ X509Certificate issuer = (X509Certificate) it.next();
+ builderResult = build(issuer, pkixParams, tbvPath);
+ }
+ }
+ }
+ catch (AnnotatedException e)
+ {
+ certPathException = e;
+ }
+ if (builderResult == null)
+ {
+ tbvPath.remove(tbvCert);
+ }
+ return builderResult;
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
new file mode 100644
index 0000000..af764f3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java
@@ -0,0 +1,462 @@
+package org.bouncycastle.jce.provider;
+
+// BEGIN android-added
+import java.math.BigInteger;
+// END android-added
+import java.security.InvalidAlgorithmParameterException;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathParameters;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorResult;
+import java.security.cert.CertPathValidatorSpi;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXCertPathValidatorResult;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashSet;
+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.x509.AlgorithmIdentifier;
+import org.bouncycastle.jce.exception.ExtCertPathValidatorException;
+import org.bouncycastle.x509.ExtendedPKIXParameters;
+
+/**
+ * CertPathValidatorSpi implementation for X.509 Certificate validation � la RFC
+ * 3280.
+ */
+public class PKIXCertPathValidatorSpi
+ extends CertPathValidatorSpi
+{
+ // BEGIN android-added
+ private final static CertBlacklist blacklist = new CertBlacklist();
+ // END android-added
+
+ public CertPathValidatorResult engineValidate(
+ CertPath certPath,
+ CertPathParameters params)
+ throws CertPathValidatorException,
+ InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PKIXParameters))
+ {
+ throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName()
+ + " instance.");
+ }
+
+ ExtendedPKIXParameters paramsPKIX;
+ if (params instanceof ExtendedPKIXParameters)
+ {
+ paramsPKIX = (ExtendedPKIXParameters)params;
+ }
+ else
+ {
+ paramsPKIX = ExtendedPKIXParameters.getInstance((PKIXParameters)params);
+ }
+ if (paramsPKIX.getTrustAnchors() == null)
+ {
+ throw new InvalidAlgorithmParameterException(
+ "trustAnchors is null, this is not allowed for certification path validation.");
+ }
+
+ //
+ // 6.1.1 - inputs
+ //
+
+ //
+ // (a)
+ //
+ List certs = certPath.getCertificates();
+ int n = certs.size();
+
+ if (certs.isEmpty())
+ {
+ throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0);
+ }
+ // BEGIN android-added
+ {
+ X509Certificate cert = (X509Certificate) certs.get(0);
+
+ if (cert != null) {
+ BigInteger serial = cert.getSerialNumber();
+ if (blacklist.isSerialNumberBlackListed(serial)) {
+ // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs
+ String message = "Certificate revocation of serial 0x" + serial.toString(16);
+ System.out.println(message);
+ AnnotatedException e = new AnnotatedException(message);
+ throw new CertPathValidatorException(e.getMessage(), e, certPath, 0);
+ }
+ }
+ }
+ // END android-added
+
+ //
+ // (b)
+ //
+ // Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX);
+
+ //
+ // (c)
+ //
+ Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
+
+ //
+ // (d)
+ //
+ TrustAnchor trust;
+ try
+ {
+ trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
+ paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e, certPath, certs.size() - 1);
+ }
+
+ if (trust == null)
+ {
+ throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
+ }
+
+ //
+ // (e), (f), (g) are part of the paramsPKIX object.
+ //
+ Iterator certIter;
+ int index = 0;
+ int i;
+ // Certificate for each interation of the validation loop
+ // Signature information for each iteration of the validation loop
+ //
+ // 6.1.2 - setup
+ //
+
+ //
+ // (a)
+ //
+ List[] policyNodes = new ArrayList[n + 1];
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ Set policySet = new HashSet();
+
+ policySet.add(RFC3280CertPathUtilities.ANY_POLICY);
+
+ PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(),
+ RFC3280CertPathUtilities.ANY_POLICY, false);
+
+ policyNodes[0].add(validPolicyTree);
+
+ //
+ // (b) and (c)
+ //
+ PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator();
+
+ // (d)
+ //
+ int explicitPolicy;
+ Set acceptablePolicies = new HashSet();
+
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = n + 1;
+ }
+
+ //
+ // (e)
+ //
+ int inhibitAnyPolicy;
+
+ if (paramsPKIX.isAnyPolicyInhibited())
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = n + 1;
+ }
+
+ //
+ // (f)
+ //
+ int policyMapping;
+
+ if (paramsPKIX.isPolicyMappingInhibited())
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = n + 1;
+ }
+
+ //
+ // (g), (h), (i), (j)
+ //
+ PublicKey workingPublicKey;
+ X500Principal workingIssuerName;
+
+ X509Certificate sign = trust.getTrustedCert();
+ try
+ {
+ if (sign != null)
+ {
+ workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+ workingPublicKey = sign.getPublicKey();
+ }
+ else
+ {
+ workingIssuerName = new X500Principal(trust.getCAName());
+ workingPublicKey = trust.getCAPublicKey();
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
+ -1);
+ }
+
+ AlgorithmIdentifier workingAlgId = null;
+ try
+ {
+ workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
+ }
+ DERObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters();
+
+ //
+ // (k)
+ //
+ int maxPathLength = n;
+
+ //
+ // 6.1.3
+ //
+
+ if (paramsPKIX.getTargetConstraints() != null
+ && !paramsPKIX.getTargetConstraints().match((X509Certificate) certs.get(0)))
+ {
+ throw new ExtCertPathValidatorException(
+ "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
+ }
+
+ //
+ // initialize CertPathChecker's
+ //
+ List pathCheckers = paramsPKIX.getCertPathCheckers();
+ certIter = pathCheckers.iterator();
+ while (certIter.hasNext())
+ {
+ ((PKIXCertPathChecker) certIter.next()).init(false);
+ }
+
+ X509Certificate cert = null;
+
+ for (index = certs.size() - 1; index >= 0; index--)
+ {
+ // BEGIN android-added
+ if (blacklist.isPublicKeyBlackListed(workingPublicKey)) {
+ // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs
+ String message = "Certificate revocation of public key " + workingPublicKey;
+ System.out.println(message);
+ AnnotatedException e = new AnnotatedException(message);
+ throw new CertPathValidatorException(e.getMessage(), e, certPath, index);
+ }
+ // END android-added
+ // try
+ // {
+ //
+ // i as defined in the algorithm description
+ //
+ i = n - index;
+
+ //
+ // set certificate to be checked in this round
+ // sign and workingPublicKey and workingIssuerName are set
+ // at the end of the for loop and initialized the
+ // first time from the TrustAnchor
+ //
+ cert = (X509Certificate) certs.get(index);
+ boolean verificationAlreadyPerformed = (index == certs.size() - 1);
+
+ //
+ // 6.1.3
+ //
+
+ RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey,
+ verificationAlreadyPerformed, workingIssuerName, sign);
+
+ RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator);
+
+ validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies,
+ validPolicyTree, policyNodes, inhibitAnyPolicy);
+
+ validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree);
+
+ RFC3280CertPathUtilities.processCertF(certPath, index, validPolicyTree, explicitPolicy);
+
+ //
+ // 6.1.4
+ //
+
+ if (i != n)
+ {
+ if (cert != null && cert.getVersion() == 1)
+ {
+ throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null,
+ certPath, index);
+ }
+
+ RFC3280CertPathUtilities.prepareNextCertA(certPath, index);
+
+ validPolicyTree = RFC3280CertPathUtilities.prepareCertB(certPath, index, policyNodes, validPolicyTree,
+ policyMapping);
+
+ RFC3280CertPathUtilities.prepareNextCertG(certPath, index, nameConstraintValidator);
+
+ // (h)
+ explicitPolicy = RFC3280CertPathUtilities.prepareNextCertH1(certPath, index, explicitPolicy);
+ policyMapping = RFC3280CertPathUtilities.prepareNextCertH2(certPath, index, policyMapping);
+ inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertH3(certPath, index, inhibitAnyPolicy);
+
+ //
+ // (i)
+ //
+ explicitPolicy = RFC3280CertPathUtilities.prepareNextCertI1(certPath, index, explicitPolicy);
+ policyMapping = RFC3280CertPathUtilities.prepareNextCertI2(certPath, index, policyMapping);
+
+ // (j)
+ inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy);
+
+ // (k)
+ RFC3280CertPathUtilities.prepareNextCertK(certPath, index);
+
+ // (l)
+ maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength);
+
+ // (m)
+ maxPathLength = RFC3280CertPathUtilities.prepareNextCertM(certPath, index, maxPathLength);
+
+ // (n)
+ RFC3280CertPathUtilities.prepareNextCertN(certPath, index);
+
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+
+ // these extensions are handled by the algorithm
+ criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ // (o)
+ RFC3280CertPathUtilities.prepareNextCertO(certPath, index, criticalExtensions, pathCheckers);
+
+ // set signing certificate for next round
+ sign = cert;
+
+ // (c)
+ workingIssuerName = CertPathValidatorUtilities.getSubjectPrincipal(sign);
+
+ // (d)
+ try
+ {
+ workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
+ }
+
+ workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
+ // (f)
+ workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ // (e)
+ workingPublicKeyParameters = workingAlgId.getParameters();
+ }
+ }
+
+ //
+ // 6.1.5 Wrap-up procedure
+ //
+
+ explicitPolicy = RFC3280CertPathUtilities.wrapupCertA(explicitPolicy, cert);
+
+ explicitPolicy = RFC3280CertPathUtilities.wrapupCertB(certPath, index + 1, explicitPolicy);
+
+ //
+ // (c) (d) and (e) are already done
+ //
+
+ //
+ // (f)
+ //
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ // these extensions are handled by the algorithm
+ criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
+ criticalExtensions.remove(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS);
+ }
+ else
+ {
+ criticalExtensions = new HashSet();
+ }
+
+ RFC3280CertPathUtilities.wrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions);
+
+ PKIXPolicyNode intersection = RFC3280CertPathUtilities.wrapupCertG(certPath, paramsPKIX, userInitialPolicySet,
+ index + 1, policyNodes, validPolicyTree, acceptablePolicies);
+
+ if ((explicitPolicy > 0) || (intersection != null))
+ {
+ return new PKIXCertPathValidatorResult(trust, intersection, cert.getPublicKey());
+ }
+
+ throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index);
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
new file mode 100644
index 0000000..ddf7462
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java
@@ -0,0 +1,1924 @@
+package org.bouncycastle.jce.provider;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+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.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralSubtree;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+
+public class PKIXNameConstraintValidator
+{
+ 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()
+ {
+ }
+
+ 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;
+ }
+
+ public void checkPermittedDN(ASN1Sequence dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ checkPermittedDN(permittedSubtreesDN, dns);
+ }
+
+ public void checkExcludedDN(ASN1Sequence dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ checkExcludedDN(excludedSubtreesDN, dns);
+ }
+
+ private void checkPermittedDN(Set permitted, ASN1Sequence dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ 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 PKIXNameConstraintValidatorException(
+ "Subject distinguished name is not from a permitted subtree");
+ }
+
+ private void checkExcludedDN(Set excluded, ASN1Sequence dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ ASN1Sequence subtree = (ASN1Sequence)it.next();
+
+ if (withinDNSubtree(dns, subtree))
+ {
+ throw new PKIXNameConstraintValidatorException(
+ "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
+ * <code>permitted</code> with <code>ip</code>.
+ *
+ * @param permitted A <code>Set</code> of permitted IP addresses with
+ * their subnet mask as byte arrays.
+ * @param ips The IP address with its subnet mask.
+ * @return The <code>Set</code> of permitted IP ranges intersected with
+ * <code>ip</code>.
+ */
+ 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 <code>excluded</code>
+ * with <code>ip</code>.
+ *
+ * @param excluded A <code>Set</code> of excluded IP addresses with their
+ * subnet mask as byte arrays.
+ * @param ip The IP address with its subnet mask.
+ * @return The <code>Set</code> of excluded IP ranges unified with
+ * <code>ip</code> 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 <code>Set</code> 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 <code>Set</code> with the single IP address with its subnet
+ * mask as a byte array or an empty <code>Set</code>.
+ */
+ 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 PKIXNameConstraintValidatorException
+ {
+ 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 PKIXNameConstraintValidatorException(
+ "Subject email address is not from a permitted subtree.");
+ }
+
+ private void checkExcludedEmail(Set excluded, String email)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ String str = (String)it.next();
+
+ if (emailIsConstrained(email, str))
+ {
+ throw new PKIXNameConstraintValidatorException(
+ "Email address is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * Checks if the IP <code>ip</code> is included in the permitted set
+ * <code>permitted</code>.
+ *
+ * @param permitted A <code>Set</code> of permitted IP addresses with
+ * their subnet mask as byte arrays.
+ * @param ip The IP address.
+ * @throws PKIXNameConstraintValidatorException
+ * if the IP is not permitted.
+ */
+ private void checkPermittedIP(Set permitted, byte[] ip)
+ throws PKIXNameConstraintValidatorException
+ {
+ 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 PKIXNameConstraintValidatorException(
+ "IP is not from a permitted subtree.");
+ }
+
+ /**
+ * Checks if the IP <code>ip</code> is included in the excluded set
+ * <code>excluded</code>.
+ *
+ * @param excluded A <code>Set</code> of excluded IP addresses with their
+ * subnet mask as byte arrays.
+ * @param ip The IP address.
+ * @throws PKIXNameConstraintValidatorException
+ * if the IP is excluded.
+ */
+ private void checkExcludedIP(Set excluded, byte[] ip)
+ throws PKIXNameConstraintValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ byte[] ipWithSubnet = (byte[])it.next();
+
+ if (isIPConstrained(ip, ipWithSubnet))
+ {
+ throw new PKIXNameConstraintValidatorException(
+ "IP is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * Checks if the IP address <code>ip</code> is constrained by
+ * <code>constraint</code>.
+ *
+ * @param ip The IP address.
+ * @param constraint The constraint. This is an IP address concatenated with
+ * its subnetmask.
+ * @return <code>true</code> if constrained, <code>false</code>
+ * 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 PKIXNameConstraintValidatorException
+ {
+ 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 PKIXNameConstraintValidatorException(
+ "DNS is not from a permitted subtree.");
+ }
+
+ private void checkExcludedDNS(Set excluded, String dns)
+ throws PKIXNameConstraintValidatorException
+ {
+ 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 PKIXNameConstraintValidatorException(
+ "DNS is from an excluded subtree.");
+ }
+ }
+ }
+
+ /**
+ * The common part of <code>email1</code> and <code>email2</code> is
+ * added to the union <code>union</code>. If <code>email1</code> and
+ * <code>email2</code> 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;
+ }
+
+ protected 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 <code>email1</code> and
+ * <code>email2</code> is added to the intersection <code>intersect</code>.
+ *
+ * @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 PKIXNameConstraintValidatorException
+ {
+ if (excluded.isEmpty())
+ {
+ return;
+ }
+
+ Iterator it = excluded.iterator();
+
+ while (it.hasNext())
+ {
+ String str = ((String)it.next());
+
+ if (isUriConstrained(uri, str))
+ {
+ throw new PKIXNameConstraintValidatorException(
+ "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 PKIXNameConstraintValidatorException
+ {
+ 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 PKIXNameConstraintValidatorException(
+ "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;
+ }
+
+ /**
+ * Checks if the given GeneralName is in the permitted set.
+ *
+ * @param name The GeneralName
+ * @throws PKIXNameConstraintValidatorException
+ * If the <code>name</code>
+ */
+ public void checkPermitted(GeneralName name)
+ throws PKIXNameConstraintValidatorException
+ {
+ switch (name.getTagNo())
+ {
+ case 1:
+ checkPermittedEmail(permittedSubtreesEmail,
+ extractNameAsString(name));
+ break;
+ case 2:
+ checkPermittedDNS(permittedSubtreesDNS, DERIA5String.getInstance(
+ name.getName()).getString());
+ break;
+ case 4:
+ checkPermittedDN(ASN1Sequence.getInstance(name.getName()
+ .toASN1Primitive()));
+ break;
+ case 6:
+ checkPermittedURI(permittedSubtreesURI, DERIA5String.getInstance(
+ name.getName()).getString());
+ break;
+ case 7:
+ 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 PKIXNameConstraintValidatorException
+ * If the <code>name</code> is
+ * excluded.
+ */
+ public void checkExcluded(GeneralName name)
+ throws PKIXNameConstraintValidatorException
+ {
+ switch (name.getTagNo())
+ {
+ case 1:
+ checkExcludedEmail(excludedSubtreesEmail, extractNameAsString(name));
+ break;
+ case 2:
+ checkExcludedDNS(excludedSubtreesDNS, DERIA5String.getInstance(
+ name.getName()).getString());
+ break;
+ case 4:
+ checkExcludedDN(ASN1Sequence.getInstance(name.getName()
+ .toASN1Primitive()));
+ break;
+ case 6:
+ checkExcludedURI(excludedSubtreesURI, DERIA5String.getInstance(
+ name.getName()).getString());
+ break;
+ case 7:
+ byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
+
+ checkExcludedIP(excludedSubtreesIP, ip);
+ }
+ }
+
+ /**
+ * Updates the permitted set of these name constraints with the intersection
+ * with the given subtree.
+ *
+ * @param permitted The permitted subtrees
+ */
+
+ public void intersectPermittedSubtree(ASN1Sequence permitted)
+ {
+ Map subtreesMap = new HashMap();
+
+ // group in sets in a map ordered by tag no.
+ for (Enumeration e = permitted.getObjects(); e.hasMoreElements();)
+ {
+ GeneralSubtree subtree = GeneralSubtree.getInstance(e.nextElement());
+ // BEGIN android-changed
+ Integer tagNo = Integer.valueOf(subtree.getBase().getTagNo());
+ // END android-changed
+ 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 1:
+ permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail,
+ (Set)entry.getValue());
+ break;
+ case 2:
+ permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS,
+ (Set)entry.getValue());
+ break;
+ case 4:
+ permittedSubtreesDN = intersectDN(permittedSubtreesDN,
+ (Set)entry.getValue());
+ break;
+ case 6:
+ permittedSubtreesURI = intersectURI(permittedSubtreesURI,
+ (Set)entry.getValue());
+ break;
+ case 7:
+ permittedSubtreesIP = intersectIP(permittedSubtreesIP,
+ (Set)entry.getValue());
+ }
+ }
+ }
+
+ private String extractNameAsString(GeneralName name)
+ {
+ return DERIA5String.getInstance(name.getName()).getString();
+ }
+
+ public void intersectEmptyPermittedSubtree(int nameType)
+ {
+ switch (nameType)
+ {
+ case 1:
+ permittedSubtreesEmail = new HashSet();
+ break;
+ case 2:
+ permittedSubtreesDNS = new HashSet();
+ break;
+ case 4:
+ permittedSubtreesDN = new HashSet();
+ break;
+ case 6:
+ permittedSubtreesURI = new HashSet();
+ break;
+ case 7:
+ 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 1:
+ excludedSubtreesEmail = unionEmail(excludedSubtreesEmail,
+ extractNameAsString(base));
+ break;
+ case 2:
+ excludedSubtreesDNS = unionDNS(excludedSubtreesDNS,
+ extractNameAsString(base));
+ break;
+ case 4:
+ excludedSubtreesDN = unionDN(excludedSubtreesDN,
+ (ASN1Sequence)base.getName().toASN1Primitive());
+ break;
+ case 6:
+ excludedSubtreesURI = unionURI(excludedSubtreesURI,
+ extractNameAsString(base));
+ break;
+ case 7:
+ excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString
+ .getInstance(base.getName()).getOctets());
+ break;
+ }
+ }
+
+ /**
+ * 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 <code>ip1</code> with <code>ip2</code>. 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 <code>ip1</code> and
+ * <code>ip2</code>.
+ *
+ * @param ip1 The first IP address.
+ * @param ip2 The second IP address.
+ * @return The OR of <code>ip1</code> and <code>ip2</code>.
+ */
+ 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;
+ }
+
+ public int hashCode()
+ {
+ return hashCollection(excludedSubtreesDN)
+ + hashCollection(excludedSubtreesDNS)
+ + hashCollection(excludedSubtreesEmail)
+ + hashCollection(excludedSubtreesIP)
+ + hashCollection(excludedSubtreesURI)
+ + hashCollection(permittedSubtreesDN)
+ + hashCollection(permittedSubtreesDNS)
+ + hashCollection(permittedSubtreesEmail)
+ + hashCollection(permittedSubtreesIP)
+ + hashCollection(permittedSubtreesURI);
+ }
+
+ 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;
+ }
+
+ 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);
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java
new file mode 100644
index 0000000..b06d5e5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.jce.provider;
+
+public class PKIXNameConstraintValidatorException
+ extends Exception
+{
+ public PKIXNameConstraintValidatorException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java
new file mode 100644
index 0000000..3437605
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java
@@ -0,0 +1,168 @@
+package org.bouncycastle.jce.provider;
+
+import java.security.cert.PolicyNode;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+public class PKIXPolicyNode
+ implements PolicyNode
+{
+ protected List children;
+ protected int depth;
+ protected Set expectedPolicies;
+ protected PolicyNode parent;
+ protected Set policyQualifiers;
+ protected String validPolicy;
+ protected boolean critical;
+
+ /*
+ *
+ * CONSTRUCTORS
+ *
+ */
+
+ public PKIXPolicyNode(
+ List _children,
+ int _depth,
+ Set _expectedPolicies,
+ PolicyNode _parent,
+ Set _policyQualifiers,
+ String _validPolicy,
+ boolean _critical)
+ {
+ children = _children;
+ depth = _depth;
+ expectedPolicies = _expectedPolicies;
+ parent = _parent;
+ policyQualifiers = _policyQualifiers;
+ validPolicy = _validPolicy;
+ critical = _critical;
+ }
+
+ public void addChild(
+ PKIXPolicyNode _child)
+ {
+ children.add(_child);
+ _child.setParent(this);
+ }
+
+ public Iterator getChildren()
+ {
+ return children.iterator();
+ }
+
+ public int getDepth()
+ {
+ return depth;
+ }
+
+ public Set getExpectedPolicies()
+ {
+ return expectedPolicies;
+ }
+
+ public PolicyNode getParent()
+ {
+ return parent;
+ }
+
+ public Set getPolicyQualifiers()
+ {
+ return policyQualifiers;
+ }
+
+ public String getValidPolicy()
+ {
+ return validPolicy;
+ }
+
+ public boolean hasChildren()
+ {
+ return !children.isEmpty();
+ }
+
+ public boolean isCritical()
+ {
+ return critical;
+ }
+
+ public void removeChild(PKIXPolicyNode _child)
+ {
+ children.remove(_child);
+ }
+
+ public void setCritical(boolean _critical)
+ {
+ critical = _critical;
+ }
+
+ public void setParent(PKIXPolicyNode _parent)
+ {
+ parent = _parent;
+ }
+
+ public String toString()
+ {
+ return toString("");
+ }
+
+ public String toString(String _indent)
+ {
+ StringBuffer _buf = new StringBuffer();
+ _buf.append(_indent);
+ _buf.append(validPolicy);
+ _buf.append(" {\n");
+
+ for(int i = 0; i < children.size(); i++)
+ {
+ _buf.append(((PKIXPolicyNode)children.get(i)).toString(_indent + " "));
+ }
+
+ _buf.append(_indent);
+ _buf.append("}\n");
+ return _buf.toString();
+ }
+
+ public Object clone()
+ {
+ return copy();
+ }
+
+ public PKIXPolicyNode copy()
+ {
+ Set _expectedPolicies = new HashSet();
+ Iterator _iter = expectedPolicies.iterator();
+ while (_iter.hasNext())
+ {
+ _expectedPolicies.add(new String((String)_iter.next()));
+ }
+
+ Set _policyQualifiers = new HashSet();
+ _iter = policyQualifiers.iterator();
+ while (_iter.hasNext())
+ {
+ _policyQualifiers.add(new String((String)_iter.next()));
+ }
+
+ PKIXPolicyNode _node = new PKIXPolicyNode(new ArrayList(),
+ depth,
+ _expectedPolicies,
+ null,
+ _policyQualifiers,
+ new String(validPolicy),
+ critical);
+
+ _iter = children.iterator();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _child = ((PKIXPolicyNode)_iter.next()).copy();
+ _child.setParent(_node);
+ _node.addChild(_child);
+ }
+
+ return _node;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
new file mode 100644
index 0000000..7357894
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java
@@ -0,0 +1,2569 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+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.X509Certificate;
+import java.security.cert.X509Extension;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+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 org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+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.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.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
+{
+ private static final PKIXCRLUtil CRL_UTIL = new PKIXCRLUtil();
+
+ /**
+ * If the complete CRL includes an issuing distribution point (IDP) CRL
+ * extension check the following:
+ * <p/>
+ * (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
+ * distribution point name is present in the IDP CRL extension and the
+ * distribution field is omitted from the DP, then verify that one of the
+ * names in the IDP matches one of the names in the cRLIssuer field of the
+ * DP.
+ * </p>
+ * <p/>
+ * (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.
+ * </p>
+ * <p/>
+ * (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.
+ * </p>
+ * <p/>
+ * (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+ * </p>
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate.
+ * @param crl The CRL.
+ * @throws AnnotatedException if one of the conditions is not met or an error occurs.
+ */
+ protected static void processCRLB2(
+ DistributionPoint dp,
+ Object cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+ // (b) (2) (i)
+ // distribution point name is present
+ if (idp != null)
+ {
+ if (idp.getDistributionPoint() != null)
+ {
+ // make list of names
+ DistributionPointName dpName = IssuingDistributionPoint.getInstance(idp).getDistributionPoint();
+ List names = new ArrayList();
+
+ if (dpName.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ names.add(genNames[j]);
+ }
+ }
+ if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ {
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ try
+ {
+ Enumeration e = ASN1Sequence.getInstance(
+ ASN1Sequence.fromByteArray(CertPathValidatorUtilities.getIssuerPrincipal(crl)
+ .getEncoded())).getObjects();
+ while (e.hasMoreElements())
+ {
+ vec.add((ASN1Encodable)e.nextElement());
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Could not read CRL issuer.", e);
+ }
+ vec.add(dpName.getName());
+ names.add(new GeneralName(X509Name.getInstance(new DERSequence(vec))));
+ }
+ boolean matches = false;
+ // verify that one of the names in the IDP matches one
+ // of the names in the DP.
+ if (dp.getDistributionPoint() != null)
+ {
+ dpName = dp.getDistributionPoint();
+ GeneralName[] genNames = null;
+ if (dpName.getType() == DistributionPointName.FULL_NAME)
+ {
+ genNames = GeneralNames.getInstance(dpName.getName()).getNames();
+ }
+ if (dpName.getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+ {
+ if (dp.getCRLIssuer() != null)
+ {
+ genNames = dp.getCRLIssuer().getNames();
+ }
+ else
+ {
+ genNames = new GeneralName[1];
+ try
+ {
+ genNames[0] = new GeneralName(new X509Name(
+ (ASN1Sequence)ASN1Sequence.fromByteArray(CertPathValidatorUtilities
+ .getEncodedIssuerPrincipal(cert).getEncoded())));
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException("Could not read certificate issuer.", e);
+ }
+ }
+ for (int j = 0; j < genNames.length; j++)
+ {
+ Enumeration e = ASN1Sequence.getInstance(genNames[j].getName().toASN1Primitive()).getObjects();
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ while (e.hasMoreElements())
+ {
+ vec.add((ASN1Encodable)e.nextElement());
+ }
+ vec.add(dpName.getName());
+ genNames[j] = new GeneralName(new X509Name(new DERSequence(vec)));
+ }
+ }
+ if (genNames != null)
+ {
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (names.contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ }
+ if (!matches)
+ {
+ throw new AnnotatedException(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ // verify that one of the names in
+ // the IDP matches one of the names in the cRLIssuer field of
+ // the DP
+ else
+ {
+ if (dp.getCRLIssuer() == null)
+ {
+ throw new AnnotatedException("Either the cRLIssuer or the distributionPoint field must "
+ + "be contained in DistributionPoint.");
+ }
+ GeneralName[] genNames = dp.getCRLIssuer().getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (names.contains(genNames[j]))
+ {
+ matches = true;
+ break;
+ }
+ }
+ if (!matches)
+ {
+ throw new AnnotatedException(
+ "No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+ }
+ }
+ }
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue((X509Extension)cert,
+ BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Basic constraints extension could not be decoded.", e);
+ }
+
+ if (cert instanceof X509Certificate)
+ {
+ // (b) (2) (ii)
+ if (idp.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+ {
+ throw new AnnotatedException("CA Cert CRL only contains user certificates.");
+ }
+
+ // (b) (2) (iii)
+ if (idp.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+ {
+ throw new AnnotatedException("End CRL only contains CA certificates.");
+ }
+ }
+
+ // (b) (2) (iv)
+ if (idp.onlyContainsAttributeCerts())
+ {
+ throw new AnnotatedException("onlyContainsAttributeCerts boolean is asserted.");
+ }
+ }
+ }
+
+ /**
+ * If the DP includes cRLIssuer, then verify that the issuer field in the
+ * complete CRL matches cRLIssuer in the DP and that the complete CRL
+ * contains an issuing distribution point extension with the indirectCRL
+ * boolean asserted. Otherwise, verify that the CRL issuer matches the
+ * certificate issuer.
+ *
+ * @param dp The distribution point.
+ * @param cert The certificate ot attribute certificate.
+ * @param crl The CRL for <code>cert</code>.
+ * @throws AnnotatedException if one of the above conditions does not apply or an error
+ * occurs.
+ */
+ protected static void processCRLB1(
+ DistributionPoint dp,
+ Object cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ ASN1Primitive idp = CertPathValidatorUtilities.getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+ boolean isIndirect = false;
+ if (idp != null)
+ {
+ if (IssuingDistributionPoint.getInstance(idp).isIndirectCRL())
+ {
+ isIndirect = true;
+ }
+ }
+ byte[] issuerBytes = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded();
+
+ boolean matchIssuer = false;
+ if (dp.getCRLIssuer() != null)
+ {
+ GeneralName genNames[] = dp.getCRLIssuer().getNames();
+ for (int j = 0; j < genNames.length; j++)
+ {
+ if (genNames[j].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (Arrays.areEqual(genNames[j].getName().toASN1Primitive().getEncoded(), issuerBytes))
+ {
+ matchIssuer = true;
+ }
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "CRL issuer information from distribution point cannot be decoded.", e);
+ }
+ }
+ }
+ if (matchIssuer && !isIndirect)
+ {
+ throw new AnnotatedException("Distribution point contains cRLIssuer field but CRL is not indirect.");
+ }
+ if (!matchIssuer)
+ {
+ throw new AnnotatedException("CRL issuer of CRL does not match CRL issuer of distribution point.");
+ }
+ }
+ else
+ {
+ if (CertPathValidatorUtilities.getIssuerPrincipal(crl).equals(
+ CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert)))
+ {
+ matchIssuer = true;
+ }
+ }
+ if (!matchIssuer)
+ {
+ throw new AnnotatedException("Cannot find matching CRL issuer for certificate.");
+ }
+ }
+
+ protected static ReasonsMask processCRLD(
+ X509CRL crl,
+ DistributionPoint dp)
+ throws AnnotatedException
+ {
+ IssuingDistributionPoint idp = null;
+ try
+ {
+ idp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+ // (d) (1)
+ if (idp != null && idp.getOnlySomeReasons() != null && dp.getReasons() != null)
+ {
+ return new ReasonsMask(dp.getReasons()).intersect(new ReasonsMask(idp.getOnlySomeReasons()));
+ }
+ // (d) (4)
+ if ((idp == null || idp.getOnlySomeReasons() == null) && dp.getReasons() == null)
+ {
+ return ReasonsMask.allReasons;
+ }
+ // (d) (2) and (d)(3)
+ return (dp.getReasons() == null
+ ? ReasonsMask.allReasons
+ : new ReasonsMask(dp.getReasons())).intersect(idp == null
+ ? ReasonsMask.allReasons
+ : new ReasonsMask(idp.getOnlySomeReasons()));
+
+ }
+
+ protected static final String CERTIFICATE_POLICIES = X509Extensions.CertificatePolicies.getId();
+
+ protected static final String POLICY_MAPPINGS = X509Extensions.PolicyMappings.getId();
+
+ protected static final String INHIBIT_ANY_POLICY = X509Extensions.InhibitAnyPolicy.getId();
+
+ protected static final String ISSUING_DISTRIBUTION_POINT = X509Extensions.IssuingDistributionPoint.getId();
+
+ protected static final String FRESHEST_CRL = X509Extensions.FreshestCRL.getId();
+
+ protected static final String DELTA_CRL_INDICATOR = X509Extensions.DeltaCRLIndicator.getId();
+
+ protected static final String POLICY_CONSTRAINTS = X509Extensions.PolicyConstraints.getId();
+
+ protected static final String BASIC_CONSTRAINTS = X509Extensions.BasicConstraints.getId();
+
+ protected static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints.getId();
+
+ protected static final String SUBJECT_ALTERNATIVE_NAME = X509Extensions.SubjectAlternativeName.getId();
+
+ protected static final String NAME_CONSTRAINTS = X509Extensions.NameConstraints.getId();
+
+ protected static final String AUTHORITY_KEY_IDENTIFIER = X509Extensions.AuthorityKeyIdentifier.getId();
+
+ protected static final String KEY_USAGE = X509Extensions.KeyUsage.getId();
+
+ protected static final String CRL_NUMBER = X509Extensions.CRLNumber.getId();
+
+ protected static final String ANY_POLICY = "2.5.29.32.0";
+
+ /*
+ * key usage bits
+ */
+ protected static final int KEY_CERT_SIGN = 5;
+
+ protected static final int CRL_SIGN = 6;
+
+ /**
+ * Obtain and validate the certification path for the complete CRL issuer.
+ * If a key usage extension is present in the CRL issuer's certificate,
+ * verify that the cRLSign bit is set.
+ *
+ * @param crl CRL which contains revocation information for the certificate
+ * <code>cert</code>.
+ * @param cert The attribute certificate or certificate to check if it is
+ * revoked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param paramsPKIX paramsPKIX PKIX parameters.
+ * @param certPathCerts The certificates on the certification path.
+ * @return A <code>Set</code> with all keys of possible CRL issuer
+ * certificates.
+ * @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+ * some error occurs.
+ */
+ protected static Set processCRLF(
+ X509CRL crl,
+ Object cert,
+ X509Certificate defaultCRLSignCert,
+ PublicKey defaultCRLSignKey,
+ ExtendedPKIXParameters paramsPKIX,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ // (f)
+
+ // get issuer from CRL
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ try
+ {
+ byte[] issuerPrincipal = CertPathValidatorUtilities.getIssuerPrincipal(crl).getEncoded();
+ selector.setSubject(issuerPrincipal);
+ }
+ catch (IOException e)
+ {
+ throw new AnnotatedException(
+ "Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e);
+ }
+
+ // get CRL signing certs
+ Collection coll;
+ try
+ {
+ coll = CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getStores());
+ coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getAdditionalStores()));
+ coll.addAll(CertPathValidatorUtilities.findCertificates(selector, paramsPKIX.getCertStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Issuer certificate for CRL cannot be searched.", e);
+ }
+
+ coll.add(defaultCRLSignCert);
+
+ Iterator cert_it = coll.iterator();
+
+ List validCerts = new ArrayList();
+ List validKeys = new ArrayList();
+
+ while (cert_it.hasNext())
+ {
+ X509Certificate signingCert = (X509Certificate)cert_it.next();
+
+ /*
+ * CA of the certificate, for which this CRL is checked, has also
+ * signed CRL, so skip the path validation, because is already done
+ */
+ if (signingCert.equals(defaultCRLSignCert))
+ {
+ validCerts.add(signingCert);
+ validKeys.add(defaultCRLSignKey);
+ continue;
+ }
+ 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);
+ /*
+ * if signingCert is placed not higher on the cert path a
+ * dependency loop results. CRL for cert is checked, but
+ * signingCert is needed for checking the CRL which is dependent
+ * on checking cert because it is higher in the cert path and so
+ * signing signingCert transitively. so, revocation is disabled,
+ * forgery attacks of the CRL are detected in this outer loop
+ * for all other it must be enabled to prevent forgery attacks
+ */
+ if (certPathCerts.contains(signingCert))
+ {
+ params.setRevocationEnabled(false);
+ }
+ else
+ {
+ params.setRevocationEnabled(true);
+ }
+ List certs = builder.build(params).getCertPath().getCertificates();
+ validCerts.add(signingCert);
+ validKeys.add(CertPathValidatorUtilities.getNextWorkingKey(certs, 0));
+ }
+ catch (CertPathBuilderException e)
+ {
+ throw new AnnotatedException("Internal error.", e);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new AnnotatedException("Public key of issuer certificate of CRL could not be retrieved.", e);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ Set checkKeys = new HashSet();
+
+ AnnotatedException lastException = null;
+ for (int i = 0; i < validCerts.size(); i++)
+ {
+ X509Certificate signCert = (X509Certificate)validCerts.get(i);
+ boolean[] keyusage = signCert.getKeyUsage();
+
+ if (keyusage != null && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+ {
+ lastException = new AnnotatedException(
+ "Issuer certificate key usage extension does not permit CRL signing.");
+ }
+ else
+ {
+ checkKeys.add(validKeys.get(i));
+ }
+ }
+
+ if (checkKeys.isEmpty() && lastException == null)
+ {
+ throw new AnnotatedException("Cannot find a valid issuer certificate.");
+ }
+ if (checkKeys.isEmpty() && lastException != null)
+ {
+ throw lastException;
+ }
+
+ return checkKeys;
+ }
+
+ protected static PublicKey processCRLG(
+ X509CRL crl,
+ Set keys)
+ throws AnnotatedException
+ {
+ Exception lastException = null;
+ for (Iterator it = keys.iterator(); it.hasNext();)
+ {
+ PublicKey key = (PublicKey)it.next();
+ try
+ {
+ crl.verify(key);
+ return key;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+ throw new AnnotatedException("Cannot verify CRL.", lastException);
+ }
+
+ protected static X509CRL processCRLH(
+ Set deltacrls,
+ PublicKey key)
+ throws AnnotatedException
+ {
+ Exception lastException = null;
+
+ for (Iterator it = deltacrls.iterator(); it.hasNext();)
+ {
+ X509CRL crl = (X509CRL)it.next();
+ try
+ {
+ crl.verify(key);
+ return crl;
+ }
+ catch (Exception e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (lastException != null)
+ {
+ throw new AnnotatedException("Cannot verify delta CRL.", lastException);
+ }
+ return null;
+ }
+
+ protected static Set processCRLA1i(
+ Date currentDate,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ Set set = new HashSet();
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ CRLDistPoint freshestCRL = null;
+ try
+ {
+ freshestCRL = CRLDistPoint
+ .getInstance(CertPathValidatorUtilities.getExtensionValue(cert, FRESHEST_CRL));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Freshest CRL extension could not be decoded from certificate.", e);
+ }
+ if (freshestCRL == null)
+ {
+ try
+ {
+ freshestCRL = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(crl,
+ FRESHEST_CRL));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Freshest CRL extension could not be decoded from CRL.", e);
+ }
+ }
+ if (freshestCRL != null)
+ {
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(freshestCRL, paramsPKIX);
+ }
+ 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));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+ }
+ }
+ }
+ return set;
+ }
+
+ protected static Set[] processCRLA1ii(
+ Date currentDate,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ X509CRL crl)
+ throws AnnotatedException
+ {
+ Set deltaSet = new HashSet();
+ X509CRLStoreSelector crlselect = new X509CRLStoreSelector();
+ crlselect.setCertificateChecking(cert);
+
+ try
+ {
+ crlselect.addIssuerName(crl.getIssuerX500Principal().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);
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRL(s)
+ try
+ {
+ deltaSet.addAll(CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException("Exception obtaining delta CRLs.", e);
+ }
+ }
+ return new Set[]
+ {
+ completeSet,
+ deltaSet};
+ }
+
+
+
+ /**
+ * If use-deltas is set, verify the issuer and scope of the delta CRL.
+ *
+ * @param deltaCRL The delta CRL.
+ * @param completeCRL The complete CRL.
+ * @param pkixParams The PKIX paramaters.
+ * @throws AnnotatedException if an exception occurs.
+ */
+ protected static void processCRLC(
+ X509CRL deltaCRL,
+ X509CRL completeCRL,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (deltaCRL == null)
+ {
+ return;
+ }
+ IssuingDistributionPoint completeidp = null;
+ try
+ {
+ completeidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+ completeCRL, RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuing distribution point extension could not be decoded.", e);
+ }
+
+ if (pkixParams.isUseDeltasEnabled())
+ {
+ // (c) (1)
+ if (!deltaCRL.getIssuerX500Principal().equals(completeCRL.getIssuerX500Principal()))
+ {
+ throw new AnnotatedException("Complete CRL issuer does not match delta CRL issuer.");
+ }
+
+ // (c) (2)
+ IssuingDistributionPoint deltaidp = null;
+ try
+ {
+ deltaidp = IssuingDistributionPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(
+ deltaCRL, ISSUING_DISTRIBUTION_POINT));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension from delta CRL could not be decoded.", e);
+ }
+
+ boolean match = false;
+ if (completeidp == null)
+ {
+ if (deltaidp == null)
+ {
+ match = true;
+ }
+ }
+ else
+ {
+ if (completeidp.equals(deltaidp))
+ {
+ match = true;
+ }
+ }
+ if (!match)
+ {
+ throw new AnnotatedException(
+ "Issuing distribution point extension from delta CRL and complete CRL does not match.");
+ }
+
+ // (c) (3)
+ ASN1Primitive completeKeyIdentifier = null;
+ try
+ {
+ completeKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+ completeCRL, AUTHORITY_KEY_IDENTIFIER);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Authority key identifier extension could not be extracted from complete CRL.", e);
+ }
+
+ ASN1Primitive deltaKeyIdentifier = null;
+ try
+ {
+ deltaKeyIdentifier = CertPathValidatorUtilities.getExtensionValue(
+ deltaCRL, AUTHORITY_KEY_IDENTIFIER);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "Authority key identifier extension could not be extracted from delta CRL.", e);
+ }
+
+ if (completeKeyIdentifier == null)
+ {
+ throw new AnnotatedException("CRL authority key identifier is null.");
+ }
+
+ if (deltaKeyIdentifier == null)
+ {
+ throw new AnnotatedException("Delta CRL authority key identifier is null.");
+ }
+
+ if (!completeKeyIdentifier.equals(deltaKeyIdentifier))
+ {
+ throw new AnnotatedException(
+ "Delta CRL authority key identifier does not match complete CRL authority key identifier.");
+ }
+ }
+ }
+
+ protected static void processCRLI(
+ Date validDate,
+ X509CRL deltacrl,
+ Object cert,
+ CertStatus certStatus,
+ ExtendedPKIXParameters pkixParams)
+ throws AnnotatedException
+ {
+ if (pkixParams.isUseDeltasEnabled() && deltacrl != null)
+ {
+ CertPathValidatorUtilities.getCertStatus(validDate, deltacrl, cert, certStatus);
+ }
+ }
+
+ protected static void processCRLJ(
+ Date validDate,
+ X509CRL completecrl,
+ Object cert,
+ CertStatus certStatus)
+ throws AnnotatedException
+ {
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ CertPathValidatorUtilities.getCertStatus(validDate, completecrl, cert, certStatus);
+ }
+ }
+
+ protected static PKIXPolicyNode prepareCertB(
+ CertPath certPath,
+ int index,
+ List[] policyNodes,
+ PKIXPolicyNode validPolicyTree,
+ int policyMapping)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ // (b)
+ //
+ ASN1Sequence pm = null;
+ try
+ {
+ pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_MAPPINGS));
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+ index);
+ }
+ PKIXPolicyNode _validPolicyTree = validPolicyTree;
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence)pm;
+ Map m_idp = new HashMap();
+ Set s_idp = new HashSet();
+
+ 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();
+ Set tmp;
+
+ if (!m_idp.containsKey(id_p))
+ {
+ tmp = new HashSet();
+ tmp.add(sd_p);
+ m_idp.put(id_p, tmp);
+ s_idp.add(id_p);
+ }
+ else
+ {
+ tmp = (Set)m_idp.get(id_p);
+ tmp.add(sd_p);
+ }
+ }
+
+ Iterator it_idp = s_idp.iterator();
+ while (it_idp.hasNext())
+ {
+ String id_p = (String)it_idp.next();
+
+ //
+ // (1)
+ //
+ if (policyMapping > 0)
+ {
+ boolean idp_found = false;
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ idp_found = true;
+ node.expectedPolicies = (Set)m_idp.get(id_p);
+ break;
+ }
+ }
+
+ if (!idp_found)
+ {
+ nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(node.getValidPolicy()))
+ {
+ Set pq = null;
+ ASN1Sequence policies = null;
+ try
+ {
+ policies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Certificate policies extension could not be decoded.", e, certPath, index);
+ }
+ Enumeration e = policies.getObjects();
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pinfo = null;
+ try
+ {
+ pinfo = PolicyInformation.getInstance(e.nextElement());
+ }
+ catch (Exception ex)
+ {
+ throw new CertPathValidatorException(
+ "Policy information could not be decoded.", ex, certPath, index);
+ }
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId()))
+ {
+ try
+ {
+ pq = CertPathValidatorUtilities
+ .getQualifierSet(pinfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+
+ throw new ExtCertPathValidatorException(
+ "Policy qualifier info set could not be decoded.", ex, certPath,
+ index);
+ }
+ break;
+ }
+ }
+ boolean ci = false;
+ if (cert.getCriticalExtensionOIDs() != null)
+ {
+ ci = cert.getCriticalExtensionOIDs().contains(
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+ }
+
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(p_node.getValidPolicy()))
+ {
+ PKIXPolicyNode c_node = new PKIXPolicyNode(new ArrayList(), i, (Set)m_idp
+ .get(id_p), p_node, pq, id_p, ci);
+ p_node.addChild(c_node);
+ policyNodes[i].add(c_node);
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (2)
+ //
+ }
+ else if (policyMapping <= 0)
+ {
+ Iterator nodes_i = policyNodes[i].iterator();
+ while (nodes_i.hasNext())
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next();
+ if (node.getValidPolicy().equals(id_p))
+ {
+ PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent();
+ p_node.removeChild(node);
+ nodes_i.remove();
+ for (int k = (i - 1); k >= 0; k--)
+ {
+ List nodes = policyNodes[k];
+ for (int l = 0; l < nodes.size(); l++)
+ {
+ PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l);
+ if (!node2.hasChildren())
+ {
+ _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(
+ _validPolicyTree, policyNodes, node2);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return _validPolicyTree;
+ }
+
+ protected static void prepareNextCertA(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ //
+ // (a) check the policy mappings
+ //
+ ASN1Sequence pm = null;
+ try
+ {
+ pm = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_MAPPINGS));
+ }
+ catch (AnnotatedException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath,
+ index);
+ }
+ if (pm != null)
+ {
+ ASN1Sequence mappings = pm;
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ DERObjectIdentifier issuerDomainPolicy = null;
+ DERObjectIdentifier subjectDomainPolicy = null;
+ try
+ {
+ ASN1Sequence mapping = DERSequence.getInstance(mappings.getObjectAt(j));
+
+ issuerDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(0));
+ subjectDomainPolicy = DERObjectIdentifier.getInstance(mapping.getObjectAt(1));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy mappings extension contents could not be decoded.",
+ e, certPath, index);
+ }
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(issuerDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("IssuerDomainPolicy is anyPolicy", null, certPath, index);
+ }
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(subjectDomainPolicy.getId()))
+ {
+
+ throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy,", null, certPath, index);
+ }
+ }
+ }
+ }
+
+ protected static void processCertF(
+ CertPath certPath,
+ int index,
+ PKIXPolicyNode validPolicyTree,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ //
+ // (f)
+ //
+ if (explicitPolicy <= 0 && validPolicyTree == null)
+ {
+ throw new ExtCertPathValidatorException("No valid policy tree found when one expected.", null, certPath,
+ index);
+ }
+ }
+
+ protected static PKIXPolicyNode processCertE(
+ CertPath certPath,
+ int index,
+ PKIXPolicyNode validPolicyTree)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (e)
+ //
+ ASN1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies == null)
+ {
+ validPolicyTree = null;
+ }
+ return validPolicyTree;
+ }
+
+ protected static void processCertBC(
+ CertPath certPath,
+ int index,
+ PKIXNameConstraintValidator nameConstraintValidator)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (b), (c) permitted and excluded subtree checking.
+ //
+ if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n)))
+ {
+ X500Principal principal = CertPathValidatorUtilities.getSubjectPrincipal(cert);
+ ASN1InputStream aIn = new ASN1InputStream(principal.getEncoded());
+ ASN1Sequence dns;
+
+ try
+ {
+ dns = DERSequence.getInstance(aIn.readObject());
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Exception extracting subject name when checking subtrees.", e,
+ certPath, index);
+ }
+
+ try
+ {
+ nameConstraintValidator.checkPermittedDN(dns);
+ nameConstraintValidator.checkExcludedDN(dns);
+ }
+ catch (PKIXNameConstraintValidatorException e)
+ {
+ throw new CertPathValidatorException("Subtree check for certificate subject failed.", e, certPath,
+ index);
+ }
+
+ GeneralNames altName = null;
+ try
+ {
+ altName = GeneralNames.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME));
+ }
+ catch (Exception e)
+ {
+ 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();)
+ {
+ String email = (String)e.nextElement();
+ GeneralName emailAsGeneralName = new GeneralName(GeneralName.rfc822Name, email);
+ try
+ {
+ nameConstraintValidator.checkPermitted(emailAsGeneralName);
+ nameConstraintValidator.checkExcluded(emailAsGeneralName);
+ }
+ catch (PKIXNameConstraintValidatorException ex)
+ {
+ throw new CertPathValidatorException(
+ "Subtree check for certificate subject alternative email failed.", ex, certPath, index);
+ }
+ }
+ if (altName != null)
+ {
+ GeneralName[] genNames = null;
+ try
+ {
+ genNames = altName.getNames();
+ }
+ catch (Exception e)
+ {
+ throw new CertPathValidatorException("Subject alternative name contents could not be decoded.", e,
+ certPath, index);
+ }
+ for (int j = 0; j < genNames.length; j++)
+ {
+
+ try
+ {
+ nameConstraintValidator.checkPermitted(genNames[j]);
+ nameConstraintValidator.checkExcluded(genNames[j]);
+ }
+ catch (PKIXNameConstraintValidatorException e)
+ {
+ throw new CertPathValidatorException(
+ "Subtree check for certificate subject alternative name failed.", e, certPath, index);
+ }
+ }
+ }
+ }
+ }
+
+ protected static PKIXPolicyNode processCertD(
+ CertPath certPath,
+ int index,
+ Set acceptablePolicies,
+ PKIXPolicyNode validPolicyTree,
+ List[] policyNodes,
+ int inhibitAnyPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ int n = certs.size();
+ // i as defined in the algorithm description
+ int i = n - index;
+ //
+ // (d) policy Information checking against initial policy and
+ // policy mapping
+ //
+ ASN1Sequence certPolicies = null;
+ try
+ {
+ certPolicies = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CERTIFICATE_POLICIES));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not read certificate policies extension from certificate.",
+ e, certPath, index);
+ }
+ if (certPolicies != null && validPolicyTree != null)
+ {
+ //
+ // (d) (1)
+ //
+ Enumeration e = certPolicies.getObjects();
+ Set pols = new HashSet();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+ DERObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+
+ pols.add(pOid.getId());
+
+ if (!RFC3280CertPathUtilities.ANY_POLICY.equals(pOid.getId()))
+ {
+ Set pq = null;
+ try
+ {
+ pq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException ex)
+ {
+ throw new ExtCertPathValidatorException("Policy qualifier info set could not be build.", ex,
+ certPath, index);
+ }
+
+ boolean match = CertPathValidatorUtilities.processCertD1i(i, policyNodes, pOid, pq);
+
+ if (!match)
+ {
+ CertPathValidatorUtilities.processCertD1ii(i, policyNodes, pOid, pq);
+ }
+ }
+ }
+
+ if (acceptablePolicies.isEmpty() || acceptablePolicies.contains(RFC3280CertPathUtilities.ANY_POLICY))
+ {
+ acceptablePolicies.clear();
+ acceptablePolicies.addAll(pols);
+ }
+ else
+ {
+ Iterator it = acceptablePolicies.iterator();
+ Set t1 = new HashSet();
+
+ while (it.hasNext())
+ {
+ Object o = it.next();
+
+ if (pols.contains(o))
+ {
+ t1.add(o);
+ }
+ }
+ acceptablePolicies.clear();
+ acceptablePolicies.addAll(t1);
+ }
+
+ //
+ // (d) (2)
+ //
+ if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert)))
+ {
+ e = certPolicies.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+ {
+ Set _apq = CertPathValidatorUtilities.getQualifierSet(pInfo.getPolicyQualifiers());
+ List _nodes = policyNodes[i - 1];
+
+ for (int k = 0; k < _nodes.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodes.get(k);
+
+ Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+ while (_policySetIter.hasNext())
+ {
+ Object _tmp = _policySetIter.next();
+
+ String _policy;
+ if (_tmp instanceof String)
+ {
+ _policy = (String)_tmp;
+ }
+ else if (_tmp instanceof DERObjectIdentifier)
+ {
+ _policy = ((DERObjectIdentifier)_tmp).getId();
+ }
+ else
+ {
+ continue;
+ }
+
+ boolean _found = false;
+ Iterator _childrenIter = _node.getChildren();
+
+ while (_childrenIter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next();
+
+ if (_policy.equals(_child.getValidPolicy()))
+ {
+ _found = true;
+ }
+ }
+
+ if (!_found)
+ {
+ Set _newChildExpectedPolicies = new HashSet();
+ _newChildExpectedPolicies.add(_policy);
+
+ PKIXPolicyNode _newChild = new PKIXPolicyNode(new ArrayList(), i,
+ _newChildExpectedPolicies, _node, _apq, _policy, false);
+ _node.addChild(_newChild);
+ policyNodes[i].add(_newChild);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ PKIXPolicyNode _validPolicyTree = validPolicyTree;
+ //
+ // (d) (3)
+ //
+ for (int j = (i - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(_validPolicyTree, policyNodes,
+ node);
+ if (_validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // d (4)
+ //
+ Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensionOids != null)
+ {
+ boolean critical = criticalExtensionOids.contains(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
+
+ List nodes = policyNodes[i];
+ for (int j = 0; j < nodes.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j);
+ node.setCritical(critical);
+ }
+ }
+ return _validPolicyTree;
+ }
+ return null;
+ }
+
+ protected static void processCertA(
+ CertPath certPath,
+ ExtendedPKIXParameters paramsPKIX,
+ int index,
+ PublicKey workingPublicKey,
+ boolean verificationAlreadyPerformed,
+ X500Principal workingIssuerName,
+ X509Certificate sign)
+ throws ExtCertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (a) verify
+ //
+ if (!verificationAlreadyPerformed)
+ {
+ try
+ {
+ // (a) (1)
+ //
+ CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
+ paramsPKIX.getSigProvider());
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+ }
+ }
+
+ try
+ {
+ // (a) (2)
+ //
+ cert.checkValidity(CertPathValidatorUtilities
+ .getValidCertDateFromValidityModel(paramsPKIX, certPath, index));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate certificate: " + e.getMessage(), e, certPath, index);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Could not validate time of certificate.", e, certPath, index);
+ }
+
+ //
+ // (a) (3)
+ //
+ if (paramsPKIX.isRevocationEnabled())
+ {
+ try
+ {
+ checkCRLs(paramsPKIX, cert, CertPathValidatorUtilities.getValidCertDateFromValidityModel(paramsPKIX,
+ certPath, index), sign, workingPublicKey, certs);
+ }
+ catch (AnnotatedException e)
+ {
+ Throwable cause = e;
+ if (null != e.getCause())
+ {
+ cause = e.getCause();
+ }
+ throw new ExtCertPathValidatorException(e.getMessage(), cause, certPath, index);
+ }
+ }
+
+ //
+ // (a) (4) name chaining
+ //
+ if (!CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).equals(workingIssuerName))
+ {
+ throw new ExtCertPathValidatorException("IssuerName(" + CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert)
+ + ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null,
+ certPath, index);
+ }
+ }
+
+ protected static int prepareNextCertI1(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (i)
+ //
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ try
+ {
+
+ ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+ if (constraint.getTagNo() == 0)
+ {
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < explicitPolicy)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+ e, certPath, index);
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static int prepareNextCertI2(
+ CertPath certPath,
+ int index,
+ int policyMapping)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (i)
+ //
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ int tmpInt;
+
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ try
+ {
+ ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement());
+ if (constraint.getTagNo() == 1)
+ {
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < policyMapping)
+ {
+ return tmpInt;
+ }
+ break;
+ }
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints extension contents cannot be decoded.",
+ e, certPath, index);
+ }
+ }
+ }
+ return policyMapping;
+ }
+
+ protected static void prepareNextCertG(
+ CertPath certPath,
+ int index,
+ PKIXNameConstraintValidator nameConstraintValidator)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (g) handle the name constraints extension
+ //
+ NameConstraints nc = null;
+ try
+ {
+ ASN1Sequence ncSeq = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.NAME_CONSTRAINTS));
+ if (ncSeq != null)
+ {
+ nc = NameConstraints.getInstance(ncSeq);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Name constraints extension could not be decoded.", e, certPath,
+ index);
+ }
+ if (nc != null)
+ {
+
+ //
+ // (g) (1) permitted subtrees
+ //
+ ASN1Sequence permitted = nc.getPermittedSubtrees();
+ if (permitted != null)
+ {
+ try
+ {
+ nameConstraintValidator.intersectPermittedSubtree(permitted);
+ }
+ catch (Exception ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+
+ //
+ // (g) (2) excluded subtrees
+ //
+ ASN1Sequence excluded = nc.getExcludedSubtrees();
+ if (excluded != null)
+ {
+ Enumeration e = excluded.getObjects();
+ try
+ {
+ while (e.hasMoreElements())
+ {
+ GeneralSubtree subtree = GeneralSubtree.getInstance(e.nextElement());
+ nameConstraintValidator.addExcludedSubtree(subtree);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new ExtCertPathValidatorException(
+ "Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks a distribution point for revocation information for the
+ * certificate <code>cert</code>.
+ *
+ * @param dp The distribution point to consider.
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+ * @param defaultCRLSignKey The public key of the issuer certificate
+ * <code>defaultCRLSignCert</code>.
+ * @param certStatus The current certificate revocation status.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ private static void checkCRL(
+ DistributionPoint dp,
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate defaultCRLSignCert,
+ PublicKey defaultCRLSignKey,
+ CertStatus certStatus,
+ ReasonsMask reasonMask,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ Date currentDate = new Date(System.currentTimeMillis());
+ if (validDate.getTime() > currentDate.getTime())
+ {
+ throw new AnnotatedException("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPKIXParameters and are in
+ * getAdditionalStore()
+ */
+
+ Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, cert, currentDate, paramsPKIX);
+ boolean validCrlFound = false;
+ AnnotatedException lastException = null;
+ Iterator crl_iter = crls.iterator();
+
+ while (crl_iter.hasNext() && certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonMask.isAllReasons())
+ {
+ try
+ {
+ X509CRL crl = (X509CRL)crl_iter.next();
+
+ // (d)
+ ReasonsMask interimReasonsMask = RFC3280CertPathUtilities.processCRLD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.hasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ Set keys = RFC3280CertPathUtilities.processCRLF(crl, cert, defaultCRLSignCert, defaultCRLSignKey,
+ paramsPKIX, certPathCerts);
+ // (g)
+ PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys);
+
+ X509CRL deltaCRL = null;
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRLs
+ Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs, key);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL validity time
+ */
+
+ if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (cert.getNotAfter().getTime() < crl.getThisUpdate().getTime())
+ {
+ throw new AnnotatedException("No valid CRL for current time found.");
+ }
+ }
+
+ RFC3280CertPathUtilities.processCRLB1(dp, cert, crl);
+
+ // (b) (2)
+ RFC3280CertPathUtilities.processCRLB2(dp, cert, crl);
+
+ // (c)
+ RFC3280CertPathUtilities.processCRLC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ RFC3280CertPathUtilities.processCRLI(validDate, deltaCRL, cert, certStatus, paramsPKIX);
+
+ // (j)
+ RFC3280CertPathUtilities.processCRLJ(validDate, crl, cert, certStatus);
+
+ // (k)
+ if (certStatus.getCertStatus() == CRLReason.removeFromCRL)
+ {
+ certStatus.setCertStatus(CertStatus.UNREVOKED);
+ }
+
+ // update reasons mask
+ reasonMask.addReasons(interimReasonsMask);
+
+ Set criticalExtensions = crl.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId());
+ criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId());
+
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new AnnotatedException("CRL contains unsupported critical extensions.");
+ }
+ }
+
+ if (deltaCRL != null)
+ {
+ criticalExtensions = deltaCRL.getCriticalExtensionOIDs();
+ if (criticalExtensions != null)
+ {
+ criticalExtensions = new HashSet(criticalExtensions);
+ criticalExtensions.remove(X509Extensions.IssuingDistributionPoint.getId());
+ criticalExtensions.remove(X509Extensions.DeltaCRLIndicator.getId());
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new AnnotatedException("Delta CRL contains unsupported critical extension.");
+ }
+ }
+ }
+
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+
+ /**
+ * Checks a certificate if it is revoked.
+ *
+ * @param paramsPKIX PKIX parameters.
+ * @param cert Certificate to check if it is revoked.
+ * @param validDate The date when the certificate revocation status should be
+ * checked.
+ * @param sign The issuer certificate of the certificate <code>cert</code>.
+ * @param workingPublicKey The public key of the issuer certificate <code>sign</code>.
+ * @param certPathCerts The certificates of the certification path.
+ * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+ * or some error occurs.
+ */
+ protected static void checkCRLs(
+ ExtendedPKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate sign,
+ PublicKey workingPublicKey,
+ List certPathCerts)
+ throws AnnotatedException
+ {
+ AnnotatedException lastException = null;
+ CRLDistPoint crldp = null;
+ try
+ {
+ crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS));
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("CRL distribution point extension could not be read.", e);
+ }
+ try
+ {
+ CertPathValidatorUtilities.addAdditionalStoresFromCRLDistributionPoint(crldp, paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new AnnotatedException(
+ "No additional CRL locations could be decoded from CRL distribution point extension.", e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ boolean validCrlFound = false;
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Distribution points could not be read.", e);
+ }
+ if (dps != null)
+ {
+ 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);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the process
+ * above with any available CRLs not specified in a distribution point
+ * but issued by the certificate issuer.
+ */
+
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED && !reasonsMask.isAllReasons())
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer fields
+ * omitted and a distribution point name of the certificate
+ * issuer.
+ */
+ ASN1Primitive issuer = null;
+ try
+ {
+ issuer = new ASN1InputStream(CertPathValidatorUtilities.getEncodedIssuerPrincipal(cert).getEncoded())
+ .readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException("Issuer from certificate for CRL could not be reencoded.", e);
+ }
+ DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.directoryName, issuer))), null, null);
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters)paramsPKIX.clone();
+ checkCRL(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask,
+ certPathCerts);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ if (lastException instanceof AnnotatedException)
+ {
+ throw lastException;
+ }
+
+ throw new AnnotatedException("No valid CRL found.", lastException);
+ }
+ if (certStatus.getCertStatus() != CertStatus.UNREVOKED)
+ {
+ String message = "Certificate revocation after " + certStatus.getRevocationDate();
+ message += ", reason: " + crlReasons[certStatus.getCertStatus()];
+ throw new AnnotatedException(message);
+ }
+ if (!reasonsMask.isAllReasons() && certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ certStatus.setCertStatus(CertStatus.UNDETERMINED);
+ }
+ if (certStatus.getCertStatus() == CertStatus.UNDETERMINED)
+ {
+ throw new AnnotatedException("Certificate status could not be determined.");
+ }
+ }
+
+ protected static int prepareNextCertJ(
+ CertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (j)
+ //
+ DERInteger iap = null;
+ try
+ {
+ iap = DERInteger.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.INHIBIT_ANY_POLICY));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Inhibit any-policy extension cannot be decoded.", e, certPath,
+ index);
+ }
+
+ if (iap != null)
+ {
+ int _inhibitAnyPolicy = iap.getValue().intValue();
+
+ if (_inhibitAnyPolicy < inhibitAnyPolicy)
+ {
+ return _inhibitAnyPolicy;
+ }
+ }
+ return inhibitAnyPolicy;
+ }
+
+ protected static void prepareNextCertK(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (k)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ if (!(bc.isCA()))
+ {
+ throw new CertPathValidatorException("Not a CA certificate");
+ }
+ }
+ else
+ {
+ throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+ }
+ }
+
+ protected static int prepareNextCertL(
+ CertPath certPath,
+ int index,
+ int maxPathLength)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (l)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ if (maxPathLength <= 0)
+ {
+ throw new ExtCertPathValidatorException("Max path length not greater than zero", null, certPath, index);
+ }
+
+ return maxPathLength - 1;
+ }
+ return maxPathLength;
+ }
+
+ protected static int prepareNextCertM(
+ CertPath certPath,
+ int index,
+ int maxPathLength)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+
+ //
+ // (m)
+ //
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.BASIC_CONSTRAINTS));
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+ index);
+ }
+ if (bc != null)
+ {
+ BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
+
+ if (_pathLengthConstraint != null)
+ {
+ int _plc = _pathLengthConstraint.intValue();
+
+ if (_plc < maxPathLength)
+ {
+ return _plc;
+ }
+ }
+ }
+ return maxPathLength;
+ }
+
+ protected static void prepareNextCertN(
+ CertPath certPath,
+ int index)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+
+ //
+ // (n)
+ //
+ boolean[] _usage = cert.getKeyUsage();
+
+ if ((_usage != null) && !_usage[RFC3280CertPathUtilities.KEY_CERT_SIGN])
+ {
+ throw new ExtCertPathValidatorException(
+ "Issuer certificate keyusage extension is critical and does not permit key signing.", null,
+ certPath, index);
+ }
+ }
+
+ protected static void prepareNextCertO(
+ CertPath certPath,
+ int index,
+ Set criticalExtensions,
+ List pathCheckers)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (o)
+ //
+
+ Iterator tmpIter;
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new CertPathValidatorException(e.getMessage(), e.getCause(), certPath, index);
+ }
+ }
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Certificate has unsupported critical extension.", null, certPath,
+ index);
+ }
+ }
+
+ protected static int prepareNextCertH1(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (1)
+ //
+ if (explicitPolicy != 0)
+ {
+ return explicitPolicy - 1;
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static int prepareNextCertH2(
+ CertPath certPath,
+ int index,
+ int policyMapping)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (2)
+ //
+ if (policyMapping != 0)
+ {
+ return policyMapping - 1;
+ }
+ }
+ return policyMapping;
+ }
+
+ protected static int prepareNextCertH3(
+ CertPath certPath,
+ int index,
+ int inhibitAnyPolicy)
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (h)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert))
+ {
+ //
+ // (3)
+ //
+ if (inhibitAnyPolicy != 0)
+ {
+ return inhibitAnyPolicy - 1;
+ }
+ }
+ return inhibitAnyPolicy;
+ }
+
+ protected static final String[] crlReasons = new String[]
+ {
+ "unspecified",
+ "keyCompromise",
+ "cACompromise",
+ "affiliationChanged",
+ "superseded",
+ "cessationOfOperation",
+ "certificateHold",
+ "unknown",
+ "removeFromCRL",
+ "privilegeWithdrawn",
+ "aACompromise"};
+
+ protected static int wrapupCertA(
+ int explicitPolicy,
+ X509Certificate cert)
+ {
+ //
+ // (a)
+ //
+ if (!CertPathValidatorUtilities.isSelfIssued(cert) && (explicitPolicy != 0))
+ {
+ explicitPolicy--;
+ }
+ return explicitPolicy;
+ }
+
+ protected static int wrapupCertB(
+ CertPath certPath,
+ int index,
+ int explicitPolicy)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ //
+ // (b)
+ //
+ int tmpInt;
+ ASN1Sequence pc = null;
+ try
+ {
+ pc = DERSequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert,
+ RFC3280CertPathUtilities.POLICY_CONSTRAINTS));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index);
+ }
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ try
+ {
+ tmpInt = DERInteger.getInstance(constraint, false).getValue().intValue();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath,
+ index);
+ }
+ if (tmpInt == 0)
+ {
+ return 0;
+ }
+ break;
+ }
+ }
+ }
+ return explicitPolicy;
+ }
+
+ protected static void wrapupCertF(
+ CertPath certPath,
+ int index,
+ List pathCheckers,
+ Set criticalExtensions)
+ throws CertPathValidatorException
+ {
+ List certs = certPath.getCertificates();
+ X509Certificate cert = (X509Certificate)certs.get(index);
+ Iterator tmpIter;
+ tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException("Additional certificate path checker failed.", e, certPath,
+ index);
+ }
+ }
+
+ if (!criticalExtensions.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Certificate has unsupported critical extension", null, certPath,
+ index);
+ }
+ }
+
+ protected static PKIXPolicyNode wrapupCertG(
+ CertPath certPath,
+ ExtendedPKIXParameters paramsPKIX,
+ Set userInitialPolicySet,
+ int index,
+ List[] policyNodes,
+ PKIXPolicyNode validPolicyTree,
+ Set acceptablePolicies)
+ throws CertPathValidatorException
+ {
+ int n = certPath.getCertificates().size();
+ //
+ // (g)
+ //
+ PKIXPolicyNode intersection;
+
+ //
+ // (g) (i)
+ //
+ if (validPolicyTree == null)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+ certPath, index);
+ }
+ intersection = null;
+ }
+ else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g)
+ // (ii)
+ {
+ if (paramsPKIX.isExplicitPolicyRequired())
+ {
+ if (acceptablePolicies.isEmpty())
+ {
+ throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null,
+ certPath, index);
+ }
+ else
+ {
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ _validPolicyNodeSet.add(_iter.next());
+ }
+ }
+ }
+ }
+
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!acceptablePolicies.contains(_validPolicy))
+ {
+ // validPolicyTree =
+ // removePolicyNode(validPolicyTree, policyNodes,
+ // _node);
+ }
+ }
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree,
+ policyNodes, node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ else
+ {
+ //
+ // (g) (iii)
+ //
+ // This implementation is not exactly same as the one described in
+ // RFC3280.
+ // However, as far as the validation result is concerned, both
+ // produce
+ // adequate result. The only difference is whether AnyPolicy is
+ // remain
+ // in the policy tree or not.
+ //
+ // (g) (iii) 1
+ //
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+ if (!RFC3280CertPathUtilities.ANY_POLICY.equals(_c_node.getValidPolicy()))
+ {
+ _validPolicyNodeSet.add(_c_node);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) (iii) 2
+ //
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!userInitialPolicySet.contains(_validPolicy))
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+
+ //
+ // (g) (iii) 4
+ //
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes,
+ node);
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ return intersection;
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/ReasonsMask.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/ReasonsMask.java
new file mode 100644
index 0000000..04f5a06
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/ReasonsMask.java
@@ -0,0 +1,101 @@
+package org.bouncycastle.jce.provider;
+
+import org.bouncycastle.asn1.x509.ReasonFlags;
+
+/**
+ * This class helps to handle CRL revocation reasons mask. Each CRL handles a
+ * certain set of revocation reasons.
+ */
+class ReasonsMask
+{
+ private int _reasons;
+
+ /**
+ * Constructs are reason mask with the reasons.
+ *
+ * @param reasons The reasons.
+ */
+ ReasonsMask(ReasonFlags reasons)
+ {
+ _reasons = reasons.intValue();
+ }
+
+ private ReasonsMask(int reasons)
+ {
+ _reasons = reasons;
+ }
+
+ /**
+ * A reason mask with no reason.
+ *
+ */
+ ReasonsMask()
+ {
+ this(0);
+ }
+
+ /**
+ * A mask with all revocation reasons.
+ */
+ static final ReasonsMask allReasons = new ReasonsMask(ReasonFlags.aACompromise
+ | ReasonFlags.affiliationChanged | ReasonFlags.cACompromise
+ | ReasonFlags.certificateHold | ReasonFlags.cessationOfOperation
+ | ReasonFlags.keyCompromise | ReasonFlags.privilegeWithdrawn
+ | ReasonFlags.unused | ReasonFlags.superseded);
+
+ /**
+ * Adds all reasons from the reasons mask to this mask.
+ *
+ * @param mask The reasons mask to add.
+ */
+ void addReasons(ReasonsMask mask)
+ {
+ _reasons = _reasons | mask.getReasons();
+ }
+
+ /**
+ * Returns <code>true</code> if this reasons mask contains all possible
+ * reasons.
+ *
+ * @return <code>true</code> if this reasons mask contains all possible
+ * reasons.
+ */
+ boolean isAllReasons()
+ {
+ return _reasons == allReasons._reasons ? true : false;
+ }
+
+ /**
+ * Intersects this mask with the given reasons mask.
+ *
+ * @param mask The mask to intersect with.
+ * @return The intersection of this and teh given mask.
+ */
+ ReasonsMask intersect(ReasonsMask mask)
+ {
+ ReasonsMask _mask = new ReasonsMask();
+ _mask.addReasons(new ReasonsMask(_reasons & mask.getReasons()));
+ return _mask;
+ }
+
+ /**
+ * Returns <code>true</code> if the passed reasons mask has new reasons.
+ *
+ * @param mask The reasons mask which should be tested for new reasons.
+ * @return <code>true</code> if the passed reasons mask has new reasons.
+ */
+ boolean hasNewReasons(ReasonsMask mask)
+ {
+ return ((_reasons | mask.getReasons() ^ _reasons) != 0);
+ }
+
+ /**
+ * Returns the reasons in this mask.
+ *
+ * @return Returns the reasons.
+ */
+ int getReasons()
+ {
+ return _reasons;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
new file mode 100644
index 0000000..da7ee11
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java
@@ -0,0 +1,296 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.cert.CRLException;
+import java.security.cert.X509CRLEntry;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DEREnumerated;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.CRLReason;
+import org.bouncycastle.asn1.x509.Extension;
+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.x509.extension.X509ExtensionUtil;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRL Entries
+ *
+ * ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+ * (critical)
+ */
+public class X509CRLEntryObject extends X509CRLEntry
+{
+ private TBSCertList.CRLEntry c;
+
+ private X500Name certificateIssuer;
+ private int hashValue;
+ private boolean isHashValueSet;
+
+ public X509CRLEntryObject(TBSCertList.CRLEntry c)
+ {
+ this.c = c;
+ this.certificateIssuer = null;
+ }
+
+ /**
+ * Constructor for CRLEntries of indirect CRLs. If <code>isIndirect</code>
+ * is <code>false</code> {@link #getCertificateIssuer()} will always
+ * return <code>null</code>, <code>previousCertificateIssuer</code> is
+ * ignored. If this <code>isIndirect</code> is specified and this CRLEntry
+ * has no certificate issuer CRL entry extension
+ * <code>previousCertificateIssuer</code> is returned by
+ * {@link #getCertificateIssuer()}.
+ *
+ * @param c
+ * TBSCertList.CRLEntry object.
+ * @param isIndirect
+ * <code>true</code> if the corresponding CRL is a indirect
+ * CRL.
+ * @param previousCertificateIssuer
+ * Certificate issuer of the previous CRLEntry.
+ */
+ public X509CRLEntryObject(
+ TBSCertList.CRLEntry c,
+ boolean isIndirect,
+ X500Name previousCertificateIssuer)
+ {
+ this.c = c;
+ this.certificateIssuer = loadCertificateIssuer(isIndirect, previousCertificateIssuer);
+ }
+
+ /**
+ * Will return true if any extensions are present and marked as critical as
+ * we currently don't handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ return extns != null && !extns.isEmpty();
+ }
+
+ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer)
+ {
+ if (!isIndirect)
+ {
+ return null;
+ }
+
+ byte[] ext = getExtensionValue(X509Extension.certificateIssuer.getId());
+ if (ext == null)
+ {
+ return previousCertificateIssuer;
+ }
+
+ try
+ {
+ GeneralName[] names = GeneralNames.getInstance(
+ X509ExtensionUtil.fromExtensionValue(ext)).getNames();
+ for (int i = 0; i < names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ return X500Name.getInstance(names[i].getName());
+ }
+ }
+ return null;
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public X500Principal getCertificateIssuer()
+ {
+ if (certificateIssuer == null)
+ {
+ return null;
+ }
+ try
+ {
+ return new X500Principal(certificateIssuer.getEncoded());
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Cache the hashCode value - calculating it with the standard method.
+ * @return calculated hashCode.
+ */
+ public int hashCode()
+ {
+ if (!isHashValueSet)
+ {
+ hashValue = super.hashCode();
+ isHashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getUserCertificate().getValue();
+ }
+
+ public Date getRevocationDate()
+ {
+ return c.getRevocationDate().getDate();
+ }
+
+ public boolean hasExtensions()
+ {
+ return c.getExtensions() != null;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" revocationDate: ").append(this.getRevocationDate()).append(nl);
+ buf.append(" certificateIssuer: ").append(this.getCertificateIssuer()).append(nl);
+
+ Extensions extensions = c.getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+ if (e.hasMoreElements())
+ {
+ buf.append(" crlEntryExtensions:").append(nl);
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(X509Extension.reasonCode))
+ {
+ buf.append(CRLReason.getInstance(DEREnumerated.getInstance(dIn.readObject()))).append(nl);
+ }
+ else if (oid.equals(X509Extension.certificateIssuer))
+ {
+ buf.append("Certificate issuer: ").append(GeneralNames.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
new file mode 100644
index 0000000..4c87114
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java
@@ -0,0 +1,576 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DERInteger;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.CRLDistPoint;
+import org.bouncycastle.asn1.x509.CRLNumber;
+import org.bouncycastle.asn1.x509.CertificateList;
+import org.bouncycastle.asn1.x509.Extension;
+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.jce.X509Principal;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * The following extensions are listed in RFC 2459 as relevant to CRLs
+ *
+ * Authority Key Identifier
+ * Issuer Alternative Name
+ * CRL Number
+ * Delta CRL Indicator (critical)
+ * Issuing Distribution Point (critical)
+ */
+public class X509CRLObject
+ extends X509CRL
+{
+ private CertificateList c;
+ private String sigAlgName;
+ private byte[] sigAlgParams;
+ private boolean isIndirect;
+
+ static boolean isIndirectCRL(X509CRL crl)
+ throws CRLException
+ {
+ try
+ {
+ byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
+ return idp != null
+ && IssuingDistributionPoint.getInstance(X509ExtensionUtil.fromExtensionValue(idp)).isIndirectCRL();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCRLException(
+ "Exception reading IssuingDistributionPoint", e);
+ }
+ }
+
+ public X509CRLObject(
+ CertificateList c)
+ throws CRLException
+ {
+ this.c = c;
+
+ try
+ {
+ this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ else
+ {
+ this.sigAlgParams = null;
+ }
+
+ this.isIndirect = isIndirectCRL(this);
+ }
+ catch (Exception e)
+ {
+ throw new CRLException("CRL contents invalid: " + e);
+ }
+ }
+
+ /**
+ * Will return true if any extensions are present and marked
+ * as critical as we currently dont handle any extensions!
+ */
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extns = getCriticalExtensionOIDs();
+
+ if (extns == null)
+ {
+ return false;
+ }
+
+ extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
+ extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
+
+ return !extns.isEmpty();
+ }
+
+ private Set getExtensionOIDs(boolean critical)
+ {
+ if (this.getVersion() == 2)
+ {
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (critical == ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions exts = c.getTBSCertList().getExtensions();
+
+ if (exts != null)
+ {
+ Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getEncoded()
+ throws CRLException
+ {
+ try
+ {
+ return c.getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public void verify(PublicKey key)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ verify(key, BouncyCastleProvider.PROVIDER_NAME);
+ }
+
+ public void verify(PublicKey key, String sigProvider)
+ throws CRLException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
+ {
+ throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
+ }
+
+ Signature sig;
+
+ if (sigProvider != null)
+ {
+ sig = Signature.getInstance(getSigAlgName(), sigProvider);
+ }
+ else
+ {
+ sig = Signature.getInstance(getSigAlgName());
+ }
+
+ sig.initVerify(key);
+ sig.update(this.getTBSCertList());
+
+ if (!sig.verify(this.getSignature()))
+ {
+ throw new SignatureException("CRL does not verify with supplied public key.");
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersionNumber();
+ }
+
+ public Principal getIssuerDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
+ }
+
+ public X500Principal getIssuerX500Principal()
+ {
+ try
+ {
+ return new X500Principal(c.getIssuer().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't encode issuer DN");
+ }
+ }
+
+ public Date getThisUpdate()
+ {
+ return c.getThisUpdate().getDate();
+ }
+
+ public Date getNextUpdate()
+ {
+ if (c.getNextUpdate() != null)
+ {
+ return c.getNextUpdate().getDate();
+ }
+
+ return null;
+ }
+
+ private Set loadCRLEntries()
+ {
+ Set entrySet = new HashSet();
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = null; // the issuer
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+ X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ entrySet.add(crlEntry);
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return entrySet;
+ }
+
+ public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
+ {
+ Enumeration certs = c.getRevokedCertificateEnumeration();
+
+ X500Name previousCertificateIssuer = null; // the issuer
+ while (certs.hasMoreElements())
+ {
+ TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
+
+ if (serialNumber.equals(entry.getUserCertificate().getValue()))
+ {
+ return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
+ }
+
+ if (isIndirect && entry.hasExtensions())
+ {
+ Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getRevokedCertificates()
+ {
+ Set entrySet = loadCRLEntries();
+
+ if (!entrySet.isEmpty())
+ {
+ return Collections.unmodifiableSet(entrySet);
+ }
+
+ return null;
+ }
+
+ public byte[] getTBSCertList()
+ throws CRLException
+ {
+ try
+ {
+ return c.getTBSCertList().getEncoded("DER");
+ }
+ catch (IOException e)
+ {
+ throw new CRLException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ public String getSigAlgName()
+ {
+ return sigAlgName;
+ }
+
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getAlgorithm().getId();
+ }
+
+ public byte[] getSigAlgParams()
+ {
+ if (sigAlgParams != null)
+ {
+ byte[] tmp = new byte[sigAlgParams.length];
+
+ System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a string representation of this CRL.
+ *
+ * @return a string representation of this CRL.
+ */
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" Version: ").append(this.getVersion()).append(
+ nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN())
+ .append(nl);
+ buf.append(" This update: ").append(this.getThisUpdate())
+ .append(nl);
+ buf.append(" Next update: ").append(this.getNextUpdate())
+ .append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName())
+ .append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(
+ new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(
+ new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ Extensions extensions = c.getTBSCertList().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: ").append(nl);
+ }
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.getExtnValue() != null)
+ {
+ byte[] octs = ext.getExtnValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(
+ ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(Extension.cRLNumber))
+ {
+ buf.append(
+ new CRLNumber(DERInteger.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid.equals(Extension.deltaCRLIndicator))
+ {
+ buf.append(
+ "Base CRL: "
+ + new CRLNumber(DERInteger.getInstance(
+ dIn.readObject()).getPositiveValue()))
+ .append(nl);
+ }
+ else if (oid
+ .equals(Extension.issuingDistributionPoint))
+ {
+ buf.append(
+ IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid
+ .equals(Extension.cRLDistributionPoints))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(Extension.freshestCRL))
+ {
+ buf.append(
+ CRLDistPoint.getInstance(dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(
+ ASN1Dump.dumpAsString(dIn.readObject()))
+ .append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+ Set set = getRevokedCertificates();
+ if (set != null)
+ {
+ Iterator it = set.iterator();
+ while (it.hasNext())
+ {
+ buf.append(it.next());
+ buf.append(nl);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Checks whether the given certificate is on this CRL.
+ *
+ * @param cert the certificate to check for.
+ * @return true if the given certificate is on this CRL,
+ * false otherwise.
+ */
+ public boolean isRevoked(Certificate cert)
+ {
+ if (!cert.getType().equals("X.509"))
+ {
+ throw new RuntimeException("X.509 CRL used with non X.509 Cert");
+ }
+
+ TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
+
+ X500Name caName = c.getIssuer();
+
+ if (certs != null)
+ {
+ BigInteger serial = ((X509Certificate)cert).getSerialNumber();
+
+ for (int i = 0; i < certs.length; i++)
+ {
+ if (isIndirect && certs[i].hasExtensions())
+ {
+ Extension currentCaName = certs[i].getExtensions().getExtension(Extension.certificateIssuer);
+
+ if (currentCaName != null)
+ {
+ caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
+ }
+ }
+
+ if (certs[i].getUserCertificate().getValue().equals(serial))
+ {
+ X500Name issuer;
+
+ if (cert instanceof X509Certificate)
+ {
+ issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded());
+ }
+ else
+ {
+ try
+ {
+ issuer = org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
+ }
+ catch (CertificateEncodingException e)
+ {
+ throw new RuntimeException("Cannot process certificate");
+ }
+ }
+
+ if (!caName.equals(issuer))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
+
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
new file mode 100644
index 0000000..e529836
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
@@ -0,0 +1,826 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+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.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;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OutputStream;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.asn1.misc.NetscapeCertType;
+import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.asn1.misc.VerisignCzagExtension;
+import org.bouncycastle.asn1.util.ASN1Dump;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.KeyUsage;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+
+public class X509CertificateObject
+ extends X509Certificate
+ implements PKCS12BagAttributeCarrier
+{
+ private X509CertificateStructure c;
+ private BasicConstraints basicConstraints;
+ private boolean[] keyUsage;
+ private boolean hashValueSet;
+ private int hashValue;
+
+ private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl();
+
+ public X509CertificateObject(
+ X509CertificateStructure c)
+ throws CertificateParsingException
+ {
+ this.c = c;
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.19");
+
+ if (bytes != null)
+ {
+ basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct BasicConstraints: " + e);
+ }
+
+ try
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.15");
+ if (bytes != null)
+ {
+ DERBitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes));
+
+ bytes = bits.getBytes();
+ int length = (bytes.length * 8) - bits.getPadBits();
+
+ keyUsage = new boolean[(length < 9) ? 9 : length];
+
+ for (int i = 0; i != length; i++)
+ {
+ keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+ }
+ else
+ {
+ keyUsage = null;
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("cannot construct KeyUsage: " + e);
+ }
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility
+ {
+ throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime());
+ }
+
+ if (date.getTime() < this.getNotBefore().getTime())
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime());
+ }
+ }
+
+ public int getVersion()
+ {
+ return c.getVersion();
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return c.getSerialNumber().getValue();
+ }
+
+ public Principal getIssuerDN()
+ {
+ try
+ {
+ return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+
+ public X500Principal getIssuerX500Principal()
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(c.getIssuer());
+
+ return new X500Principal(bOut.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't encode issuer DN");
+ }
+ }
+
+ public Principal getSubjectDN()
+ {
+ return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive()));
+ }
+
+ public X500Principal getSubjectX500Principal()
+ {
+ try
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(c.getSubject());
+
+ return new X500Principal(bOut.toByteArray());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("can't encode issuer DN");
+ }
+ }
+
+ public Date getNotBefore()
+ {
+ return c.getStartDate().getDate();
+ }
+
+ public Date getNotAfter()
+ {
+ return c.getEndDate().getDate();
+ }
+
+ public byte[] getTBSCertificate()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ return c.getTBSCertificate().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return c.getSignature().getBytes();
+ }
+
+ /**
+ * return a more "meaningful" representation for the signature algorithm used in
+ * the certficate.
+ */
+ 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 the object identifier for the signature.
+ */
+ public String getSigAlgOID()
+ {
+ return c.getSignatureAlgorithm().getObjectId().getId();
+ }
+
+ /**
+ * return the signature parameters, or null if there aren't any.
+ */
+ public byte[] getSigAlgParams()
+ {
+ if (c.getSignatureAlgorithm().getParameters() != null)
+ {
+ try
+ {
+ return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER);
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getIssuerUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getSubjectUniqueID()
+ {
+ DERBitString id = c.getTBSCertificate().getSubjectUniqueId();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public boolean[] getKeyUsage()
+ {
+ return keyUsage;
+ }
+
+ public List getExtendedKeyUsage()
+ throws CertificateParsingException
+ {
+ byte[] bytes = this.getExtensionBytes("2.5.29.37");
+
+ if (bytes != null)
+ {
+ try
+ {
+ ASN1InputStream dIn = new ASN1InputStream(bytes);
+ ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ list.add(((DERObjectIdentifier)seq.getObjectAt(i)).getId());
+ }
+
+ return Collections.unmodifiableList(list);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("error processing extended key usage extension");
+ }
+ }
+
+ return null;
+ }
+
+ public int getBasicConstraints()
+ {
+ if (basicConstraints != null)
+ {
+ if (basicConstraints.isCA())
+ {
+ if (basicConstraints.getPathLenConstraint() == null)
+ {
+ return Integer.MAX_VALUE;
+ }
+ else
+ {
+ return basicConstraints.getPathLenConstraint().intValue();
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return -1;
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ X509Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ private byte[] getExtensionBytes(String oid)
+ {
+ X509Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
+ if (ext != null)
+ {
+ return ext.getValue().getOctets();
+ }
+ }
+
+ return null;
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ X509Extensions exts = c.getTBSCertificate().getExtensions();
+
+ if (exts != null)
+ {
+ X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getValue().getEncoded();
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException("error parsing " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ if (this.getVersion() == 3)
+ {
+ Set set = new HashSet();
+ X509Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (!ext.isCritical())
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+ }
+
+ return null;
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ if (this.getVersion() == 3)
+ {
+ X509Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)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))
+ {
+ continue;
+ }
+
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical())
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public PublicKey getPublicKey()
+ {
+ try
+ {
+ return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo());
+ }
+ catch (IOException e)
+ {
+ return null; // should never happen...
+ }
+ }
+
+ // BEGIN android-changed
+ private byte[] encoded;
+ // END android-changed
+ public byte[] getEncoded()
+ throws CertificateEncodingException
+ {
+ try
+ {
+ // BEGIN android-changed
+ if (encoded == null) {
+ encoded = c.getEncoded(ASN1Encoding.DER);
+ }
+ return encoded;
+ // END android-changed
+ }
+ catch (IOException e)
+ {
+ throw new CertificateEncodingException(e.toString());
+ }
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof Certificate))
+ {
+ return false;
+ }
+
+ Certificate other = (Certificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+ }
+
+ public synchronized int hashCode()
+ {
+ if (!hashValueSet)
+ {
+ hashValue = calculateHashCode();
+ hashValueSet = true;
+ }
+
+ return hashValue;
+ }
+
+ private int calculateHashCode()
+ {
+ try
+ {
+ int hashCode = 0;
+ byte[] certData = this.getEncoded();
+ for (int i = 1; i < certData.length; i++)
+ {
+ hashCode += certData[i] * i;
+ }
+ return hashCode;
+ }
+ catch (CertificateEncodingException e)
+ {
+ return 0;
+ }
+ }
+
+ public void setBagAttribute(
+ ASN1ObjectIdentifier oid,
+ ASN1Encodable attribute)
+ {
+ attrCarrier.setBagAttribute(oid, attribute);
+ }
+
+ public ASN1Encodable getBagAttribute(
+ DERObjectIdentifier oid)
+ {
+ return attrCarrier.getBagAttribute(oid);
+ }
+
+ public Enumeration getBagAttributeKeys()
+ {
+ return attrCarrier.getBagAttributeKeys();
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ String nl = System.getProperty("line.separator");
+
+ buf.append(" [0] Version: ").append(this.getVersion()).append(nl);
+ buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl);
+ buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl);
+ buf.append(" Start Date: ").append(this.getNotBefore()).append(nl);
+ buf.append(" Final Date: ").append(this.getNotAfter()).append(nl);
+ buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl);
+ buf.append(" Public Key: ").append(this.getPublicKey()).append(nl);
+ buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl);
+
+ byte[] sig = this.getSignature();
+
+ buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
+ for (int i = 20; i < sig.length; i += 20)
+ {
+ if (i < sig.length - 20)
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
+ }
+ else
+ {
+ buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
+ }
+ }
+
+ X509Extensions extensions = c.getTBSCertificate().getExtensions();
+
+ if (extensions != null)
+ {
+ Enumeration e = extensions.oids();
+
+ if (e.hasMoreElements())
+ {
+ buf.append(" Extensions: \n");
+ }
+
+ while (e.hasMoreElements())
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
+ X509Extension ext = extensions.getExtension(oid);
+
+ if (ext.getValue() != null)
+ {
+ byte[] octs = ext.getValue().getOctets();
+ ASN1InputStream dIn = new ASN1InputStream(octs);
+ buf.append(" critical(").append(ext.isCritical()).append(") ");
+ try
+ {
+ if (oid.equals(X509Extension.basicConstraints))
+ {
+ buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(X509Extension.keyUsage))
+ {
+ buf.append(new KeyUsage((DERBitString)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeCertType))
+ {
+ buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL))
+ {
+ buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension))
+ {
+ buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl);
+ }
+ else
+ {
+ buf.append(oid.getId());
+ buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
+ //buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ catch (Exception ex)
+ {
+ buf.append(oid.getId());
+ // buf.append(" value = ").append(new String(Hex.encode(ext.getValue().getOctets()))).append(nl);
+ buf.append(" value = ").append("*****").append(nl);
+ }
+ }
+ else
+ {
+ buf.append(nl);
+ }
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public final void verify(
+ PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature;
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+
+ try
+ {
+ signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (Exception e)
+ {
+ signature = Signature.getInstance(sigName);
+ }
+
+ checkSignature(key, signature);
+ }
+
+ public final void verify(
+ PublicKey key,
+ String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
+ Signature signature = Signature.getInstance(sigName, sigProvider);
+
+ checkSignature(key, signature);
+ }
+
+ private void checkSignature(
+ PublicKey key,
+ Signature signature)
+ throws CertificateException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException
+ {
+ if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature()))
+ {
+ throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
+ }
+
+ ASN1Encodable params = c.getSignatureAlgorithm().getParameters();
+
+ // TODO This should go after the initVerify?
+ X509SignatureUtil.setSignatureParameters(signature, params);
+
+ signature.initVerify(key);
+
+ signature.update(this.getTBSCertificate());
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new SignatureException("certificate does not verify with supplied key");
+ }
+ }
+
+ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2)
+ {
+ if (!id1.getObjectId().equals(id2.getObjectId()))
+ {
+ return false;
+ }
+
+ if (id1.getParameters() == null)
+ {
+ if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ if (id2.getParameters() == null)
+ {
+ if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return id1.getParameters().equals(id2.getParameters());
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
new file mode 100644
index 0000000..8e492dc
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
@@ -0,0 +1,148 @@
+package org.bouncycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+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.ASN1Sequence;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+// 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;
+import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+
+class X509SignatureUtil
+{
+ // BEGIN android-changed
+ private static final ASN1Null derNull = DERNull.INSTANCE;
+ // END android-changed
+
+ static void setSignatureParameters(
+ Signature signature,
+ ASN1Encodable params)
+ throws NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ if (params != null && !derNull.equals(params))
+ {
+ AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider());
+
+ try
+ {
+ sigParams.init(params.toASN1Primitive().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("IOException decoding parameters: " + e.getMessage());
+ }
+
+ if (signature.getAlgorithm().endsWith("MGF1"))
+ {
+ try
+ {
+ signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ static String getSignatureName(
+ AlgorithmIdentifier sigAlgId)
+ {
+ ASN1Encodable params = sigAlgId.getParameters();
+
+ if (params != null && !derNull.equals(params))
+ {
+ // BEGIN android-removed
+ // if (sigAlgId.getObjectId().equals(PKCSObjectIdentifiers.id_RSASSA_PSS))
+ // {
+ // RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params);
+ //
+ // return getDigestAlgName(rsaParams.getHashAlgorithm().getObjectId()) + "withRSAandMGF1";
+ // }
+ // END android-removed
+ if (sigAlgId.getObjectId().equals(X9ObjectIdentifiers.ecdsa_with_SHA2))
+ {
+ ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params);
+
+ return getDigestAlgName((DERObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA";
+ }
+ }
+
+ return sigAlgId.getObjectId().getId();
+ }
+
+ /**
+ * Return the digest algorithm using one of the standard JCA string
+ * representations rather the the algorithm identifier (if possible).
+ */
+ private static String getDigestAlgName(
+ DERObjectIdentifier digestAlgOID)
+ {
+ if (PKCSObjectIdentifiers.md5.equals(digestAlgOID))
+ {
+ return "MD5";
+ }
+ else if (OIWObjectIdentifiers.idSHA1.equals(digestAlgOID))
+ {
+ return "SHA1";
+ }
+ // BEGIN android-removed
+ // else if (NISTObjectIdentifiers.id_sha224.equals(digestAlgOID))
+ // {
+ // return "SHA224";
+ // }
+ // END android-removed
+ 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/bcprov/src/main/java/org/bouncycastle/jce/spec/ECKeySpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECKeySpec.java
new file mode 100644
index 0000000..1215784
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECKeySpec.java
@@ -0,0 +1,26 @@
+package org.bouncycastle.jce.spec;
+
+import java.security.spec.KeySpec;
+
+/**
+ * base class for an Elliptic Curve Key Spec
+ */
+public class ECKeySpec
+ implements KeySpec
+{
+ private ECParameterSpec spec;
+
+ protected ECKeySpec(
+ ECParameterSpec spec)
+ {
+ this.spec = spec;
+ }
+
+ /**
+ * return the domain parameters for the curve
+ */
+ public ECParameterSpec getParams()
+ {
+ return spec;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java
new file mode 100644
index 0000000..a5dd319
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveGenParameterSpec.java
@@ -0,0 +1,28 @@
+package org.bouncycastle.jce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * Named curve generation spec
+ * <p>
+ * If you are using JDK 1.5 you should be looking at ECGenParameterSpec.
+ */
+public class ECNamedCurveGenParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private String name;
+
+ public ECNamedCurveGenParameterSpec(
+ String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * return the name of the curve the EC domain parameters belong to.
+ */
+ public String getName()
+ {
+ return name;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java
new file mode 100644
index 0000000..47416a2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveParameterSpec.java
@@ -0,0 +1,62 @@
+package org.bouncycastle.jce.spec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * specification signifying that the curve parameters can also be
+ * refered to by name.
+ * <p>
+ * If you are using JDK 1.5 you should be looking at ECNamedCurveSpec.
+ */
+public class ECNamedCurveParameterSpec
+ extends ECParameterSpec
+{
+ private String name;
+
+ public ECNamedCurveParameterSpec(
+ String name,
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n)
+ {
+ super(curve, G, n);
+
+ this.name = name;
+ }
+
+ public ECNamedCurveParameterSpec(
+ String name,
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h)
+ {
+ super(curve, G, n, h);
+
+ this.name = name;
+ }
+
+ public ECNamedCurveParameterSpec(
+ String name,
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ super(curve, G, n, h, seed);
+
+ this.name = name;
+ }
+
+ /**
+ * return the name of the curve the EC domain parameters belong to.
+ */
+ public String getName()
+ {
+ return name;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java
new file mode 100644
index 0000000..84ebf70
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECNamedCurveSpec.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.jce.spec;
+
+import java.math.BigInteger;
+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.ECCurve;
+
+/**
+ * specification signifying that the curve parameters can also be
+ * referred to by name.
+ */
+public class ECNamedCurveSpec
+ extends java.security.spec.ECParameterSpec
+{
+ private String name;
+
+ private static EllipticCurve convertCurve(
+ ECCurve curve,
+ byte[] seed)
+ {
+ if (curve instanceof ECCurve.Fp)
+ {
+ return new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), seed);
+ }
+ else
+ {
+ 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);
+ }
+ }
+
+ }
+
+ private static ECPoint convertPoint(
+ org.bouncycastle.math.ec.ECPoint g)
+ {
+ return new ECPoint(g.getX().toBigInteger(), g.getY().toBigInteger());
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ ECCurve curve,
+ org.bouncycastle.math.ec.ECPoint g,
+ BigInteger n)
+ {
+ super(convertCurve(curve, null), convertPoint(g), n, 1);
+
+ this.name = name;
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ EllipticCurve curve,
+ ECPoint g,
+ BigInteger n)
+ {
+ super(curve, g, n, 1);
+
+ this.name = name;
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ ECCurve curve,
+ org.bouncycastle.math.ec.ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ {
+ super(convertCurve(curve, null), convertPoint(g), n, h.intValue());
+
+ this.name = name;
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ EllipticCurve curve,
+ ECPoint g,
+ BigInteger n,
+ BigInteger h)
+ {
+ super(curve, g, n, h.intValue());
+
+ this.name = name;
+ }
+
+ public ECNamedCurveSpec(
+ String name,
+ ECCurve curve,
+ org.bouncycastle.math.ec.ECPoint g,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ super(convertCurve(curve, seed), convertPoint(g), n, h.intValue());
+
+ this.name = name;
+ }
+
+ /**
+ * return the name of the curve the EC domain parameters belong to.
+ */
+ public String getName()
+ {
+ return name;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java
new file mode 100644
index 0000000..e774a11
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECParameterSpec.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.jce.spec;
+
+import org.bouncycastle.math.ec.ECCurve;
+import org.bouncycastle.math.ec.ECPoint;
+
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * basic domain parameters for an Elliptic Curve public or private key.
+ */
+public class ECParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private ECCurve curve;
+ private byte[] seed;
+ private ECPoint G;
+ private BigInteger n;
+ private BigInteger h;
+
+ public ECParameterSpec(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n)
+ {
+ this.curve = curve;
+ this.G = G;
+ this.n = n;
+ this.h = BigInteger.valueOf(1);
+ this.seed = null;
+ }
+
+ public ECParameterSpec(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h)
+ {
+ this.curve = curve;
+ this.G = G;
+ this.n = n;
+ this.h = h;
+ this.seed = null;
+ }
+
+ public ECParameterSpec(
+ ECCurve curve,
+ ECPoint G,
+ BigInteger n,
+ BigInteger h,
+ byte[] seed)
+ {
+ this.curve = curve;
+ this.G = G;
+ this.n = n;
+ this.h = h;
+ this.seed = seed;
+ }
+
+ /**
+ * return the curve along which the base point lies.
+ * @return the curve
+ */
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ /**
+ * return the base point we are using for these domain parameters.
+ * @return the base point.
+ */
+ public ECPoint getG()
+ {
+ return G;
+ }
+
+ /**
+ * return the order N of G
+ * @return the order
+ */
+ public BigInteger getN()
+ {
+ return n;
+ }
+
+ /**
+ * return the cofactor H to the order of G.
+ * @return the cofactor
+ */
+ public BigInteger getH()
+ {
+ return h;
+ }
+
+ /**
+ * return the seed used to generate this curve (if available).
+ * @return the random seed
+ */
+ public byte[] getSeed()
+ {
+ return seed;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof ECParameterSpec))
+ {
+ return false;
+ }
+
+ ECParameterSpec other = (ECParameterSpec)o;
+
+ return this.getCurve().equals(other.getCurve()) && this.getG().equals(other.getG());
+ }
+
+ public int hashCode()
+ {
+ return this.getCurve().hashCode() ^ this.getG().hashCode();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPrivateKeySpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPrivateKeySpec.java
new file mode 100644
index 0000000..27885c4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPrivateKeySpec.java
@@ -0,0 +1,35 @@
+package org.bouncycastle.jce.spec;
+
+import java.math.BigInteger;
+
+/**
+ * Elliptic Curve private key specification.
+ */
+public class ECPrivateKeySpec
+ extends ECKeySpec
+{
+ private BigInteger d;
+
+ /**
+ * base constructor
+ *
+ * @param d the private number for the key.
+ * @param spec the domain parameters for the curve being used.
+ */
+ public ECPrivateKeySpec(
+ BigInteger d,
+ ECParameterSpec spec)
+ {
+ super(spec);
+
+ this.d = d;
+ }
+
+ /**
+ * return the private number D
+ */
+ public BigInteger getD()
+ {
+ return d;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java
new file mode 100644
index 0000000..debab00
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/ECPublicKeySpec.java
@@ -0,0 +1,35 @@
+package org.bouncycastle.jce.spec;
+
+import org.bouncycastle.math.ec.ECPoint;
+
+/**
+ * Elliptic Curve public key specification
+ */
+public class ECPublicKeySpec
+ extends ECKeySpec
+{
+ private ECPoint q;
+
+ /**
+ * base constructor
+ *
+ * @param q the public point on the curve.
+ * @param spec the domain parameters for the curve.
+ */
+ public ECPublicKeySpec(
+ ECPoint q,
+ ECParameterSpec spec)
+ {
+ super(spec);
+
+ this.q = q;
+ }
+
+ /**
+ * return the public point q
+ */
+ public ECPoint getQ()
+ {
+ return q;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java b/bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java
new file mode 100644
index 0000000..2a7ceb5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/jce/spec/RepeatedSecretKeySpec.java
@@ -0,0 +1,34 @@
+package org.bouncycastle.jce.spec;
+
+
+import javax.crypto.SecretKey;
+
+/**
+ * A simple object to indicate that a symmetric cipher should reuse the
+ * last key provided.
+ */
+public class RepeatedSecretKeySpec
+ implements SecretKey
+{
+ private String algorithm;
+
+ public RepeatedSecretKeySpec(String algorithm)
+ {
+ this.algorithm = algorithm;
+ }
+
+ public String getAlgorithm()
+ {
+ return algorithm;
+ }
+
+ public String getFormat()
+ {
+ return null;
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
new file mode 100644
index 0000000..78a7a8f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java
@@ -0,0 +1,92 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+public class ECAlgorithms
+{
+ public static ECPoint sumOfTwoMultiplies(ECPoint P, BigInteger a,
+ ECPoint Q, BigInteger b)
+ {
+ ECCurve c = P.getCurve();
+ if (!c.equals(Q.getCurve()))
+ {
+ throw new IllegalArgumentException("P and Q must be on same curve");
+ }
+
+ // Point multiplication for Koblitz curves (using WTNAF) beats Shamir's trick
+ if (c instanceof ECCurve.F2m)
+ {
+ ECCurve.F2m f2mCurve = (ECCurve.F2m)c;
+ if (f2mCurve.isKoblitz())
+ {
+ return P.multiply(a).add(Q.multiply(b));
+ }
+ }
+
+ return implShamirsTrick(P, a, Q, b);
+ }
+
+ /*
+ * "Shamir's Trick", originally due to E. G. Straus
+ * (Addition chains of vectors. American Mathematical Monthly,
+ * 71(7):806-808, Aug./Sept. 1964)
+ * <pre>
+ * Input: The points P, Q, scalar k = (km?, ... , k1, k0)
+ * and scalar l = (lm?, ... , l1, l0).
+ * Output: R = k * P + l * Q.
+ * 1: Z <- P + Q
+ * 2: R <- O
+ * 3: for i from m-1 down to 0 do
+ * 4: R <- R + R {point doubling}
+ * 5: if (ki = 1) and (li = 0) then R <- R + P end if
+ * 6: if (ki = 0) and (li = 1) then R <- R + Q end if
+ * 7: if (ki = 1) and (li = 1) then R <- R + Z end if
+ * 8: end for
+ * 9: return R
+ * </pre>
+ */
+ public static ECPoint shamirsTrick(ECPoint P, BigInteger k,
+ ECPoint Q, BigInteger l)
+ {
+ if (!P.getCurve().equals(Q.getCurve()))
+ {
+ throw new IllegalArgumentException("P and Q must be on same curve");
+ }
+
+ return implShamirsTrick(P, k, Q, l);
+ }
+
+ private static ECPoint implShamirsTrick(ECPoint P, BigInteger k,
+ ECPoint Q, BigInteger l)
+ {
+ int m = Math.max(k.bitLength(), l.bitLength());
+ ECPoint Z = P.add(Q);
+ ECPoint R = P.getCurve().getInfinity();
+
+ for (int i = m - 1; i >= 0; --i)
+ {
+ R = R.twice();
+
+ if (k.testBit(i))
+ {
+ if (l.testBit(i))
+ {
+ R = R.add(Z);
+ }
+ else
+ {
+ R = R.add(P);
+ }
+ }
+ else
+ {
+ if (l.testBit(i))
+ {
+ R = R.add(Q);
+ }
+ }
+ }
+
+ return R;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECConstants.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECConstants.java
new file mode 100644
index 0000000..864f746
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECConstants.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+public interface ECConstants
+{
+ public static final BigInteger ZERO = BigInteger.valueOf(0);
+ public static final BigInteger ONE = BigInteger.valueOf(1);
+ public static final BigInteger TWO = BigInteger.valueOf(2);
+ public static final BigInteger THREE = BigInteger.valueOf(3);
+ public static final BigInteger FOUR = BigInteger.valueOf(4);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java
new file mode 100644
index 0000000..c984104
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECCurve.java
@@ -0,0 +1,668 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+/**
+ * base class for an elliptic curve
+ */
+public abstract class ECCurve
+{
+ ECFieldElement a, b;
+
+ public abstract int getFieldSize();
+
+ public abstract ECFieldElement fromBigInteger(BigInteger x);
+
+ public abstract ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression);
+
+ public abstract ECPoint decodePoint(byte[] encoded);
+
+ public abstract ECPoint getInfinity();
+
+ public ECFieldElement getA()
+ {
+ return a;
+ }
+
+ public ECFieldElement getB()
+ {
+ return b;
+ }
+
+ /**
+ * Elliptic curve over Fp
+ */
+ public static class Fp extends ECCurve
+ {
+ BigInteger q;
+ ECPoint.Fp infinity;
+
+ public Fp(BigInteger q, BigInteger a, BigInteger b)
+ {
+ this.q = q;
+ this.a = fromBigInteger(a);
+ this.b = fromBigInteger(b);
+ this.infinity = new ECPoint.Fp(this, null, null);
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public int getFieldSize()
+ {
+ return q.bitLength();
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new ECFieldElement.Fp(this.q, x);
+ }
+
+ public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+ {
+ return new ECPoint.Fp(this, fromBigInteger(x), fromBigInteger(y), withCompression);
+ }
+
+ /**
+ * Decode a point on this curve from its ASN.1 encoding. The different
+ * encodings are taken account of, including point compression for
+ * <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17).
+ * @return The decoded point.
+ */
+ public ECPoint decodePoint(byte[] encoded)
+ {
+ ECPoint p = null;
+
+ switch (encoded[0])
+ {
+ // infinity
+ case 0x00:
+ if (encoded.length > 1)
+ {
+ throw new RuntimeException("Invalid point encoding");
+ }
+ p = getInfinity();
+ break;
+ // compressed
+ case 0x02:
+ case 0x03:
+ int ytilde = encoded[0] & 1;
+ byte[] i = new byte[encoded.length - 1];
+
+ System.arraycopy(encoded, 1, i, 0, i.length);
+
+ ECFieldElement x = new ECFieldElement.Fp(this.q, new BigInteger(1, i));
+ ECFieldElement alpha = x.multiply(x.square().add(a)).add(b);
+ ECFieldElement beta = alpha.sqrt();
+
+ //
+ // if we can't find a sqrt we haven't got a point on the
+ // curve - run!
+ //
+ if (beta == null)
+ {
+ throw new RuntimeException("Invalid point compression");
+ }
+
+ int bit0 = (beta.toBigInteger().testBit(0) ? 1 : 0);
+
+ if (bit0 == ytilde)
+ {
+ p = new ECPoint.Fp(this, x, beta, true);
+ }
+ else
+ {
+ p = new ECPoint.Fp(this, x,
+ new ECFieldElement.Fp(this.q, q.subtract(beta.toBigInteger())), true);
+ }
+ break;
+ // uncompressed
+ case 0x04:
+ // hybrid
+ case 0x06:
+ case 0x07:
+ byte[] xEnc = new byte[(encoded.length - 1) / 2];
+ byte[] yEnc = new byte[(encoded.length - 1) / 2];
+
+ System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
+ System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
+
+ p = new ECPoint.Fp(this,
+ new ECFieldElement.Fp(this.q, new BigInteger(1, xEnc)),
+ new ECFieldElement.Fp(this.q, new BigInteger(1, yEnc)));
+ break;
+ default:
+ throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
+ }
+
+ return p;
+ }
+
+ public ECPoint getInfinity()
+ {
+ return infinity;
+ }
+
+ public boolean equals(
+ Object anObject)
+ {
+ if (anObject == this)
+ {
+ return true;
+ }
+
+ if (!(anObject instanceof ECCurve.Fp))
+ {
+ return false;
+ }
+
+ ECCurve.Fp other = (ECCurve.Fp) anObject;
+
+ return this.q.equals(other.q)
+ && a.equals(other.a) && b.equals(other.b);
+ }
+
+ public int hashCode()
+ {
+ return a.hashCode() ^ b.hashCode() ^ q.hashCode();
+ }
+ }
+
+ /**
+ * Elliptic curves over F2m. The Weierstrass equation is given by
+ * <code>y<sup>2</sup> + xy = x<sup>3</sup> + ax<sup>2</sup> + b</code>.
+ */
+ public static class F2m extends ECCurve
+ {
+ /**
+ * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+ */
+ private int m; // can't be final - JDK 1.1
+
+ /**
+ * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+ * x<sup>k</sup> + 1</code> represents the reduction polynomial
+ * <code>f(z)</code>.<br>
+ * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ private int k1; // can't be final - JDK 1.1
+
+ /**
+ * TPB: Always set to <code>0</code><br>
+ * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ private int k2; // can't be final - JDK 1.1
+
+ /**
+ * TPB: Always set to <code>0</code><br>
+ * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ 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 <code>&mu;</code> of the elliptic curve if this is
+ * a Koblitz curve.
+ */
+ private byte mu = 0;
+
+ /**
+ * The auxiliary values <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code> used for partial modular reduction for
+ * Koblitz curves.
+ */
+ private BigInteger[] si = null;
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+ * x<sup>k</sup> + 1</code> represents the reduction
+ * polynomial <code>f(z)</code>.
+ * @param a The coefficient <code>a</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param b The coefficient <code>b</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ */
+ public F2m(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b)
+ {
+ this(m, k, 0, 0, a, b, null, null);
+ }
+
+ /**
+ * Constructor for Trinomial Polynomial Basis (TPB).
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+ * x<sup>k</sup> + 1</code> represents the reduction
+ * polynomial <code>f(z)</code>.
+ * @param a The coefficient <code>a</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param b The coefficient <code>b</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param n The order of the main subgroup of the elliptic curve.
+ * @param h The cofactor of the elliptic curve, i.e.
+ * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+ */
+ public F2m(
+ int m,
+ int k,
+ BigInteger a,
+ BigInteger b,
+ BigInteger n,
+ BigInteger h)
+ {
+ this(m, k, 0, 0, a, b, n, h);
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param a The coefficient <code>a</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param b The coefficient <code>b</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ */
+ public F2m(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b)
+ {
+ this(m, k1, k2, k3, a, b, null, null);
+ }
+
+ /**
+ * Constructor for Pentanomial Polynomial Basis (PPB).
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param a The coefficient <code>a</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param b The coefficient <code>b</code> in the Weierstrass equation
+ * for non-supersingular elliptic curves over
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param n The order of the main subgroup of the elliptic curve.
+ * @param h The cofactor of the elliptic curve, i.e.
+ * <code>#E<sub>a</sub>(F<sub>2<sup>m</sup></sub>) = h * n</code>.
+ */
+ public F2m(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger a,
+ BigInteger b,
+ BigInteger n,
+ BigInteger h)
+ {
+ 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.a = fromBigInteger(a);
+ this.b = fromBigInteger(b);
+ this.infinity = new ECPoint.F2m(this, null, null);
+ }
+
+ public int getFieldSize()
+ {
+ return m;
+ }
+
+ public ECFieldElement fromBigInteger(BigInteger x)
+ {
+ return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x);
+ }
+
+ public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression)
+ {
+ return new ECPoint.F2m(this, fromBigInteger(x), fromBigInteger(y), withCompression);
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECCurve#decodePoint(byte[])
+ */
+ public ECPoint decodePoint(byte[] encoded)
+ {
+ ECPoint p = null;
+
+ switch (encoded[0])
+ {
+ // infinity
+ case 0x00:
+ if (encoded.length > 1)
+ {
+ throw new RuntimeException("Invalid point encoding");
+ }
+ p = getInfinity();
+ break;
+ // compressed
+ case 0x02:
+ case 0x03:
+ byte[] enc = new byte[encoded.length - 1];
+ System.arraycopy(encoded, 1, enc, 0, enc.length);
+ if (encoded[0] == 0x02)
+ {
+ p = decompressPoint(enc, 0);
+ }
+ else
+ {
+ p = decompressPoint(enc, 1);
+ }
+ break;
+ // uncompressed
+ case 0x04:
+ // hybrid
+ case 0x06:
+ case 0x07:
+ byte[] xEnc = new byte[(encoded.length - 1) / 2];
+ byte[] yEnc = new byte[(encoded.length - 1) / 2];
+
+ System.arraycopy(encoded, 1, xEnc, 0, xEnc.length);
+ System.arraycopy(encoded, xEnc.length + 1, yEnc, 0, yEnc.length);
+
+ p = new ECPoint.F2m(this,
+ new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
+ new BigInteger(1, xEnc)),
+ new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3,
+ new BigInteger(1, yEnc)), false);
+ break;
+
+ default:
+ throw new RuntimeException("Invalid point encoding 0x" + Integer.toString(encoded[0], 16));
+ }
+
+ return p;
+ }
+
+ 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.toBigInteger().equals(ECConstants.ZERO)) ||
+ (a.toBigInteger().equals(ECConstants.ONE))) &&
+ (b.toBigInteger().equals(ECConstants.ONE)));
+ }
+
+ /**
+ * Returns the parameter <code>&mu;</code> of the elliptic curve.
+ * @return <code>&mu;</code> 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 <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code> used for partial modular reduction for
+ * Koblitz curves.
+ */
+ synchronized BigInteger[] getSi()
+ {
+ if (si == null)
+ {
+ si = Tnaf.getSi(this);
+ }
+ return si;
+ }
+
+ /**
+ * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
+ *
+ * @param xEnc
+ * The encoding of field element xp.
+ * @param ypBit
+ * ~yp, an indication bit for the decompression of yp.
+ * @return the decompressed point.
+ */
+ private ECPoint decompressPoint(
+ byte[] xEnc,
+ int ypBit)
+ {
+ ECFieldElement xp = new ECFieldElement.F2m(
+ this.m, this.k1, this.k2, this.k3, new BigInteger(1, xEnc));
+ ECFieldElement yp = null;
+ if (xp.toBigInteger().equals(ECConstants.ZERO))
+ {
+ 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 = solveQuadradicEquation(beta);
+ if (z == null)
+ {
+ throw new RuntimeException("Invalid point compression");
+ }
+ int zBit = 0;
+ if (z.toBigInteger().testBit(0))
+ {
+ zBit = 1;
+ }
+ if (zBit != ypBit)
+ {
+ z = z.add(new ECFieldElement.F2m(this.m, this.k1, this.k2,
+ this.k3, ECConstants.ONE));
+ }
+ yp = xp.multiply(z);
+ }
+
+ return new ECPoint.F2m(this, xp, yp);
+ }
+
+ /**
+ * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+ * D.1.6) The other solution is <code>z + 1</code>.
+ *
+ * @param beta
+ * The value to solve the qradratic equation for.
+ * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+ * <code>null</code> if no solution exists.
+ */
+ private ECFieldElement solveQuadradicEquation(ECFieldElement beta)
+ {
+ ECFieldElement zeroElement = new ECFieldElement.F2m(
+ this.m, this.k1, this.k2, this.k3, ECConstants.ZERO);
+
+ if (beta.toBigInteger().equals(ECConstants.ZERO))
+ {
+ return zeroElement;
+ }
+
+ ECFieldElement z = null;
+ ECFieldElement gamma = zeroElement;
+
+ Random rand = new Random();
+ do
+ {
+ ECFieldElement t = new ECFieldElement.F2m(this.m, this.k1,
+ this.k2, this.k3, 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.toBigInteger().equals(ECConstants.ZERO))
+ {
+ return null;
+ }
+ gamma = z.square().add(z);
+ }
+ while (gamma.toBigInteger().equals(ECConstants.ZERO));
+
+ 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()
+ {
+ return this.a.hashCode() ^ this.b.hashCode() ^ m ^ k1 ^ k2 ^ k3;
+ }
+
+ public int getM()
+ {
+ return m;
+ }
+
+ /**
+ * Return true if curve uses a Trinomial basis.
+ *
+ * @return true if curve Trinomial, false otherwise.
+ */
+ public boolean isTrinomial()
+ {
+ return k2 == 0 && k3 == 0;
+ }
+
+ public int getK1()
+ {
+ return k1;
+ }
+
+ public int getK2()
+ {
+ return k2;
+ }
+
+ public int getK3()
+ {
+ return k3;
+ }
+
+ public BigInteger getN()
+ {
+ return n;
+ }
+
+ public BigInteger getH()
+ {
+ return h;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
new file mode 100644
index 0000000..b5e9aa5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java
@@ -0,0 +1,1196 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+import java.util.Random;
+
+public abstract class ECFieldElement
+ implements ECConstants
+{
+
+ public abstract BigInteger toBigInteger();
+ public abstract String getFieldName();
+ public abstract int getFieldSize();
+ public abstract ECFieldElement add(ECFieldElement b);
+ public abstract ECFieldElement subtract(ECFieldElement b);
+ public abstract ECFieldElement multiply(ECFieldElement b);
+ public abstract ECFieldElement divide(ECFieldElement b);
+ public abstract ECFieldElement negate();
+ public abstract ECFieldElement square();
+ public abstract ECFieldElement invert();
+ public abstract ECFieldElement sqrt();
+
+ public String toString()
+ {
+ return this.toBigInteger().toString(2);
+ }
+
+ public static class Fp extends ECFieldElement
+ {
+ BigInteger x;
+
+ BigInteger q;
+
+ public Fp(BigInteger q, BigInteger x)
+ {
+ this.x = x;
+
+ if (x.compareTo(q) >= 0)
+ {
+ throw new IllegalArgumentException("x value too large in field element");
+ }
+
+ this.q = q;
+ }
+
+ public BigInteger toBigInteger()
+ {
+ return x;
+ }
+
+ /**
+ * return the field name for this field.
+ *
+ * @return the string "Fp".
+ */
+ public String getFieldName()
+ {
+ return "Fp";
+ }
+
+ public int getFieldSize()
+ {
+ return q.bitLength();
+ }
+
+ public BigInteger getQ()
+ {
+ return q;
+ }
+
+ public ECFieldElement add(ECFieldElement b)
+ {
+ return new Fp(q, x.add(b.toBigInteger()).mod(q));
+ }
+
+ public ECFieldElement subtract(ECFieldElement b)
+ {
+ return new Fp(q, x.subtract(b.toBigInteger()).mod(q));
+ }
+
+ public ECFieldElement multiply(ECFieldElement b)
+ {
+ return new Fp(q, x.multiply(b.toBigInteger()).mod(q));
+ }
+
+ public ECFieldElement divide(ECFieldElement b)
+ {
+ return new Fp(q, x.multiply(b.toBigInteger().modInverse(q)).mod(q));
+ }
+
+ public ECFieldElement negate()
+ {
+ return new Fp(q, x.negate().mod(q));
+ }
+
+ public ECFieldElement square()
+ {
+ return new Fp(q, x.multiply(x).mod(q));
+ }
+
+ public ECFieldElement invert()
+ {
+ return new Fp(q, x.modInverse(q));
+ }
+
+ // 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()
+ {
+ if (!q.testBit(0))
+ {
+ throw new RuntimeException("not done yet");
+ }
+
+ // 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))
+ {
+ // z = g^(u+1) + p, p = 4u + 3
+ ECFieldElement z = new Fp(q, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q));
+
+ return z.square().equals(this) ? z : null;
+ }
+
+ // p mod 4 == 1
+ BigInteger qMinusOne = q.subtract(ECConstants.ONE);
+
+ BigInteger legendreExponent = qMinusOne.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 Q = this.x;
+ BigInteger fourQ = Q.shiftLeft(2).mod(q);
+
+ BigInteger U, V;
+ Random rand = new Random();
+ do
+ {
+ BigInteger P;
+ do
+ {
+ P = new BigInteger(q.bitLength(), rand);
+ }
+ while (P.compareTo(q) >= 0
+ || !(P.multiply(P).subtract(fourQ).modPow(legendreExponent, q).equals(qMinusOne)));
+
+ BigInteger[] result = lucasSequence(q, P, Q, k);
+ U = result[0];
+ V = result[1];
+
+ if (V.multiply(V).mod(q).equals(fourQ))
+ {
+ // 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, 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 static BigInteger[] lucasSequence(
+ BigInteger p,
+ BigInteger P,
+ BigInteger Q,
+ BigInteger k)
+ {
+ int n = k.bitLength();
+ int s = k.getLowestSetBit();
+
+ BigInteger Uh = ECConstants.ONE;
+ BigInteger Vl = ECConstants.TWO;
+ BigInteger Vh = P;
+ BigInteger Ql = ECConstants.ONE;
+ BigInteger Qh = ECConstants.ONE;
+
+ for (int j = n - 1; j >= s + 1; --j)
+ {
+ Ql = Ql.multiply(Qh).mod(p);
+
+ if (k.testBit(j))
+ {
+ Qh = Ql.multiply(Q).mod(p);
+ Uh = Uh.multiply(Vh).mod(p);
+ Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
+ Vh = Vh.multiply(Vh).subtract(Qh.shiftLeft(1)).mod(p);
+ }
+ else
+ {
+ Qh = Ql;
+ Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
+ Vh = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
+ Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
+ }
+ }
+
+ Ql = Ql.multiply(Qh).mod(p);
+ Qh = Ql.multiply(Q).mod(p);
+ Uh = Uh.multiply(Vl).subtract(Ql).mod(p);
+ Vl = Vh.multiply(Vl).subtract(P.multiply(Ql)).mod(p);
+ Ql = Ql.multiply(Qh).mod(p);
+
+ for (int j = 1; j <= s; ++j)
+ {
+ Uh = Uh.multiply(Vl).mod(p);
+ Vl = Vl.multiply(Vl).subtract(Ql.shiftLeft(1)).mod(p);
+ Ql = Ql.multiply(Ql).mod(p);
+ }
+
+ return new BigInteger[]{ Uh, Vl };
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof ECFieldElement.Fp))
+ {
+ return false;
+ }
+
+ ECFieldElement.Fp o = (ECFieldElement.Fp)other;
+ return q.equals(o.q) && x.equals(o.x);
+ }
+
+ public int hashCode()
+ {
+ return q.hashCode() ^ x.hashCode();
+ }
+ }
+
+// /**
+// * Class representing the Elements of the finite field
+// * <code>F<sub>2<sup>m</sup></sub></code> 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 <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+// */
+// private int m;
+//
+// /**
+// * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+// * x<sup>k</sup> + 1</code> represents the reduction polynomial
+// * <code>f(z)</code>.<br>
+// * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+// * represents the reduction polynomial <code>f(z)</code>.<br>
+// */
+// private int k1;
+//
+// /**
+// * TPB: Always set to <code>0</code><br>
+// * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+// * represents the reduction polynomial <code>f(z)</code>.<br>
+// */
+// private int k2;
+//
+// /**
+// * TPB: Always set to <code>0</code><br>
+// * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+// * represents the reduction polynomial <code>f(z)</code>.<br>
+// */
+// private int k3;
+//
+// /**
+// * Constructor for PPB.
+// * @param m The exponent <code>m</code> of
+// * <code>F<sub>2<sup>m</sup></sub></code>.
+// * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+// * represents the reduction polynomial <code>f(z)</code>.
+// * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+// * represents the reduction polynomial <code>f(z)</code>.
+// * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+// * represents the reduction polynomial <code>f(z)</code>.
+// * @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 <code>m</code> of
+// * <code>F<sub>2<sup>m</sup></sub></code>.
+// * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+// * x<sup>k</sup> + 1</code> represents the reduction
+// * polynomial <code>f(z)</code>.
+// * @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 <code>a</code> and <code>b</code>
+// * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>
+// * (having the same representation).
+// * @param a field element.
+// * @param b field element to be compared.
+// * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
+// * are not elements of the same field
+// * <code>F<sub>2<sup>m</sup></sub></code> (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 <code>z * a(z) mod f(z)</code>, where <code>f(z)</code> is
+// * the reduction polynomial of <code>this</code>.
+// * @param a The polynomial <code>a(z)</code> to be multiplied by
+// * <code>z mod f(z)</code>.
+// * @return <code>z * a(z) mod f(z)</code>
+// */
+// 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(2));
+//// }
+// }
+// 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
+// * <code>F<sub>2<sup>m</sup></sub></code>, either of
+// * TPB (trinomial
+// * basis representation) or
+// * PPB (pentanomial
+// * basis representation).
+// */
+// public int getRepresentation()
+// {
+// return this.representation;
+// }
+//
+// /**
+// * @return the degree <code>m</code> of the reduction polynomial
+// * <code>f(z)</code>.
+// */
+// public int getM()
+// {
+// return this.m;
+// }
+//
+// /**
+// * @return TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+// * x<sup>k</sup> + 1</code> represents the reduction polynomial
+// * <code>f(z)</code>.<br>
+// * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+// * represents the reduction polynomial <code>f(z)</code>.<br>
+// */
+// public int getK1()
+// {
+// return this.k1;
+// }
+//
+// /**
+// * @return TPB: Always returns <code>0</code><br>
+// * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+// * represents the reduction polynomial <code>f(z)</code>.<br>
+// */
+// public int getK2()
+// {
+// return this.k2;
+// }
+//
+// /**
+// * @return TPB: Always set to <code>0</code><br>
+// * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+// * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+// * represents the reduction polynomial <code>f(z)</code>.<br>
+// */
+// 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
+ * <code>F<sub>2<sup>m</sup></sub></code> 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
+ {
+ /**
+ * 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 <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+ */
+ private int m;
+
+ /**
+ * TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+ * x<sup>k</sup> + 1</code> represents the reduction polynomial
+ * <code>f(z)</code>.<br>
+ * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ private int k1;
+
+ /**
+ * TPB: Always set to <code>0</code><br>
+ * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ private int k2;
+
+ /**
+ * TPB: Always set to <code>0</code><br>
+ * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ private int k3;
+
+ /**
+ * The <code>IntArray</code> holding the bits.
+ */
+ private IntArray x;
+
+ /**
+ * The number of <code>int</code>s required to hold <code>m</code> bits.
+ */
+ private int t;
+
+ /**
+ * Constructor for PPB.
+ * @param m The exponent <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k1 The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k2 The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param k3 The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.
+ * @param x The BigInteger representing the value of the field element.
+ */
+ public F2m(
+ int m,
+ int k1,
+ int k2,
+ int k3,
+ BigInteger x)
+ {
+ // t = m / 32 rounded up to the next integer
+ t = (m + 31) >> 5;
+ this.x = new IntArray(x, t);
+
+ 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 <code>m</code> of
+ * <code>F<sub>2<sup>m</sup></sub></code>.
+ * @param k The integer <code>k</code> where <code>x<sup>m</sup> +
+ * x<sup>k</sup> + 1</code> represents the reduction
+ * polynomial <code>f(z)</code>.
+ * @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);
+ }
+
+ private F2m(int m, int k1, int k2, int k3, IntArray x)
+ {
+ t = (m + 31) >> 5;
+ this.x = x;
+ this.m = m;
+ this.k1 = k1;
+ this.k2 = k2;
+ this.k3 = k3;
+
+ if ((k2 == 0) && (k3 == 0))
+ {
+ this.representation = TPB;
+ }
+ else
+ {
+ this.representation = PPB;
+ }
+
+ }
+
+ public BigInteger toBigInteger()
+ {
+ return x.toBigInteger();
+ }
+
+ public String getFieldName()
+ {
+ return "F2m";
+ }
+
+ public int getFieldSize()
+ {
+ return m;
+ }
+
+ /**
+ * Checks, if the ECFieldElements <code>a</code> and <code>b</code>
+ * are elements of the same field <code>F<sub>2<sup>m</sup></sub></code>
+ * (having the same representation).
+ * @param a field element.
+ * @param b field element to be compared.
+ * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
+ * are not elements of the same field
+ * <code>F<sub>2<sup>m</sup></sub></code> (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");
+ }
+
+ 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");
+ }
+ }
+
+ 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);
+ IntArray iarrClone = (IntArray)this.x.clone();
+ F2m bF2m = (F2m)b;
+ iarrClone.addShifted(bF2m.x, 0);
+ return new F2m(m, k1, k2, k3, iarrClone);
+ }
+
+ public ECFieldElement subtract(final ECFieldElement b)
+ {
+ // Addition and subtraction are the same in F2m
+ return add(b);
+ }
+
+ public ECFieldElement multiply(final ECFieldElement b)
+ {
+ // Right-to-left comb multiplication in the IntArray
+ // 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);
+ F2m bF2m = (F2m)b;
+ IntArray mult = x.multiply(bF2m.x, m);
+ mult.reduce(m, new int[]{k1, k2, k3});
+ return new F2m(m, k1, k2, k3, mult);
+ }
+
+ 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()
+ {
+ IntArray squared = x.square(m);
+ squared.reduce(m, new int[]{k1, k2, k3});
+ return new F2m(m, k1, k2, k3, squared);
+ }
+
+
+ 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)
+ IntArray uz = (IntArray)this.x.clone();
+
+ // v(z) := f(z)
+ IntArray vz = new IntArray(t);
+ vz.setBit(m);
+ vz.setBit(0);
+ vz.setBit(this.k1);
+ if (this.representation == PPB)
+ {
+ vz.setBit(this.k2);
+ vz.setBit(this.k3);
+ }
+
+ // g1(z) := 1, g2(z) := 0
+ IntArray g1z = new IntArray(t);
+ g1z.setBit(0);
+ IntArray g2z = new IntArray(t);
+
+ // while u != 0
+ while (!uz.isZero())
+// while (uz.getUsedLength() > 0)
+// while (uz.bitLength() > 1)
+ {
+ // 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 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));
+ // jInt = n / 32
+ int jInt = j >> 5;
+ // jInt = n % 32
+ int jBit = j & 0x1F;
+ IntArray vzShift = vz.shiftLeft(jBit);
+ uz.addShifted(vzShift, jInt);
+
+ // g1(z) := g1(z) + z^j * g2(z)
+// g1z = g1z.xor(g2z.shiftLeft(j));
+ IntArray g2zShift = g2z.shiftLeft(jBit);
+ g1z.addShifted(g2zShift, jInt);
+
+ }
+ 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
+ * <code>F<sub>2<sup>m</sup></sub></code>, either of
+ * TPB (trinomial
+ * basis representation) or
+ * PPB (pentanomial
+ * basis representation).
+ */
+ public int getRepresentation()
+ {
+ return this.representation;
+ }
+
+ /**
+ * @return the degree <code>m</code> of the reduction polynomial
+ * <code>f(z)</code>.
+ */
+ public int getM()
+ {
+ return this.m;
+ }
+
+ /**
+ * @return TPB: The integer <code>k</code> where <code>x<sup>m</sup> +
+ * x<sup>k</sup> + 1</code> represents the reduction polynomial
+ * <code>f(z)</code>.<br>
+ * PPB: The integer <code>k1</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ public int getK1()
+ {
+ return this.k1;
+ }
+
+ /**
+ * @return TPB: Always returns <code>0</code><br>
+ * PPB: The integer <code>k2</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ public int getK2()
+ {
+ return this.k2;
+ }
+
+ /**
+ * @return TPB: Always set to <code>0</code><br>
+ * PPB: The integer <code>k3</code> where <code>x<sup>m</sup> +
+ * x<sup>k3</sup> + x<sup>k2</sup> + x<sup>k1</sup> + 1</code>
+ * represents the reduction polynomial <code>f(z)</code>.<br>
+ */
+ 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;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java
new file mode 100644
index 0000000..4d72e33
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECMultiplier.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Interface for classes encapsulating a point multiplication algorithm
+ * for <code>ECPoint</code>s.
+ */
+interface ECMultiplier
+{
+ /**
+ * Multiplies the <code>ECPoint p</code> by <code>k</code>, i.e.
+ * <code>p</code> is added <code>k</code> times to itself.
+ * @param p The <code>ECPoint</code> to be multiplied.
+ * @param k The factor by which <code>p</code> i multiplied.
+ * @return <code>p</code> multiplied by <code>k</code>.
+ */
+ ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java
new file mode 100644
index 0000000..b14e4c1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ECPoint.java
@@ -0,0 +1,588 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.x9.X9IntegerConverter;
+
+/**
+ * base class for points on elliptic curves.
+ */
+public abstract class ECPoint
+{
+ ECCurve curve;
+ ECFieldElement x;
+ ECFieldElement y;
+
+ protected boolean withCompression;
+
+ protected ECMultiplier multiplier = null;
+
+ protected PreCompInfo preCompInfo = null;
+
+ private static X9IntegerConverter converter = new X9IntegerConverter();
+
+ protected ECPoint(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ {
+ this.curve = curve;
+ this.x = x;
+ this.y = y;
+ }
+
+ public ECCurve getCurve()
+ {
+ return curve;
+ }
+
+ public ECFieldElement getX()
+ {
+ return x;
+ }
+
+ public ECFieldElement getY()
+ {
+ return y;
+ }
+
+ public boolean isInfinity()
+ {
+ return x == null && y == null;
+ }
+
+ public boolean isCompressed()
+ {
+ return withCompression;
+ }
+
+ public boolean equals(
+ Object other)
+ {
+ if (other == this)
+ {
+ return true;
+ }
+
+ if (!(other instanceof ECPoint))
+ {
+ return false;
+ }
+
+ ECPoint o = (ECPoint)other;
+
+ if (this.isInfinity())
+ {
+ return o.isInfinity();
+ }
+
+ return x.equals(o.x) && y.equals(o.y);
+ }
+
+ public int hashCode()
+ {
+ if (this.isInfinity())
+ {
+ return 0;
+ }
+
+ return x.hashCode() ^ y.hashCode();
+ }
+
+// /**
+// * Mainly for testing. Explicitly set the <code>ECMultiplier</code>.
+// * @param multiplier The <code>ECMultiplier</code> to be used to multiply
+// * this <code>ECPoint</code>.
+// */
+// public void setECMultiplier(ECMultiplier multiplier)
+// {
+// this.multiplier = multiplier;
+// }
+
+ /**
+ * Sets the <code>PreCompInfo</code>. Used by <code>ECMultiplier</code>s
+ * to save the precomputation for this <code>ECPoint</code> to store the
+ * precomputation result for use by subsequent multiplication.
+ * @param preCompInfo The values precomputed by the
+ * <code>ECMultiplier</code>.
+ */
+ void setPreCompInfo(PreCompInfo preCompInfo)
+ {
+ this.preCompInfo = preCompInfo;
+ }
+
+ public abstract byte[] getEncoded();
+
+ public abstract ECPoint add(ECPoint b);
+ public abstract ECPoint subtract(ECPoint b);
+ public abstract ECPoint negate();
+ public abstract ECPoint twice();
+
+ /**
+ * Sets the default <code>ECMultiplier</code>, unless already set.
+ */
+ synchronized void assertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ this.multiplier = new FpNafMultiplier();
+ }
+ }
+
+ /**
+ * Multiplies this <code>ECPoint</code> by the given number.
+ * @param k The multiplicator.
+ * @return <code>k * this</code>.
+ */
+ public ECPoint multiply(BigInteger k)
+ {
+ if (k.signum() < 0)
+ {
+ throw new IllegalArgumentException("The multiplicator cannot be negative");
+ }
+
+ if (this.isInfinity())
+ {
+ return this;
+ }
+
+ if (k.signum() == 0)
+ {
+ return this.curve.getInfinity();
+ }
+
+ assertECMultiplier();
+ return this.multiplier.multiply(this, k, preCompInfo);
+ }
+
+ /**
+ * Elliptic curve points over Fp
+ */
+ public static class Fp extends ECPoint
+ {
+
+ /**
+ * 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
+ */
+ public Fp(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
+ */
+ public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x != null && y == null) || (x == null && y != null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ /**
+ * return the field element encoded with point compression. (S 4.3.6)
+ */
+ public byte[] getEncoded()
+ {
+ if (this.isInfinity())
+ {
+ return new byte[1];
+ }
+
+ int qLength = converter.getByteLength(x);
+
+ if (withCompression)
+ {
+ byte PC;
+
+ if (this.getY().toBigInteger().testBit(0))
+ {
+ PC = 0x03;
+ }
+ else
+ {
+ PC = 0x02;
+ }
+
+ byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
+ byte[] PO = new byte[X.length + 1];
+
+ PO[0] = PC;
+ System.arraycopy(X, 0, PO, 1, X.length);
+
+ return PO;
+ }
+ else
+ {
+ byte[] X = converter.integerToBytes(this.getX().toBigInteger(), qLength);
+ byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), qLength);
+ byte[] PO = new byte[X.length + Y.length + 1];
+
+ PO[0] = 0x04;
+ System.arraycopy(X, 0, PO, 1, X.length);
+ System.arraycopy(Y, 0, PO, X.length + 1, Y.length);
+
+ return PO;
+ }
+ }
+
+ // B.3 pg 62
+ public ECPoint add(ECPoint b)
+ {
+ if (this.isInfinity())
+ {
+ return b;
+ }
+
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Check if b = this or b = -this
+ if (this.x.equals(b.x))
+ {
+ if (this.y.equals(b.y))
+ {
+ // this = b, i.e. this must be doubled
+ return this.twice();
+ }
+
+ // this = -b, i.e. the result is the point at infinity
+ return this.curve.getInfinity();
+ }
+
+ ECFieldElement gamma = b.y.subtract(this.y).divide(b.x.subtract(this.x));
+
+ ECFieldElement x3 = gamma.square().subtract(this.x).subtract(b.x);
+ ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+
+ return new ECPoint.Fp(curve, x3, y3);
+ }
+
+ // B.3 pg 62
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ // Twice identity element (point at infinity) is identity
+ return this;
+ }
+
+ if (this.y.toBigInteger().signum() == 0)
+ {
+ // if y1 == 0, then (x1, y1) == (x1, -y1)
+ // and hence this = -this and thus 2(x1, y1) == infinity
+ return this.curve.getInfinity();
+ }
+
+ ECFieldElement TWO = this.curve.fromBigInteger(BigInteger.valueOf(2));
+ ECFieldElement THREE = this.curve.fromBigInteger(BigInteger.valueOf(3));
+ ECFieldElement gamma = this.x.square().multiply(THREE).add(curve.a).divide(y.multiply(TWO));
+
+ ECFieldElement x3 = gamma.square().subtract(this.x.multiply(TWO));
+ ECFieldElement y3 = gamma.multiply(this.x.subtract(x3)).subtract(this.y);
+
+ return new ECPoint.Fp(curve, x3, y3, this.withCompression);
+ }
+
+ // 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()
+ {
+ return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression);
+ }
+
+ /**
+ * Sets the default <code>ECMultiplier</code>, unless already set.
+ */
+ synchronized void assertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ this.multiplier = new WNafMultiplier();
+ }
+ }
+ }
+
+ /**
+ * Elliptic curve points over F2m
+ */
+ public static class F2m extends ECPoint
+ {
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ */
+ public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y)
+ {
+ this(curve, x, y, false);
+ }
+
+ /**
+ * @param curve base curve
+ * @param x x point
+ * @param y y point
+ * @param withCompression true if encode with point compression.
+ */
+ public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression)
+ {
+ super(curve, x, y);
+
+ if ((x != null && y == null) || (x == null && y != null))
+ {
+ throw new IllegalArgumentException("Exactly one of the field elements is null");
+ }
+
+ if (x != null)
+ {
+ // Check if x and y are elements of the same field
+ ECFieldElement.F2m.checkFieldElements(this.x, this.y);
+
+ // Check if x and a are elements of the same field
+ if (curve != null)
+ {
+ ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA());
+ }
+ }
+
+ this.withCompression = withCompression;
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#getEncoded()
+ */
+ public byte[] getEncoded()
+ {
+ if (this.isInfinity())
+ {
+ return new byte[1];
+ }
+
+ int byteCount = converter.getByteLength(this.x);
+ byte[] X = converter.integerToBytes(this.getX().toBigInteger(), byteCount);
+ byte[] PO;
+
+ if (withCompression)
+ {
+ // See X9.62 4.3.6 and 4.2.2
+ PO = new byte[byteCount + 1];
+
+ PO[0] = 0x02;
+ // X9.62 4.2.2 and 4.3.6:
+ // if x = 0 then ypTilde := 0, else ypTilde is the rightmost
+ // bit of y * x^(-1)
+ // if ypTilde = 0, then PC := 02, else PC := 03
+ // Note: PC === PO[0]
+ if (!(this.getX().toBigInteger().equals(ECConstants.ZERO)))
+ {
+ if (this.getY().multiply(this.getX().invert())
+ .toBigInteger().testBit(0))
+ {
+ // ypTilde = 1, hence PC = 03
+ PO[0] = 0x03;
+ }
+ }
+
+ System.arraycopy(X, 0, PO, 1, byteCount);
+ }
+ else
+ {
+ byte[] Y = converter.integerToBytes(this.getY().toBigInteger(), byteCount);
+
+ PO = new byte[byteCount + byteCount + 1];
+
+ PO[0] = 0x04;
+ System.arraycopy(X, 0, PO, 1, byteCount);
+ System.arraycopy(Y, 0, PO, byteCount + 1, byteCount);
+ }
+
+ return PO;
+ }
+
+ /**
+ * Check, if two <code>ECPoint</code>s can be added or subtracted.
+ * @param a The first <code>ECPoint</code> to check.
+ * @param b The second <code>ECPoint</code> to check.
+ * @throws IllegalArgumentException if <code>a</code> and <code>b</code>
+ * cannot be added.
+ */
+ private static void checkPoints(ECPoint a, ECPoint b)
+ {
+ // Check, if points are on the same curve
+ if (!(a.curve.equals(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 <code>ECPoints.F2m</code> to <code>this</code> 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 <code>ECPoints.F2m</code> to add to
+ * <code>this</code>.
+ * @return <code>this + b</code>
+ */
+ public ECPoint.F2m addSimple(ECPoint.F2m b)
+ {
+ ECPoint.F2m other = b;
+ if (this.isInfinity())
+ {
+ return other;
+ }
+
+ if (other.isInfinity())
+ {
+ return this;
+ }
+
+ ECFieldElement.F2m x2 = (ECFieldElement.F2m)other.getX();
+ ECFieldElement.F2m y2 = (ECFieldElement.F2m)other.getY();
+
+ // Check if other = this or other = -this
+ if (this.x.equals(x2))
+ {
+ if (this.y.equals(y2))
+ {
+ // this = other, i.e. this must be doubled
+ return (ECPoint.F2m)this.twice();
+ }
+
+ // this = -other, i.e. the result is the point at infinity
+ return (ECPoint.F2m)this.curve.getInfinity();
+ }
+
+ ECFieldElement.F2m lambda
+ = (ECFieldElement.F2m)(this.y.add(y2)).divide(this.x.add(x2));
+
+ ECFieldElement.F2m x3
+ = (ECFieldElement.F2m)lambda.square().add(lambda).add(this.x).add(x2).add(this.curve.getA());
+
+ ECFieldElement.F2m y3
+ = (ECFieldElement.F2m)lambda.multiply(this.x.add(x3)).add(x3).add(this.y);
+
+ return new ECPoint.F2m(curve, x3, y3, withCompression);
+ }
+
+ /* (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 <code>ECPoints.F2m</code> from <code>this</code>
+ * 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 <code>ECPoints.F2m</code> to subtract from
+ * <code>this</code>.
+ * @return <code>this - b</code>
+ */
+ public ECPoint.F2m subtractSimple(ECPoint.F2m b)
+ {
+ if (b.isInfinity())
+ {
+ return this;
+ }
+
+ // Add -b
+ return addSimple((ECPoint.F2m)b.negate());
+ }
+
+ /* (non-Javadoc)
+ * @see org.bouncycastle.math.ec.ECPoint#twice()
+ */
+ public ECPoint twice()
+ {
+ if (this.isInfinity())
+ {
+ // Twice identity element (point at infinity) is identity
+ return this;
+ }
+
+ if (this.x.toBigInteger().signum() == 0)
+ {
+ // if x1 == 0, then (x1, y1) == (x1, x1 + y1)
+ // and hence this = -this and thus 2(x1, y1) == infinity
+ return this.curve.getInfinity();
+ }
+
+ ECFieldElement.F2m lambda
+ = (ECFieldElement.F2m)this.x.add(this.y.divide(this.x));
+
+ ECFieldElement.F2m x3
+ = (ECFieldElement.F2m)lambda.square().add(lambda).
+ add(this.curve.getA());
+
+ ECFieldElement ONE = this.curve.fromBigInteger(ECConstants.ONE);
+ ECFieldElement.F2m y3
+ = (ECFieldElement.F2m)this.x.square().add(
+ x3.multiply(lambda.add(ONE)));
+
+ return new ECPoint.F2m(this.curve, x3, y3, withCompression);
+ }
+
+ public ECPoint negate()
+ {
+ return new ECPoint.F2m(curve, this.getX(), this.getY().add(this.getX()), withCompression);
+ }
+
+ /**
+ * Sets the appropriate <code>ECMultiplier</code>, unless already set.
+ */
+ synchronized void assertECMultiplier()
+ {
+ if (this.multiplier == null)
+ {
+ if (((ECCurve.F2m)this.curve).isKoblitz())
+ {
+ this.multiplier = new WTauNafMultiplier();
+ }
+ else
+ {
+ this.multiplier = new WNafMultiplier();
+ }
+ }
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java
new file mode 100644
index 0000000..35e601d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/FpNafMultiplier.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.
+ */
+class FpNafMultiplier implements ECMultiplier
+{
+ /**
+ * D.3.2 pg 101
+ * @see org.bouncycastle.math.ec.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger)
+ */
+ public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+ {
+ // TODO Probably should try to add this
+ // BigInteger e = k.mod(n); // n == order of p
+ BigInteger e = k;
+ BigInteger h = e.multiply(BigInteger.valueOf(3));
+
+ ECPoint neg = p.negate();
+ ECPoint R = p;
+
+ for (int i = h.bitLength() - 2; i > 0; --i)
+ {
+ R = R.twice();
+
+ boolean hBit = h.testBit(i);
+ boolean eBit = e.testBit(i);
+
+ if (hBit != eBit)
+ {
+ R = R.add(hBit ? p : neg);
+ }
+ }
+
+ return R;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java b/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java
new file mode 100644
index 0000000..ead38c4
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/IntArray.java
@@ -0,0 +1,518 @@
+package org.bouncycastle.math.ec;
+
+import org.bouncycastle.util.Arrays;
+
+import java.math.BigInteger;
+
+class IntArray
+{
+ // 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)
+ {
+ this(bigInt, 0);
+ }
+
+ public IntArray(BigInteger bigInt, int minIntLen)
+ {
+ if (bigInt.signum() == -1)
+ {
+ throw new IllegalArgumentException("Only positive Integers allowed");
+ }
+ if (bigInt.equals(ECConstants.ZERO))
+ {
+ 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;
+ if (intLen < minIntLen)
+ {
+ m_ints = new int[minIntLen];
+ }
+ else
+ {
+ 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];
+ if (barrBarrI < 0)
+ {
+ barrBarrI += 256;
+ }
+ 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++];
+ if (barrBarrI < 0)
+ {
+ barrBarrI += 256;
+ }
+ temp |= barrBarrI;
+ }
+ m_ints[iarrJ] = temp;
+ }
+ }
+
+ public boolean isZero()
+ {
+ return m_ints.length == 0
+ || (m_ints[0] == 0 && getUsedLength() == 0);
+ }
+
+ public int getUsedLength()
+ {
+ int highestIntPos = m_ints.length;
+
+ if (highestIntPos < 1)
+ {
+ return 0;
+ }
+
+ // Check if first element will act as sentinel
+ if (m_ints[0] != 0)
+ {
+ while (m_ints[--highestIntPos] == 0)
+ {
+ }
+ return highestIntPos + 1;
+ }
+
+ do
+ {
+ if (m_ints[--highestIntPos] != 0)
+ {
+ return highestIntPos + 1;
+ }
+ }
+ while (highestIntPos > 0);
+
+ return 0;
+ }
+
+ public int bitLength()
+ {
+ // JDK 1.5: see Integer.numberOfLeadingZeros()
+ int intLen = getUsedLength();
+ if (intLen == 0)
+ {
+ return 0;
+ }
+
+ int last = intLen - 1;
+ int highest = m_ints[last];
+ int bits = (last << 5) + 1;
+
+ // A couple of binary search steps
+ if ((highest & 0xffff0000) != 0)
+ {
+ if ((highest & 0xff000000) != 0)
+ {
+ bits += 24;
+ highest >>>= 24;
+ }
+ else
+ {
+ bits += 16;
+ highest >>>= 16;
+ }
+ }
+ else if (highest > 0x000000ff)
+ {
+ bits += 8;
+ highest >>>= 8;
+ }
+
+ while (highest != 1)
+ {
+ ++bits;
+ highest >>>= 1;
+ }
+
+ return bits;
+ }
+
+ private int[] resizedInts(int newLen)
+ {
+ int[] newInts = new int[newLen];
+ int oldLen = m_ints.length;
+ int copyLen = oldLen < newLen ? oldLen : newLen;
+ System.arraycopy(m_ints, 0, newInts, 0, copyLen);
+ 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);
+ }
+
+ public void shiftLeft()
+ {
+ int usedLen = getUsedLength();
+ if (usedLen == 0)
+ {
+ return;
+ }
+ if (m_ints[usedLen - 1] < 0)
+ {
+ // highest bit of highest used byte is set, so shifting left will
+ // make the IntArray one byte longer
+ usedLen++;
+ if (usedLen > m_ints.length)
+ {
+ // make the m_ints one byte longer, because we need one more
+ // byte which is not available in m_ints
+ m_ints = resizedInts(m_ints.length + 1);
+ }
+ }
+
+ boolean carry = false;
+ for (int i = 0; i < usedLen; i++)
+ {
+ // nextCarry is true if highest bit is set
+ boolean nextCarry = m_ints[i] < 0;
+ m_ints[i] <<= 1;
+ if (carry)
+ {
+ // set lowest bit
+ m_ints[i] |= 1;
+ }
+ carry = nextCarry;
+ }
+ }
+
+ public IntArray shiftLeft(int n)
+ {
+ int usedLen = getUsedLength();
+ if (usedLen == 0)
+ {
+ return this;
+ }
+
+ if (n == 0)
+ {
+ return this;
+ }
+
+ if (n > 31)
+ {
+ throw new IllegalArgumentException("shiftLeft() for max 31 bits "
+ + ", " + n + "bit shift is not possible");
+ }
+
+ int[] newInts = new int[usedLen + 1];
+
+ int nm32 = 32 - n;
+ newInts[0] = m_ints[0] << n;
+ for (int i = 1; i < usedLen; i++)
+ {
+ newInts[i] = (m_ints[i] << n) | (m_ints[i - 1] >>> nm32);
+ }
+ newInts[usedLen] = m_ints[usedLen - 1] >>> nm32;
+
+ return new IntArray(newInts);
+ }
+
+ public void addShifted(IntArray other, int shift)
+ {
+ int usedLenOther = other.getUsedLength();
+ int newMinUsedLen = usedLenOther + shift;
+ if (newMinUsedLen > m_ints.length)
+ {
+ m_ints = resizedInts(newMinUsedLen);
+ //System.out.println("Resize required");
+ }
+
+ for (int i = 0; i < usedLenOther; i++)
+ {
+ m_ints[i + shift] ^= other.m_ints[i];
+ }
+ }
+
+ public int getLength()
+ {
+ return m_ints.length;
+ }
+
+ 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 IntArray multiply(IntArray other, int m)
+ {
+ // Lenght of c is 2m bits rounded up to the next int (32 bit)
+ int t = (m + 31) >> 5;
+ if (m_ints.length < t)
+ {
+ m_ints = resizedInts(t);
+ }
+
+ IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
+ IntArray c = new IntArray((m + m + 31) >> 5);
+ // IntArray c = new IntArray(t + t);
+ int testBit = 1;
+ for (int k = 0; k < 32; k++)
+ {
+ for (int j = 0; j < t; j++)
+ {
+ if ((m_ints[j] & testBit) != 0)
+ {
+ // The kth bit of m_ints[j] is set
+ c.addShifted(b, j);
+ }
+ }
+ testBit <<= 1;
+ b.shiftLeft();
+ }
+ return c;
+ }
+
+ // public IntArray multiplyLeftToRight(IntArray other, int m) {
+ // // Lenght of c is 2m bits rounded up to the next int (32 bit)
+ // int t = (m + 31) / 32;
+ // if (m_ints.length < t) {
+ // m_ints = resizedInts(t);
+ // }
+ //
+ // IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
+ // IntArray c = new IntArray((m + m + 31) / 32);
+ // // IntArray c = new IntArray(t + t);
+ // int testBit = 1 << 31;
+ // for (int k = 31; k >= 0; k--) {
+ // for (int j = 0; j < t; j++) {
+ // if ((m_ints[j] & testBit) != 0) {
+ // // The kth bit of m_ints[j] is set
+ // c.addShifted(b, j);
+ // }
+ // }
+ // testBit >>>= 1;
+ // if (k > 0) {
+ // c.shiftLeft();
+ // }
+ // }
+ // return c;
+ // }
+
+ // TODO note, redPol.length must be 3 for TPB and 5 for PPB
+ public void reduce(int m, int[] redPol)
+ {
+ for (int i = m + m - 2; i >= m; i--)
+ {
+ if (testBit(i))
+ {
+ int bit = i - m;
+ flipBit(bit);
+ flipBit(i);
+ int l = redPol.length;
+ while (--l >= 0)
+ {
+ flipBit(redPol[l] + bit);
+ }
+ }
+ }
+ m_ints = resizedInts((m + 31) >> 5);
+ }
+
+ public IntArray square(int m)
+ {
+ // TODO make the table static final
+ final int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40,
+ 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };
+
+ int t = (m + 31) >> 5;
+ if (m_ints.length < t)
+ {
+ m_ints = resizedInts(t);
+ }
+
+ IntArray c = new IntArray(t + t);
+
+ // TODO twice the same code, put in separate private method
+ for (int i = 0; i < t; i++)
+ {
+ int v0 = 0;
+ for (int j = 0; j < 4; j++)
+ {
+ v0 = v0 >>> 8;
+ int u = (m_ints[i] >>> (j * 4)) & 0xF;
+ int w = table[u] << 24;
+ v0 |= w;
+ }
+ c.m_ints[i + i] = v0;
+
+ v0 = 0;
+ int upper = m_ints[i] >>> 16;
+ for (int j = 0; j < 4; j++)
+ {
+ v0 = v0 >>> 8;
+ int u = (upper >>> (j * 4)) & 0xF;
+ int w = table[u] << 24;
+ v0 |= w;
+ }
+ c.m_ints[i + i + 1] = v0;
+ }
+ return c;
+ }
+
+ 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 = hash * 31 + m_ints[i];
+ }
+ return hash;
+ }
+
+ public Object clone()
+ {
+ return new IntArray(Arrays.clone(m_ints));
+ }
+
+ public String toString()
+ {
+ int usedLen = getUsedLength();
+ if (usedLen == 0)
+ {
+ return "0";
+ }
+
+ StringBuffer sb = new StringBuffer(Integer
+ .toBinaryString(m_ints[usedLen - 1]));
+ for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+ {
+ String hexString = Integer.toBinaryString(m_ints[iarrJ]);
+
+ // Add leading zeroes, except for highest significant int
+ for (int i = hexString.length(); i < 8; i++)
+ {
+ hexString = "0" + hexString;
+ }
+ sb.append(hexString);
+ }
+ return sb.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java b/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java
new file mode 100644
index 0000000..804dcf7
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/PreCompInfo.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.math.ec;
+
+/**
+ * Interface for classes storing precomputation data for multiplication
+ * algorithms. Used as a Memento (see GOF patterns) for
+ * <code>WNafMultiplier</code>.
+ */
+interface PreCompInfo
+{
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java b/bcprov/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java
new file mode 100644
index 0000000..96e666d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java
@@ -0,0 +1,253 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class representing a simple version of a big decimal. A
+ * <code>SimpleBigDecimal</code> is basically a
+ * {@link java.math.BigInteger BigInteger} with a few digits on the right of
+ * the decimal point. The number of (binary) digits on the right of the decimal
+ * point is called the <code>scale</code> of the <code>SimpleBigDecimal</code>.
+ * Unlike in {@link java.math.BigDecimal BigDecimal}, the scale is not adjusted
+ * automatically, but must be set manually. All <code>SimpleBigDecimal</code>s
+ * taking part in the same arithmetic operation must have equal scale. The
+ * result of a multiplication of two <code>SimpleBigDecimal</code>s returns a
+ * <code>SimpleBigDecimal</code> with double scale.
+ */
+class SimpleBigDecimal
+ //extends Number // not in J2ME - add compatibility class?
+{
+ private static final long serialVersionUID = 1L;
+
+ private final BigInteger bigInt;
+ private final int scale;
+
+ /**
+ * Returns a <code>SimpleBigDecimal</code> representing the same numerical
+ * value as <code>value</code>.
+ * @param value The value of the <code>SimpleBigDecimal</code> to be
+ * created.
+ * @param scale The scale of the <code>SimpleBigDecimal</code> to be
+ * created.
+ * @return The such created <code>SimpleBigDecimal</code>.
+ */
+ public static SimpleBigDecimal getInstance(BigInteger value, int scale)
+ {
+ return new SimpleBigDecimal(value.shiftLeft(scale), scale);
+ }
+
+ /**
+ * Constructor for <code>SimpleBigDecimal</code>. The value of the
+ * constructed <code>SimpleBigDecimal</code> equals <code>bigInt /
+ * 2<sup>scale</sup></code>.
+ * @param bigInt The <code>bigInt</code> value parameter.
+ * @param scale The scale of the constructed <code>SimpleBigDecimal</code>.
+ */
+ public SimpleBigDecimal(BigInteger bigInt, int scale)
+ {
+ if (scale < 0)
+ {
+ throw new IllegalArgumentException("scale may not be negative");
+ }
+
+ this.bigInt = bigInt;
+ this.scale = scale;
+ }
+
+ private SimpleBigDecimal(SimpleBigDecimal limBigDec)
+ {
+ bigInt = limBigDec.bigInt;
+ scale = limBigDec.scale;
+ }
+
+ private void checkScale(SimpleBigDecimal b)
+ {
+ if (scale != b.scale)
+ {
+ throw new IllegalArgumentException("Only SimpleBigDecimal of " +
+ "same scale allowed in arithmetic operations");
+ }
+ }
+
+ public SimpleBigDecimal adjustScale(int newScale)
+ {
+ if (newScale < 0)
+ {
+ throw new IllegalArgumentException("scale may not be negative");
+ }
+
+ if (newScale == scale)
+ {
+ return new SimpleBigDecimal(this);
+ }
+
+ return new SimpleBigDecimal(bigInt.shiftLeft(newScale - scale),
+ newScale);
+ }
+
+ public SimpleBigDecimal add(SimpleBigDecimal b)
+ {
+ checkScale(b);
+ return new SimpleBigDecimal(bigInt.add(b.bigInt), scale);
+ }
+
+ public SimpleBigDecimal add(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.add(b.shiftLeft(scale)), scale);
+ }
+
+ public SimpleBigDecimal negate()
+ {
+ return new SimpleBigDecimal(bigInt.negate(), scale);
+ }
+
+ public SimpleBigDecimal subtract(SimpleBigDecimal b)
+ {
+ return add(b.negate());
+ }
+
+ public SimpleBigDecimal subtract(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.subtract(b.shiftLeft(scale)),
+ scale);
+ }
+
+ public SimpleBigDecimal multiply(SimpleBigDecimal b)
+ {
+ checkScale(b);
+ return new SimpleBigDecimal(bigInt.multiply(b.bigInt), scale + scale);
+ }
+
+ public SimpleBigDecimal multiply(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.multiply(b), scale);
+ }
+
+ public SimpleBigDecimal divide(SimpleBigDecimal b)
+ {
+ checkScale(b);
+ BigInteger dividend = bigInt.shiftLeft(scale);
+ return new SimpleBigDecimal(dividend.divide(b.bigInt), scale);
+ }
+
+ public SimpleBigDecimal divide(BigInteger b)
+ {
+ return new SimpleBigDecimal(bigInt.divide(b), scale);
+ }
+
+ public SimpleBigDecimal shiftLeft(int n)
+ {
+ return new SimpleBigDecimal(bigInt.shiftLeft(n), scale);
+ }
+
+ public int compareTo(SimpleBigDecimal val)
+ {
+ checkScale(val);
+ return bigInt.compareTo(val.bigInt);
+ }
+
+ public int compareTo(BigInteger val)
+ {
+ return bigInt.compareTo(val.shiftLeft(scale));
+ }
+
+ public BigInteger floor()
+ {
+ return bigInt.shiftRight(scale);
+ }
+
+ public BigInteger round()
+ {
+ SimpleBigDecimal oneHalf = new SimpleBigDecimal(ECConstants.ONE, 1);
+ return add(oneHalf.adjustScale(scale)).floor();
+ }
+
+ public int intValue()
+ {
+ return floor().intValue();
+ }
+
+ public long longValue()
+ {
+ return floor().longValue();
+ }
+ /* NON-J2ME compliant.
+ public double doubleValue()
+ {
+ return Double.valueOf(toString()).doubleValue();
+ }
+
+ public float floatValue()
+ {
+ return Float.valueOf(toString()).floatValue();
+ }
+ */
+ public int getScale()
+ {
+ return scale;
+ }
+
+ public String toString()
+ {
+ if (scale == 0)
+ {
+ return bigInt.toString();
+ }
+
+ BigInteger floorBigInt = floor();
+
+ BigInteger fract = bigInt.subtract(floorBigInt.shiftLeft(scale));
+ if (bigInt.signum() == -1)
+ {
+ fract = ECConstants.ONE.shiftLeft(scale).subtract(fract);
+ }
+
+ if ((floorBigInt.signum() == -1) && (!(fract.equals(ECConstants.ZERO))))
+ {
+ floorBigInt = floorBigInt.add(ECConstants.ONE);
+ }
+ String leftOfPoint = floorBigInt.toString();
+
+ char[] fractCharArr = new char[scale];
+ String fractStr = fract.toString(2);
+ int fractLen = fractStr.length();
+ int zeroes = scale - fractLen;
+ for (int i = 0; i < zeroes; i++)
+ {
+ fractCharArr[i] = '0';
+ }
+ for (int j = 0; j < fractLen; j++)
+ {
+ fractCharArr[zeroes + j] = fractStr.charAt(j);
+ }
+ String rightOfPoint = new String(fractCharArr);
+
+ StringBuffer sb = new StringBuffer(leftOfPoint);
+ sb.append(".");
+ sb.append(rightOfPoint);
+
+ return sb.toString();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+
+ if (!(o instanceof SimpleBigDecimal))
+ {
+ return false;
+ }
+
+ SimpleBigDecimal other = (SimpleBigDecimal)o;
+ return ((bigInt.equals(other.bigInt)) && (scale == other.scale));
+ }
+
+ public int hashCode()
+ {
+ return bigInt.hashCode() ^ scale;
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java b/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java
new file mode 100644
index 0000000..af4355f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/Tnaf.java
@@ -0,0 +1,844 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class holding methods for point multiplication based on the window
+ * &tau;-adic nonadjacent form (WTNAF). The algorithms are based on the
+ * paper "Improved Algorithms for Arithmetic on Anomalous Binary Curves"
+ * by Jerome A. Solinas. The paper first appeared in the Proceedings of
+ * Crypto 1997.
+ */
+class Tnaf
+{
+ private static final BigInteger MINUS_ONE = ECConstants.ONE.negate();
+ private static final BigInteger MINUS_TWO = ECConstants.TWO.negate();
+ private static final BigInteger MINUS_THREE = ECConstants.THREE.negate();
+
+ /**
+ * The window width of WTNAF. The standard value of 4 is slightly less
+ * than optimal for running time, but keeps space requirements for
+ * precomputation low. For typical curves, a value of 5 or 6 results in
+ * a better running time. When changing this value, the
+ * <code>&alpha;<sub>u</sub></code>'s must be computed differently, see
+ * e.g. "Guide to Elliptic Curve Cryptography", Darrel Hankerson,
+ * Alfred Menezes, Scott Vanstone, Springer-Verlag New York Inc., 2004,
+ * p. 121-122
+ */
+ public static final byte WIDTH = 4;
+
+ /**
+ * 2<sup>4</sup>
+ */
+ public static final byte POW_2_WIDTH = 16;
+
+ /**
+ * The <code>&alpha;<sub>u</sub></code>'s for <code>a=0</code> as an array
+ * of <code>ZTauElement</code>s.
+ */
+ public static final ZTauElement[] alpha0 = {
+ null,
+ new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
+ new ZTauElement(MINUS_THREE, MINUS_ONE), null,
+ new ZTauElement(MINUS_ONE, MINUS_ONE), null,
+ new ZTauElement(ECConstants.ONE, MINUS_ONE), null
+ };
+
+ /**
+ * The <code>&alpha;<sub>u</sub></code>'s for <code>a=0</code> as an array
+ * of TNAFs.
+ */
+ public static final byte[][] alpha0Tnaf = {
+ null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, 1}
+ };
+
+ /**
+ * The <code>&alpha;<sub>u</sub></code>'s for <code>a=1</code> as an array
+ * of <code>ZTauElement</code>s.
+ */
+ public static final ZTauElement[] alpha1 = {null,
+ new ZTauElement(ECConstants.ONE, ECConstants.ZERO), null,
+ new ZTauElement(MINUS_THREE, ECConstants.ONE), null,
+ new ZTauElement(MINUS_ONE, ECConstants.ONE), null,
+ new ZTauElement(ECConstants.ONE, ECConstants.ONE), null
+ };
+
+ /**
+ * The <code>&alpha;<sub>u</sub></code>'s for <code>a=1</code> as an array
+ * of TNAFs.
+ */
+ public static final byte[][] alpha1Tnaf = {
+ null, {1}, null, {-1, 0, 1}, null, {1, 0, 1}, null, {-1, 0, 0, -1}
+ };
+
+ /**
+ * Computes the norm of an element <code>&lambda;</code> of
+ * <code><b>Z</b>[&tau;]</code>.
+ * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+ * @param lambda The element <code>&lambda;</code> of
+ * <code><b>Z</b>[&tau;]</code>.
+ * @return The norm of <code>&lambda;</code>.
+ */
+ public static BigInteger norm(final byte mu, ZTauElement lambda)
+ {
+ BigInteger norm;
+
+ // s1 = u^2
+ BigInteger s1 = lambda.u.multiply(lambda.u);
+
+ // s2 = u * v
+ BigInteger s2 = lambda.u.multiply(lambda.v);
+
+ // s3 = 2 * v^2
+ BigInteger s3 = lambda.v.multiply(lambda.v).shiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.add(s2).add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.subtract(s2).add(s3);
+ }
+ else
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Computes the norm of an element <code>&lambda;</code> of
+ * <code><b>R</b>[&tau;]</code>, where <code>&lambda; = u + v&tau;</code>
+ * and <code>u</code> and <code>u</code> are real numbers (elements of
+ * <code><b>R</b></code>).
+ * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+ * @param u The real part of the element <code>&lambda;</code> of
+ * <code><b>R</b>[&tau;]</code>.
+ * @param v The <code>&tau;</code>-adic part of the element
+ * <code>&lambda;</code> of <code><b>R</b>[&tau;]</code>.
+ * @return The norm of <code>&lambda;</code>.
+ */
+ public static SimpleBigDecimal norm(final byte mu, SimpleBigDecimal u,
+ SimpleBigDecimal v)
+ {
+ SimpleBigDecimal norm;
+
+ // s1 = u^2
+ SimpleBigDecimal s1 = u.multiply(u);
+
+ // s2 = u * v
+ SimpleBigDecimal s2 = u.multiply(v);
+
+ // s3 = 2 * v^2
+ SimpleBigDecimal s3 = v.multiply(v).shiftLeft(1);
+
+ if (mu == 1)
+ {
+ norm = s1.add(s2).add(s3);
+ }
+ else if (mu == -1)
+ {
+ norm = s1.subtract(s2).add(s3);
+ }
+ else
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ return norm;
+ }
+
+ /**
+ * Rounds an element <code>&lambda;</code> of <code><b>R</b>[&tau;]</code>
+ * to an element of <code><b>Z</b>[&tau;]</code>, such that their difference
+ * has minimal norm. <code>&lambda;</code> is given as
+ * <code>&lambda; = &lambda;<sub>0</sub> + &lambda;<sub>1</sub>&tau;</code>.
+ * @param lambda0 The component <code>&lambda;<sub>0</sub></code>.
+ * @param lambda1 The component <code>&lambda;<sub>1</sub></code>.
+ * @param mu The parameter <code>&mu;</code> of the elliptic curve. Must
+ * equal 1 or -1.
+ * @return The rounded element of <code><b>Z</b>[&tau;]</code>.
+ * @throws IllegalArgumentException if <code>lambda0</code> and
+ * <code>lambda1</code> do not have same scale.
+ */
+ public static ZTauElement round(SimpleBigDecimal lambda0,
+ SimpleBigDecimal lambda1, byte mu)
+ {
+ int scale = lambda0.getScale();
+ if (lambda1.getScale() != scale)
+ {
+ throw new IllegalArgumentException("lambda0 and lambda1 do not " +
+ "have same scale");
+ }
+
+ if (!((mu == 1) || (mu == -1)))
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger f0 = lambda0.round();
+ BigInteger f1 = lambda1.round();
+
+ SimpleBigDecimal eta0 = lambda0.subtract(f0);
+ SimpleBigDecimal eta1 = lambda1.subtract(f1);
+
+ // eta = 2*eta0 + mu*eta1
+ SimpleBigDecimal eta = eta0.add(eta0);
+ if (mu == 1)
+ {
+ eta = eta.add(eta1);
+ }
+ else
+ {
+ // mu == -1
+ eta = eta.subtract(eta1);
+ }
+
+ // check1 = eta0 - 3*mu*eta1
+ // check2 = eta0 + 4*mu*eta1
+ SimpleBigDecimal threeEta1 = eta1.add(eta1).add(eta1);
+ SimpleBigDecimal fourEta1 = threeEta1.add(eta1);
+ SimpleBigDecimal check1;
+ SimpleBigDecimal check2;
+ if (mu == 1)
+ {
+ check1 = eta0.subtract(threeEta1);
+ check2 = eta0.add(fourEta1);
+ }
+ else
+ {
+ // mu == -1
+ check1 = eta0.add(threeEta1);
+ check2 = eta0.subtract(fourEta1);
+ }
+
+ byte h0 = 0;
+ byte h1 = 0;
+
+ // if eta >= 1
+ if (eta.compareTo(ECConstants.ONE) >= 0)
+ {
+ if (check1.compareTo(MINUS_ONE) < 0)
+ {
+ h1 = mu;
+ }
+ else
+ {
+ h0 = 1;
+ }
+ }
+ else
+ {
+ // eta < 1
+ if (check2.compareTo(ECConstants.TWO) >= 0)
+ {
+ h1 = mu;
+ }
+ }
+
+ // if eta < -1
+ if (eta.compareTo(MINUS_ONE) < 0)
+ {
+ if (check1.compareTo(ECConstants.ONE) >= 0)
+ {
+ h1 = (byte)-mu;
+ }
+ else
+ {
+ h0 = -1;
+ }
+ }
+ else
+ {
+ // eta >= -1
+ if (check2.compareTo(MINUS_TWO) < 0)
+ {
+ h1 = (byte)-mu;
+ }
+ }
+
+ BigInteger q0 = f0.add(BigInteger.valueOf(h0));
+ BigInteger q1 = f1.add(BigInteger.valueOf(h1));
+ return new ZTauElement(q0, q1);
+ }
+
+ /**
+ * Approximate division by <code>n</code>. For an integer
+ * <code>k</code>, the value <code>&lambda; = s k / n</code> is
+ * computed to <code>c</code> bits of accuracy.
+ * @param k The parameter <code>k</code>.
+ * @param s The curve parameter <code>s<sub>0</sub></code> or
+ * <code>s<sub>1</sub></code>.
+ * @param vm The Lucas Sequence element <code>V<sub>m</sub></code>.
+ * @param a The parameter <code>a</code> of the elliptic curve.
+ * @param m The bit length of the finite field
+ * <code><b>F</b><sub>m</sub></code>.
+ * @param c The number of bits of accuracy, i.e. the scale of the returned
+ * <code>SimpleBigDecimal</code>.
+ * @return The value <code>&lambda; = s k / n</code> computed to
+ * <code>c</code> bits of accuracy.
+ */
+ public static SimpleBigDecimal approximateDivisionByN(BigInteger k,
+ BigInteger s, BigInteger vm, byte a, int m, int c)
+ {
+ int _k = (m + 5)/2 + c;
+ BigInteger ns = k.shiftRight(m - _k - 2 + a);
+
+ BigInteger gs = s.multiply(ns);
+
+ BigInteger hs = gs.shiftRight(m);
+
+ BigInteger js = vm.multiply(hs);
+
+ BigInteger gsPlusJs = gs.add(js);
+ BigInteger ls = gsPlusJs.shiftRight(_k-c);
+ if (gsPlusJs.testBit(_k-c-1))
+ {
+ // round up
+ ls = ls.add(ECConstants.ONE);
+ }
+
+ return new SimpleBigDecimal(ls, c);
+ }
+
+ /**
+ * Computes the <code>&tau;</code>-adic NAF (non-adjacent form) of an
+ * element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>.
+ * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+ * @param lambda The element <code>&lambda;</code> of
+ * <code><b>Z</b>[&tau;]</code>.
+ * @return The <code>&tau;</code>-adic NAF of <code>&lambda;</code>.
+ */
+ public static byte[] tauAdicNaf(byte mu, ZTauElement lambda)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger norm = norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.bitLength();
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 : 34;
+
+ // The array holding the TNAF
+ byte[] u = new byte[maxLength];
+ int i = 0;
+
+ // The actual length of the TNAF
+ int length = 0;
+
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+
+ while(!((r0.equals(ECConstants.ZERO)) && (r1.equals(ECConstants.ZERO))))
+ {
+ // If r0 is odd
+ if (r0.testBit(0))
+ {
+ u[i] = (byte) ECConstants.TWO.subtract((r0.subtract(r1.shiftLeft(1))).mod(ECConstants.FOUR)).intValue();
+
+ // r0 = r0 - u[i]
+ if (u[i] == 1)
+ {
+ r0 = r0.clearBit(0);
+ }
+ else
+ {
+ // u[i] == -1
+ r0 = r0.add(ECConstants.ONE);
+ }
+ length = i;
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+ BigInteger s = r0.shiftRight(1);
+ if (mu == 1)
+ {
+ r0 = r1.add(s);
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.subtract(s);
+ }
+
+ r1 = t.shiftRight(1).negate();
+ i++;
+ }
+
+ length++;
+
+ // Reduce the TNAF array to its actual length
+ byte[] tnaf = new byte[length];
+ System.arraycopy(u, 0, tnaf, 0, length);
+ return tnaf;
+ }
+
+ /**
+ * Applies the operation <code>&tau;()</code> to an
+ * <code>ECPoint.F2m</code>.
+ * @param p The ECPoint.F2m to which <code>&tau;()</code> is applied.
+ * @return <code>&tau;(p)</code>
+ */
+ public static ECPoint.F2m tau(ECPoint.F2m p)
+ {
+ if (p.isInfinity())
+ {
+ return p;
+ }
+
+ ECFieldElement x = p.getX();
+ ECFieldElement y = p.getY();
+
+ return new ECPoint.F2m(p.getCurve(), x.square(), y.square(), p.isCompressed());
+ }
+
+ /**
+ * Returns the parameter <code>&mu;</code> of the elliptic curve.
+ * @param curve The elliptic curve from which to obtain <code>&mu;</code>.
+ * The curve must be a Koblitz curve, i.e. <code>a</code> equals
+ * <code>0</code> or <code>1</code> and <code>b</code> equals
+ * <code>1</code>.
+ * @return <code>&mu;</code> of the elliptic curve.
+ * @throws IllegalArgumentException if the given ECCurve is not a Koblitz
+ * curve.
+ */
+ public static byte getMu(ECCurve.F2m curve)
+ {
+ BigInteger a = curve.getA().toBigInteger();
+ byte mu;
+
+ if (a.equals(ECConstants.ZERO))
+ {
+ mu = -1;
+ }
+ else if (a.equals(ECConstants.ONE))
+ {
+ mu = 1;
+ }
+ else
+ {
+ throw new IllegalArgumentException("No Koblitz curve (ABC), " +
+ "TNAF multiplication not possible");
+ }
+ return mu;
+ }
+
+ /**
+ * Calculates the Lucas Sequence elements <code>U<sub>k-1</sub></code> and
+ * <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code> and
+ * <code>V<sub>k</sub></code>.
+ * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+ * @param k The index of the second element of the Lucas Sequence to be
+ * returned.
+ * @param doV If set to true, computes <code>V<sub>k-1</sub></code> and
+ * <code>V<sub>k</sub></code>, otherwise <code>U<sub>k-1</sub></code> and
+ * <code>U<sub>k</sub></code>.
+ * @return An array with 2 elements, containing <code>U<sub>k-1</sub></code>
+ * and <code>U<sub>k</sub></code> or <code>V<sub>k-1</sub></code>
+ * and <code>V<sub>k</sub></code>.
+ */
+ public static BigInteger[] getLucas(byte mu, int k, boolean doV)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger u0;
+ BigInteger u1;
+ BigInteger u2;
+
+ if (doV)
+ {
+ u0 = ECConstants.TWO;
+ u1 = BigInteger.valueOf(mu);
+ }
+ else
+ {
+ u0 = ECConstants.ZERO;
+ u1 = ECConstants.ONE;
+ }
+
+ for (int i = 1; i < k; i++)
+ {
+ // u2 = mu*u1 - 2*u0;
+ BigInteger s = null;
+ if (mu == 1)
+ {
+ s = u1;
+ }
+ else
+ {
+ // mu == -1
+ s = u1.negate();
+ }
+
+ u2 = s.subtract(u0.shiftLeft(1));
+ u0 = u1;
+ u1 = u2;
+// System.out.println(i + ": " + u2);
+// System.out.println();
+ }
+
+ BigInteger[] retVal = {u0, u1};
+ return retVal;
+ }
+
+ /**
+ * Computes the auxiliary value <code>t<sub>w</sub></code>. If the width is
+ * 4, then for <code>mu = 1</code>, <code>t<sub>w</sub> = 6</code> and for
+ * <code>mu = -1</code>, <code>t<sub>w</sub> = 10</code>
+ * @param mu The parameter <code>&mu;</code> of the elliptic curve.
+ * @param w The window width of the WTNAF.
+ * @return the auxiliary value <code>t<sub>w</sub></code>
+ */
+ public static BigInteger getTw(byte mu, int w)
+ {
+ if (w == 4)
+ {
+ if (mu == 1)
+ {
+ return BigInteger.valueOf(6);
+ }
+ else
+ {
+ // mu == -1
+ return BigInteger.valueOf(10);
+ }
+ }
+ else
+ {
+ // For w <> 4, the values must be computed
+ BigInteger[] us = getLucas(mu, w, false);
+ BigInteger twoToW = ECConstants.ZERO.setBit(w);
+ BigInteger u1invert = us[1].modInverse(twoToW);
+ BigInteger tw;
+ tw = ECConstants.TWO.multiply(us[0]).multiply(u1invert).mod(twoToW);
+// System.out.println("mu = " + mu);
+// System.out.println("tw = " + tw);
+ return tw;
+ }
+ }
+
+ /**
+ * Computes the auxiliary values <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code> used for partial modular reduction.
+ * @param curve The elliptic curve for which to compute
+ * <code>s<sub>0</sub></code> and <code>s<sub>1</sub></code>.
+ * @throws IllegalArgumentException if <code>curve</code> is not a
+ * Koblitz curve (Anomalous Binary Curve, ABC).
+ */
+ public static BigInteger[] getSi(ECCurve.F2m curve)
+ {
+ if (!curve.isKoblitz())
+ {
+ throw new IllegalArgumentException("si is defined for Koblitz curves only");
+ }
+
+ int m = curve.getM();
+ int a = curve.getA().toBigInteger().intValue();
+ byte mu = curve.getMu();
+ int h = curve.getH().intValue();
+ 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");
+ }
+
+ BigInteger[] si = new BigInteger[2];
+
+ if (h == 2)
+ {
+ si[0] = dividend0.shiftRight(1);
+ si[1] = dividend1.shiftRight(1).negate();
+ }
+ else if (h == 4)
+ {
+ si[0] = dividend0.shiftRight(2);
+ si[1] = dividend1.shiftRight(2).negate();
+ }
+ else
+ {
+ throw new IllegalArgumentException("h (Cofactor) must be 2 or 4");
+ }
+
+ return si;
+ }
+
+ /**
+ * Partial modular reduction modulo
+ * <code>(&tau;<sup>m</sup> - 1)/(&tau; - 1)</code>.
+ * @param k The integer to be reduced.
+ * @param m The bitlength of the underlying finite field.
+ * @param a The parameter <code>a</code> of the elliptic curve.
+ * @param s The auxiliary values <code>s<sub>0</sub></code> and
+ * <code>s<sub>1</sub></code>.
+ * @param mu The parameter &mu; of the elliptic curve.
+ * @param c The precision (number of bits of accuracy) of the partial
+ * modular reduction.
+ * @return <code>&rho; := k partmod (&tau;<sup>m</sup> - 1)/(&tau; - 1)</code>
+ */
+ public static ZTauElement partModReduction(BigInteger k, int m, byte a,
+ BigInteger[] s, byte mu, byte c)
+ {
+ // d0 = s[0] + mu*s[1]; mu is either 1 or -1
+ BigInteger d0;
+ if (mu == 1)
+ {
+ d0 = s[0].add(s[1]);
+ }
+ else
+ {
+ d0 = s[0].subtract(s[1]);
+ }
+
+ BigInteger[] v = getLucas(mu, m, true);
+ BigInteger vm = v[1];
+
+ SimpleBigDecimal lambda0 = approximateDivisionByN(
+ k, s[0], vm, a, m, c);
+
+ SimpleBigDecimal lambda1 = approximateDivisionByN(
+ k, s[1], vm, a, m, c);
+
+ ZTauElement q = round(lambda0, lambda1, mu);
+
+ // r0 = n - d0*q0 - 2*s1*q1
+ BigInteger r0 = k.subtract(d0.multiply(q.u)).subtract(
+ BigInteger.valueOf(2).multiply(s[1]).multiply(q.v));
+
+ // r1 = s1*q0 - s0*q1
+ BigInteger r1 = s[1].multiply(q.u).subtract(s[0].multiply(q.v));
+
+ return new ZTauElement(r0, r1);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by a <code>BigInteger</code> using the reduced <code>&tau;</code>-adic
+ * NAF (RTNAF) method.
+ * @param p The ECPoint.F2m to multiply.
+ * @param k The <code>BigInteger</code> by which to multiply <code>p</code>.
+ * @return <code>k * p</code>
+ */
+ public static ECPoint.F2m multiplyRTnaf(ECPoint.F2m 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();
+ BigInteger[] s = curve.getSi();
+ ZTauElement rho = partModReduction(k, m, a, s, mu, (byte)10);
+
+ return multiplyTnaf(p, rho);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>
+ * using the <code>&tau;</code>-adic NAF (TNAF) method.
+ * @param p The ECPoint.F2m to multiply.
+ * @param lambda The element <code>&lambda;</code> of
+ * <code><b>Z</b>[&tau;]</code>.
+ * @return <code>&lambda; * p</code>
+ */
+ public static ECPoint.F2m multiplyTnaf(ECPoint.F2m p, ZTauElement lambda)
+ {
+ ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
+ byte mu = curve.getMu();
+ byte[] u = tauAdicNaf(mu, lambda);
+
+ ECPoint.F2m q = multiplyFromTnaf(p, u);
+
+ return q;
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>
+ * using the <code>&tau;</code>-adic NAF (TNAF) method, given the TNAF
+ * of <code>&lambda;</code>.
+ * @param p The ECPoint.F2m to multiply.
+ * @param u The the TNAF of <code>&lambda;</code>..
+ * @return <code>&lambda; * p</code>
+ */
+ public static ECPoint.F2m multiplyFromTnaf(ECPoint.F2m p, byte[] u)
+ {
+ ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
+ ECPoint.F2m q = (ECPoint.F2m) curve.getInfinity();
+ for (int i = u.length - 1; i >= 0; i--)
+ {
+ q = tau(q);
+ if (u[i] == 1)
+ {
+ q = (ECPoint.F2m)q.addSimple(p);
+ }
+ else if (u[i] == -1)
+ {
+ q = (ECPoint.F2m)q.subtractSimple(p);
+ }
+ }
+ return q;
+ }
+
+ /**
+ * Computes the <code>[&tau;]</code>-adic window NAF of an element
+ * <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>.
+ * @param mu The parameter &mu; of the elliptic curve.
+ * @param lambda The element <code>&lambda;</code> of
+ * <code><b>Z</b>[&tau;]</code> of which to compute the
+ * <code>[&tau;]</code>-adic NAF.
+ * @param width The window width of the resulting WNAF.
+ * @param pow2w 2<sup>width</sup>.
+ * @param tw The auxiliary value <code>t<sub>w</sub></code>.
+ * @param alpha The <code>&alpha;<sub>u</sub></code>'s for the window width.
+ * @return The <code>[&tau;]</code>-adic window NAF of
+ * <code>&lambda;</code>.
+ */
+ public static byte[] tauAdicWNaf(byte mu, ZTauElement lambda,
+ byte width, BigInteger pow2w, BigInteger tw, ZTauElement[] alpha)
+ {
+ if (!((mu == 1) || (mu == -1)))
+ {
+ throw new IllegalArgumentException("mu must be 1 or -1");
+ }
+
+ BigInteger norm = norm(mu, lambda);
+
+ // Ceiling of log2 of the norm
+ int log2Norm = norm.bitLength();
+
+ // If length(TNAF) > 30, then length(TNAF) < log2Norm + 3.52
+ int maxLength = log2Norm > 30 ? log2Norm + 4 + width : 34 + width;
+
+ // The array holding the TNAF
+ byte[] u = new byte[maxLength];
+
+ // 2^(width - 1)
+ BigInteger pow2wMin1 = pow2w.shiftRight(1);
+
+ // Split lambda into two BigIntegers to simplify calculations
+ BigInteger r0 = lambda.u;
+ BigInteger r1 = lambda.v;
+ int i = 0;
+
+ // while lambda <> (0, 0)
+ while (!((r0.equals(ECConstants.ZERO))&&(r1.equals(ECConstants.ZERO))))
+ {
+ // if r0 is odd
+ if (r0.testBit(0))
+ {
+ // uUnMod = r0 + r1*tw mod 2^width
+ BigInteger uUnMod
+ = r0.add(r1.multiply(tw)).mod(pow2w);
+
+ byte uLocal;
+ // if uUnMod >= 2^(width - 1)
+ if (uUnMod.compareTo(pow2wMin1) >= 0)
+ {
+ uLocal = (byte) uUnMod.subtract(pow2w).intValue();
+ }
+ else
+ {
+ uLocal = (byte) uUnMod.intValue();
+ }
+ // uLocal is now in [-2^(width-1), 2^(width-1)-1]
+
+ u[i] = uLocal;
+ boolean s = true;
+ if (uLocal < 0)
+ {
+ s = false;
+ uLocal = (byte)-uLocal;
+ }
+ // uLocal is now >= 0
+
+ if (s)
+ {
+ r0 = r0.subtract(alpha[uLocal].u);
+ r1 = r1.subtract(alpha[uLocal].v);
+ }
+ else
+ {
+ r0 = r0.add(alpha[uLocal].u);
+ r1 = r1.add(alpha[uLocal].v);
+ }
+ }
+ else
+ {
+ u[i] = 0;
+ }
+
+ BigInteger t = r0;
+
+ if (mu == 1)
+ {
+ r0 = r1.add(r0.shiftRight(1));
+ }
+ else
+ {
+ // mu == -1
+ r0 = r1.subtract(r0.shiftRight(1));
+ }
+ r1 = t.shiftRight(1).negate();
+ i++;
+ }
+ return u;
+ }
+
+ /**
+ * Does the precomputation for WTNAF multiplication.
+ * @param p The <code>ECPoint</code> for which to do the precomputation.
+ * @param a The parameter <code>a</code> of the elliptic curve.
+ * @return The precomputation array for <code>p</code>.
+ */
+ public static ECPoint.F2m[] getPreComp(ECPoint.F2m 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;
+ }
+
+ int precompLen = alphaTnaf.length;
+ for (int i = 3; i < precompLen; i = i + 2)
+ {
+ pu[i] = Tnaf.multiplyFromTnaf(p, alphaTnaf[i]);
+ }
+
+ return pu;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java
new file mode 100644
index 0000000..10c8ed2
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafMultiplier.java
@@ -0,0 +1,240 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+ * algorithm.
+ */
+class WNafMultiplier implements ECMultiplier
+{
+ /**
+ * Computes the Window NAF (non-adjacent Form) of an integer.
+ * @param width The width <code>w</code> of the Window NAF. The width is
+ * defined as the minimal number <code>w</code>, such that for any
+ * <code>w</code> consecutive digits in the resulting representation, at
+ * most one is non-zero.
+ * @param k The integer of which the Window NAF is computed.
+ * @return The Window NAF of the given width, such that the following holds:
+ * <code>k = &sum;<sub>i=0</sub><sup>l-1</sup> k<sub>i</sub>2<sup>i</sup>
+ * </code>, where the <code>k<sub>i</sub></code> denote the elements of the
+ * returned <code>byte[]</code>.
+ */
+ public byte[] windowNaf(byte width, BigInteger k)
+ {
+ // The window NAF is at most 1 element longer than the binary
+ // representation of the integer k. byte can be used instead of short or
+ // int unless the window width is larger than 8. For larger width use
+ // short or int. However, a width of more than 8 is not efficient for
+ // m = log2(q) smaller than 2305 Bits. Note: Values for m larger than
+ // 1000 Bits are currently not used in practice.
+ byte[] wnaf = new byte[k.bitLength() + 1];
+
+ // 2^width as short and BigInteger
+ short pow2wB = (short)(1 << width);
+ BigInteger pow2wBI = BigInteger.valueOf(pow2wB);
+
+ int i = 0;
+
+ // The actual length of the WNAF
+ int length = 0;
+
+ // while k >= 1
+ while (k.signum() > 0)
+ {
+ // if k is odd
+ if (k.testBit(0))
+ {
+ // k mod 2^width
+ BigInteger remainder = k.mod(pow2wBI);
+
+ // if remainder > 2^(width - 1) - 1
+ if (remainder.testBit(width - 1))
+ {
+ wnaf[i] = (byte)(remainder.intValue() - pow2wB);
+ }
+ else
+ {
+ wnaf[i] = (byte)remainder.intValue();
+ }
+ // wnaf[i] is now in [-2^(width-1), 2^(width-1)-1]
+
+ k = k.subtract(BigInteger.valueOf(wnaf[i]));
+ length = i;
+ }
+ else
+ {
+ wnaf[i] = 0;
+ }
+
+ // k = k/2
+ k = k.shiftRight(1);
+ i++;
+ }
+
+ length++;
+
+ // Reduce the WNAF array to its actual length
+ byte[] wnafShort = new byte[length];
+ System.arraycopy(wnaf, 0, wnafShort, 0, length);
+ return wnafShort;
+ }
+
+ /**
+ * Multiplies <code>this</code> by an integer <code>k</code> using the
+ * Window NAF method.
+ * @param k The integer by which <code>this</code> is multiplied.
+ * @return A new <code>ECPoint</code> which equals <code>this</code>
+ * multiplied by <code>k</code>.
+ */
+ public ECPoint multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+ {
+ WNafPreCompInfo wnafPreCompInfo;
+
+ if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo))
+ {
+ wnafPreCompInfo = (WNafPreCompInfo)preCompInfo;
+ }
+ else
+ {
+ // Ignore empty PreCompInfo or PreCompInfo of incorrect type
+ wnafPreCompInfo = new WNafPreCompInfo();
+ }
+
+ // floor(log2(k))
+ int m = k.bitLength();
+
+ // width of the Window NAF
+ byte width;
+
+ // Required length of precomputation array
+ int reqPreCompLen;
+
+ // Determine optimal width and corresponding length of precomputation
+ // array based on literature values
+ if (m < 13)
+ {
+ width = 2;
+ reqPreCompLen = 1;
+ }
+ else
+ {
+ if (m < 41)
+ {
+ width = 3;
+ reqPreCompLen = 2;
+ }
+ else
+ {
+ if (m < 121)
+ {
+ width = 4;
+ reqPreCompLen = 4;
+ }
+ else
+ {
+ if (m < 337)
+ {
+ width = 5;
+ reqPreCompLen = 8;
+ }
+ else
+ {
+ if (m < 897)
+ {
+ width = 6;
+ reqPreCompLen = 16;
+ }
+ else
+ {
+ if (m < 2305)
+ {
+ width = 7;
+ reqPreCompLen = 32;
+ }
+ else
+ {
+ width = 8;
+ reqPreCompLen = 127;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // The length of the precomputation array
+ int preCompLen = 1;
+
+ ECPoint[] preComp = wnafPreCompInfo.getPreComp();
+ ECPoint twiceP = wnafPreCompInfo.getTwiceP();
+
+ // Check if the precomputed ECPoints already exist
+ if (preComp == null)
+ {
+ // Precomputation must be performed from scratch, create an empty
+ // precomputation array of desired length
+ preComp = new ECPoint[]{ p };
+ }
+ else
+ {
+ // Take the already precomputed ECPoints to start with
+ preCompLen = preComp.length;
+ }
+
+ if (twiceP == null)
+ {
+ // Compute twice(p)
+ twiceP = p.twice();
+ }
+
+ if (preCompLen < reqPreCompLen)
+ {
+ // Precomputation array must be made bigger, copy existing preComp
+ // array into the larger new preComp array
+ ECPoint[] oldPreComp = preComp;
+ preComp = new ECPoint[reqPreCompLen];
+ System.arraycopy(oldPreComp, 0, preComp, 0, preCompLen);
+
+ for (int i = preCompLen; i < reqPreCompLen; i++)
+ {
+ // Compute the new ECPoints for the precomputation array.
+ // The values 1, 3, 5, ..., 2^(width-1)-1 times p are
+ // computed
+ preComp[i] = twiceP.add(preComp[i - 1]);
+ }
+ }
+
+ // Compute the Window NAF of the desired width
+ byte[] wnaf = windowNaf(width, k);
+ int l = wnaf.length;
+
+ // Apply the Window NAF to p using the precomputed ECPoint values.
+ ECPoint q = p.getCurve().getInfinity();
+ for (int i = l - 1; i >= 0; i--)
+ {
+ q = q.twice();
+
+ if (wnaf[i] != 0)
+ {
+ if (wnaf[i] > 0)
+ {
+ q = q.add(preComp[(wnaf[i] - 1)/2]);
+ }
+ else
+ {
+ // wnaf[i] < 0
+ q = q.subtract(preComp[(-wnaf[i] - 1)/2]);
+ }
+ }
+ }
+
+ // Set PreCompInfo in ECPoint, such that it is available for next
+ // multiplication.
+ wnafPreCompInfo.setPreComp(preComp);
+ wnafPreCompInfo.setTwiceP(twiceP);
+ p.setPreCompInfo(wnafPreCompInfo);
+ return q;
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java
new file mode 100644
index 0000000..fc0d5fe
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WNafPreCompInfo.java
@@ -0,0 +1,44 @@
+package org.bouncycastle.math.ec;
+
+/**
+ * Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
+ * algorithm.
+ */
+class WNafPreCompInfo implements PreCompInfo
+{
+ /**
+ * Array holding the precomputed <code>ECPoint</code>s used for the Window
+ * NAF multiplication in <code>
+ * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
+ * WNafMultiplier.multiply()}</code>.
+ */
+ private ECPoint[] preComp = null;
+
+ /**
+ * Holds an <code>ECPoint</code> representing twice(this). Used for the
+ * Window NAF multiplication in <code>
+ * {@link org.bouncycastle.math.ec.multiplier.WNafMultiplier.multiply()
+ * WNafMultiplier.multiply()}</code>.
+ */
+ private ECPoint twiceP = null;
+
+ protected ECPoint[] getPreComp()
+ {
+ return preComp;
+ }
+
+ protected void setPreComp(ECPoint[] preComp)
+ {
+ this.preComp = preComp;
+ }
+
+ protected ECPoint getTwiceP()
+ {
+ return twiceP;
+ }
+
+ protected void setTwiceP(ECPoint twiceThis)
+ {
+ this.twiceP = twiceThis;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java
new file mode 100644
index 0000000..2353979
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafMultiplier.java
@@ -0,0 +1,119 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class implementing the WTNAF (Window
+ * <code>&tau;</code>-adic Non-Adjacent Form) algorithm.
+ */
+class WTauNafMultiplier implements ECMultiplier
+{
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by <code>k</code> using the reduced <code>&tau;</code>-adic NAF (RTNAF)
+ * method.
+ * @param p The ECPoint.F2m to multiply.
+ * @param k The integer by which to multiply <code>k</code>.
+ * @return <code>p</code> multiplied by <code>k</code>.
+ */
+ public ECPoint multiply(ECPoint point, BigInteger k, PreCompInfo preCompInfo)
+ {
+ if (!(point instanceof ECPoint.F2m))
+ {
+ throw new IllegalArgumentException("Only ECPoint.F2m can be " +
+ "used in WTauNafMultiplier");
+ }
+
+ ECPoint.F2m p = (ECPoint.F2m)point;
+
+ ECCurve.F2m curve = (ECCurve.F2m) p.getCurve();
+ int m = curve.getM();
+ byte a = curve.getA().toBigInteger().byteValue();
+ byte mu = curve.getMu();
+ BigInteger[] s = curve.getSi();
+
+ ZTauElement rho = Tnaf.partModReduction(k, m, a, s, mu, (byte)10);
+
+ return multiplyWTnaf(p, rho, preCompInfo, a, mu);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code> using
+ * the <code>&tau;</code>-adic NAF (TNAF) method.
+ * @param p The ECPoint.F2m to multiply.
+ * @param lambda The element <code>&lambda;</code> of
+ * <code><b>Z</b>[&tau;]</code> of which to compute the
+ * <code>[&tau;]</code>-adic NAF.
+ * @return <code>p</code> multiplied by <code>&lambda;</code>.
+ */
+ private ECPoint.F2m multiplyWTnaf(ECPoint.F2m p, ZTauElement lambda,
+ PreCompInfo preCompInfo, byte a, byte mu)
+ {
+ ZTauElement[] alpha;
+ if (a == 0)
+ {
+ alpha = Tnaf.alpha0;
+ }
+ else
+ {
+ // a == 1
+ alpha = 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);
+
+ return multiplyFromWTnaf(p, u, preCompInfo);
+ }
+
+ /**
+ * Multiplies a {@link org.bouncycastle.math.ec.ECPoint.F2m ECPoint.F2m}
+ * by an element <code>&lambda;</code> of <code><b>Z</b>[&tau;]</code>
+ * using the window <code>&tau;</code>-adic NAF (TNAF) method, given the
+ * WTNAF of <code>&lambda;</code>.
+ * @param p The ECPoint.F2m to multiply.
+ * @param u The the WTNAF of <code>&lambda;</code>..
+ * @return <code>&lambda; * p</code>
+ */
+ private static ECPoint.F2m multiplyFromWTnaf(ECPoint.F2m p, byte[] u,
+ PreCompInfo preCompInfo)
+ {
+ ECCurve.F2m curve = (ECCurve.F2m)p.getCurve();
+ byte a = curve.getA().toBigInteger().byteValue();
+
+ ECPoint.F2m[] pu;
+ if ((preCompInfo == null) || !(preCompInfo instanceof WTauNafPreCompInfo))
+ {
+ pu = Tnaf.getPreComp(p, a);
+ p.setPreCompInfo(new WTauNafPreCompInfo(pu));
+ }
+ else
+ {
+ pu = ((WTauNafPreCompInfo)preCompInfo).getPreComp();
+ }
+
+ // q = infinity
+ ECPoint.F2m q = (ECPoint.F2m) p.getCurve().getInfinity();
+ for (int i = u.length - 1; i >= 0; i--)
+ {
+ q = Tnaf.tau(q);
+ if (u[i] != 0)
+ {
+ if (u[i] > 0)
+ {
+ q = q.addSimple(pu[u[i]]);
+ }
+ else
+ {
+ // u[i] < 0
+ q = q.subtractSimple(pu[-u[i]]);
+ }
+ }
+ }
+
+ return q;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java b/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java
new file mode 100644
index 0000000..d7c583f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/WTauNafPreCompInfo.java
@@ -0,0 +1,39 @@
+package org.bouncycastle.math.ec;
+
+/**
+ * Class holding precomputation data for the WTNAF (Window
+ * <code>&tau;</code>-adic Non-Adjacent Form) algorithm.
+ */
+class WTauNafPreCompInfo implements PreCompInfo
+{
+ /**
+ * Array holding the precomputed <code>ECPoint.F2m</code>s used for the
+ * WTNAF multiplication in <code>
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}</code>.
+ */
+ private ECPoint.F2m[] preComp = null;
+
+ /**
+ * Constructor for <code>WTauNafPreCompInfo</code>
+ * @param preComp Array holding the precomputed <code>ECPoint.F2m</code>s
+ * used for the WTNAF multiplication in <code>
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}</code>.
+ */
+ WTauNafPreCompInfo(ECPoint.F2m[] preComp)
+ {
+ this.preComp = preComp;
+ }
+
+ /**
+ * @return the array holding the precomputed <code>ECPoint.F2m</code>s
+ * used for the WTNAF multiplication in <code>
+ * {@link org.bouncycastle.math.ec.multiplier.WTauNafMultiplier.multiply()
+ * WTauNafMultiplier.multiply()}</code>.
+ */
+ protected ECPoint.F2m[] getPreComp()
+ {
+ return preComp;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/math/ec/ZTauElement.java b/bcprov/src/main/java/org/bouncycastle/math/ec/ZTauElement.java
new file mode 100644
index 0000000..7402f22
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/math/ec/ZTauElement.java
@@ -0,0 +1,37 @@
+package org.bouncycastle.math.ec;
+
+import java.math.BigInteger;
+
+/**
+ * Class representing an element of <code><b>Z</b>[&tau;]</code>. Let
+ * <code>&lambda;</code> be an element of <code><b>Z</b>[&tau;]</code>. Then
+ * <code>&lambda;</code> is given as <code>&lambda; = u + v&tau;</code>. The
+ * components <code>u</code> and <code>v</code> may be used directly, there
+ * are no accessor methods.
+ * Immutable class.
+ */
+class ZTauElement
+{
+ /**
+ * The &quot;real&quot; part of <code>&lambda;</code>.
+ */
+ public final BigInteger u;
+
+ /**
+ * The &quot;<code>&tau;</code>-adic&quot; part of <code>&lambda;</code>.
+ */
+ public final BigInteger v;
+
+ /**
+ * Constructor for an element <code>&lambda;</code> of
+ * <code><b>Z</b>[&tau;]</code>.
+ * @param u The &quot;real&quot; part of <code>&lambda;</code>.
+ * @param v The &quot;<code>&tau;</code>-adic&quot; part of
+ * <code>&lambda;</code>.
+ */
+ public ZTauElement(BigInteger u, BigInteger v)
+ {
+ this.u = u;
+ this.v = v;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/Arrays.java b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java
new file mode 100644
index 0000000..4564b68
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/Arrays.java
@@ -0,0 +1,532 @@
+package org.bouncycastle.util;
+
+import java.math.BigInteger;
+
+/**
+ * General array utilities.
+ */
+public final class Arrays
+{
+ private Arrays()
+ {
+ // static class, hide constructor
+ }
+
+ public static boolean areEqual(
+ boolean[] a,
+ boolean[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean areEqual(
+ char[] a,
+ char[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean areEqual(
+ byte[] a,
+ byte[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * A constant time equals comparison - does not terminate early if
+ * test will fail.
+ *
+ * @param a first array
+ * @param b second array
+ * @return true if arrays equal, false otherwise.
+ */
+ public static boolean constantTimeAreEqual(
+ byte[] a,
+ byte[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ int nonEqual = 0;
+
+ for (int i = 0; i != a.length; i++)
+ {
+ nonEqual |= (a[i] ^ b[i]);
+ }
+
+ return nonEqual == 0;
+ }
+
+ public static boolean areEqual(
+ int[] a,
+ int[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean areEqual(
+ long[] a,
+ long[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (a[i] != b[i])
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean areEqual(
+ BigInteger[] a,
+ BigInteger[] b)
+ {
+ if (a == b)
+ {
+ return true;
+ }
+
+ if (a == null || b == null)
+ {
+ return false;
+ }
+
+ if (a.length != b.length)
+ {
+ return false;
+ }
+
+ for (int i = 0; i != a.length; i++)
+ {
+ if (!a[i].equals(b[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static void fill(
+ byte[] array,
+ byte value)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static void fill(
+ long[] array,
+ long value)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static void fill(
+ short[] array,
+ short value)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static void fill(
+ int[] array,
+ int value)
+ {
+ for (int i = 0; i < array.length; i++)
+ {
+ array[i] = value;
+ }
+ }
+
+ public static int hashCode(byte[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i];
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(char[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i];
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(int[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i];
+ }
+
+ return hc;
+ }
+
+ public static int hashCode(BigInteger[] data)
+ {
+ if (data == null)
+ {
+ return 0;
+ }
+
+ int i = data.length;
+ int hc = i + 1;
+
+ while (--i >= 0)
+ {
+ hc *= 257;
+ hc ^= data[i].hashCode();
+ }
+
+ return hc;
+ }
+
+ public static byte[] clone(byte[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ byte[] copy = new byte[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ public static int[] clone(int[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ int[] copy = new int[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ public static BigInteger[] clone(BigInteger[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+ BigInteger[] copy = new BigInteger[data.length];
+
+ System.arraycopy(data, 0, copy, 0, data.length);
+
+ return copy;
+ }
+
+ public static byte[] copyOf(byte[] data, int newLength)
+ {
+ byte[] tmp = new byte[newLength];
+
+ if (newLength < data.length)
+ {
+ System.arraycopy(data, 0, tmp, 0, newLength);
+ }
+ else
+ {
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ }
+
+ return tmp;
+ }
+
+ public static int[] copyOf(int[] data, int newLength)
+ {
+ int[] tmp = new int[newLength];
+
+ if (newLength < data.length)
+ {
+ System.arraycopy(data, 0, tmp, 0, newLength);
+ }
+ else
+ {
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ }
+
+ return tmp;
+ }
+
+ public static long[] copyOf(long[] data, int newLength)
+ {
+ long[] tmp = new long[newLength];
+
+ if (newLength < data.length)
+ {
+ System.arraycopy(data, 0, tmp, 0, newLength);
+ }
+ else
+ {
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ }
+
+ return tmp;
+ }
+
+ public static BigInteger[] copyOf(BigInteger[] data, int newLength)
+ {
+ BigInteger[] tmp = new BigInteger[newLength];
+
+ if (newLength < data.length)
+ {
+ System.arraycopy(data, 0, tmp, 0, newLength);
+ }
+ else
+ {
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ }
+
+ return tmp;
+ }
+
+ public static byte[] copyOfRange(byte[] data, int from, int to)
+ {
+ int newLength = getLength(from, to);
+
+ byte[] tmp = new byte[newLength];
+
+ if (data.length - from < newLength)
+ {
+ System.arraycopy(data, from, tmp, 0, data.length - from);
+ }
+ else
+ {
+ System.arraycopy(data, from, tmp, 0, newLength);
+ }
+
+ return tmp;
+ }
+
+ public static int[] copyOfRange(int[] data, int from, int to)
+ {
+ int newLength = getLength(from, to);
+
+ int[] tmp = new int[newLength];
+
+ if (data.length - from < newLength)
+ {
+ System.arraycopy(data, from, tmp, 0, data.length - from);
+ }
+ else
+ {
+ System.arraycopy(data, from, tmp, 0, newLength);
+ }
+
+ return tmp;
+ }
+
+ public static long[] copyOfRange(long[] data, int from, int to)
+ {
+ int newLength = getLength(from, to);
+
+ long[] tmp = new long[newLength];
+
+ if (data.length - from < newLength)
+ {
+ System.arraycopy(data, from, tmp, 0, data.length - from);
+ }
+ else
+ {
+ System.arraycopy(data, from, tmp, 0, newLength);
+ }
+
+ return tmp;
+ }
+
+ public static BigInteger[] copyOfRange(BigInteger[] data, int from, int to)
+ {
+ int newLength = getLength(from, to);
+
+ BigInteger[] tmp = new BigInteger[newLength];
+
+ if (data.length - from < newLength)
+ {
+ System.arraycopy(data, from, tmp, 0, data.length - from);
+ }
+ else
+ {
+ System.arraycopy(data, from, tmp, 0, newLength);
+ }
+
+ return tmp;
+ }
+
+ private static int getLength(int from, int to)
+ {
+ int newLength = to - from;
+ if (newLength < 0)
+ {
+ throw new IllegalArgumentException(from + " > " + to);
+ }
+ return newLength;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java b/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java
new file mode 100644
index 0000000..2115799
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/BigIntegers.java
@@ -0,0 +1,78 @@
+package org.bouncycastle.util;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+/**
+ * BigInteger utilities.
+ */
+public final class BigIntegers
+{
+ private static final int MAX_ITERATIONS = 1000;
+ private static final BigInteger ZERO = BigInteger.valueOf(0);
+
+ /**
+ * Return the passed in value as an unsigned byte array.
+ *
+ * @param value value to be converted.
+ * @return a byte array without a leading zero byte if present in the signed encoding.
+ */
+ public static byte[] asUnsignedByteArray(
+ BigInteger value)
+ {
+ byte[] bytes = value.toByteArray();
+
+ if (bytes[0] == 0)
+ {
+ byte[] tmp = new byte[bytes.length - 1];
+
+ System.arraycopy(bytes, 1, tmp, 0, tmp.length);
+
+ return tmp;
+ }
+
+ return bytes;
+ }
+
+ /**
+ * Return a random BigInteger not less than 'min' and not greater than 'max'
+ *
+ * @param min the least value that may be generated
+ * @param max the greatest value that may be generated
+ * @param random the source of randomness
+ * @return a random BigInteger value in the range [min,max]
+ */
+ public static BigInteger createRandomInRange(
+ BigInteger min,
+ BigInteger max,
+ SecureRandom random)
+ {
+ int cmp = min.compareTo(max);
+ if (cmp >= 0)
+ {
+ if (cmp > 0)
+ {
+ throw new IllegalArgumentException("'min' may not be greater than 'max'");
+ }
+
+ return min;
+ }
+
+ if (min.bitLength() > max.bitLength() / 2)
+ {
+ return createRandomInRange(ZERO, max.subtract(min), random).add(min);
+ }
+
+ for (int i = 0; i < MAX_ITERATIONS; ++i)
+ {
+ BigInteger x = new BigInteger(max.bitLength(), random);
+ if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0)
+ {
+ return x;
+ }
+ }
+
+ // fall back to a faster (restricted) method
+ return new BigInteger(max.subtract(min).bitLength() - 1, random).add(min);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/CollectionStore.java b/bcprov/src/main/java/org/bouncycastle/util/CollectionStore.java
new file mode 100644
index 0000000..91aba14
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/CollectionStore.java
@@ -0,0 +1,57 @@
+package org.bouncycastle.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A simple collection backed store.
+ */
+public class CollectionStore
+ implements Store
+{
+ private Collection _local;
+
+ /**
+ * Basic constructor.
+ *
+ * @param collection - initial contents for the store, this is copied.
+ */
+ public CollectionStore(
+ Collection collection)
+ {
+ _local = new ArrayList(collection);
+ }
+
+ /**
+ * Return the matches in the collection for the passed in selector.
+ *
+ * @param selector the selector to match against.
+ * @return a possibly empty collection of matching objects.
+ */
+ public Collection getMatches(Selector selector)
+ {
+ if (selector == null)
+ {
+ return new ArrayList(_local);
+ }
+ else
+ {
+ List col = new ArrayList();
+ Iterator iter = _local.iterator();
+
+ while (iter.hasNext())
+ {
+ Object obj = iter.next();
+
+ if (selector.match(obj))
+ {
+ col.add(obj);
+ }
+ }
+
+ return col;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java b/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java
new file mode 100644
index 0000000..9f5d1cb
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/IPAddress.java
@@ -0,0 +1,188 @@
+package org.bouncycastle.util;
+
+public class IPAddress
+{
+ /**
+ * Validate the given IPv4 or IPv6 address.
+ *
+ * @param address the IP address as a String.
+ *
+ * @return true if a valid address, false otherwise
+ */
+ public static boolean isValid(
+ String address)
+ {
+ return isValidIPv4(address) || isValidIPv6(address);
+ }
+
+ /**
+ * Validate the given IPv4 or IPv6 address and netmask.
+ *
+ * @param address the IP address as a String.
+ *
+ * @return true if a valid address with netmask, false otherwise
+ */
+ public static boolean isValidWithNetMask(
+ String address)
+ {
+ return isValidIPv4WithNetmask(address) || isValidIPv6WithNetmask(address);
+ }
+
+ /**
+ * Validate the given IPv4 address.
+ *
+ * @param address the IP address as a String.
+ *
+ * @return true if a valid IPv4 address, false otherwise
+ */
+ public static boolean isValidIPv4(
+ String address)
+ {
+ if (address.length() == 0)
+ {
+ return false;
+ }
+
+ int octet;
+ int octets = 0;
+
+ String temp = address+".";
+
+ int pos;
+ int start = 0;
+ while (start < temp.length()
+ && (pos = temp.indexOf('.', start)) > start)
+ {
+ if (octets == 4)
+ {
+ return false;
+ }
+ try
+ {
+ octet = Integer.parseInt(temp.substring(start, pos));
+ }
+ catch (NumberFormatException ex)
+ {
+ return false;
+ }
+ if (octet < 0 || octet > 255)
+ {
+ return false;
+ }
+ start = pos + 1;
+ octets++;
+ }
+
+ return octets == 4;
+ }
+
+ public static boolean isValidIPv4WithNetmask(
+ String address)
+ {
+ int index = address.indexOf("/");
+ String mask = address.substring(index + 1);
+
+ return (index > 0) && isValidIPv4(address.substring(0, index))
+ && (isValidIPv4(mask) || isMaskValue(mask, 32));
+ }
+
+ public static boolean isValidIPv6WithNetmask(
+ String address)
+ {
+ int index = address.indexOf("/");
+ String mask = address.substring(index + 1);
+
+ return (index > 0) && (isValidIPv6(address.substring(0, index))
+ && (isValidIPv6(mask) || isMaskValue(mask, 128)));
+ }
+
+ private static boolean isMaskValue(String component, int size)
+ {
+ try
+ {
+ int value = Integer.parseInt(component);
+
+ return value >= 0 && value <= size;
+ }
+ catch (NumberFormatException e)
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Validate the given IPv6 address.
+ *
+ * @param address the IP address as a String.
+ *
+ * @return true if a valid IPv4 address, false otherwise
+ */
+ public static boolean isValidIPv6(
+ String address)
+ {
+ if (address.length() == 0)
+ {
+ return false;
+ }
+
+ int octet;
+ int octets = 0;
+
+ String temp = address + ":";
+ boolean doubleColonFound = false;
+ int pos;
+ int start = 0;
+ while (start < temp.length()
+ && (pos = temp.indexOf(':', start)) >= start)
+ {
+ if (octets == 8)
+ {
+ return false;
+ }
+
+ if (start != pos)
+ {
+ String value = temp.substring(start, pos);
+
+ if (pos == (temp.length() - 1) && value.indexOf('.') > 0)
+ {
+ if (!isValidIPv4(value))
+ {
+ return false;
+ }
+
+ octets++; // add an extra one as address covers 2 words.
+ }
+ else
+ {
+ try
+ {
+ octet = Integer.parseInt(temp.substring(start, pos), 16);
+ }
+ catch (NumberFormatException ex)
+ {
+ return false;
+ }
+ if (octet < 0 || octet > 0xffff)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (pos != 1 && pos != temp.length() - 1 && doubleColonFound)
+ {
+ return false;
+ }
+ doubleColonFound = true;
+ }
+ start = pos + 1;
+ octets++;
+ }
+
+ return octets == 8 || doubleColonFound;
+ }
+}
+
+
diff --git a/bcprov/src/main/java/org/bouncycastle/util/Selector.java b/bcprov/src/main/java/org/bouncycastle/util/Selector.java
new file mode 100644
index 0000000..7ad86bf
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/Selector.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.util;
+
+public interface Selector
+ extends Cloneable
+{
+ boolean match(Object obj);
+
+ Object clone();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/Store.java b/bcprov/src/main/java/org/bouncycastle/util/Store.java
new file mode 100644
index 0000000..b994c92
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/Store.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.util;
+
+import java.util.Collection;
+
+public interface Store
+{
+ Collection getMatches(Selector selector)
+ throws StoreException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/StoreException.java b/bcprov/src/main/java/org/bouncycastle/util/StoreException.java
new file mode 100644
index 0000000..5ea09e8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/StoreException.java
@@ -0,0 +1,18 @@
+package org.bouncycastle.util;
+
+public class StoreException
+ extends RuntimeException
+{
+ private Throwable _e;
+
+ public StoreException(String s, Throwable e)
+ {
+ super(s);
+ _e = e;
+ }
+
+ public Throwable getCause()
+ {
+ return _e;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/Strings.java b/bcprov/src/main/java/org/bouncycastle/util/Strings.java
new file mode 100644
index 0000000..7f67404
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/Strings.java
@@ -0,0 +1,303 @@
+package org.bouncycastle.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Vector;
+
+public final class Strings
+{
+ public static String fromUTF8ByteArray(byte[] bytes)
+ {
+ int i = 0;
+ int length = 0;
+
+ while (i < bytes.length)
+ {
+ length++;
+ if ((bytes[i] & 0xf0) == 0xf0)
+ {
+ // surrogate pair
+ length++;
+ i += 4;
+ }
+ else if ((bytes[i] & 0xe0) == 0xe0)
+ {
+ i += 3;
+ }
+ else if ((bytes[i] & 0xc0) == 0xc0)
+ {
+ i += 2;
+ }
+ else
+ {
+ i += 1;
+ }
+ }
+
+ char[] cs = new char[length];
+
+ i = 0;
+ length = 0;
+
+ while (i < bytes.length)
+ {
+ char ch;
+
+ 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 U = codePoint - 0x10000;
+ char W1 = (char)(0xD800 | (U >> 10));
+ char W2 = (char)(0xDC00 | (U & 0x3FF));
+ cs[length++] = W1;
+ ch = W2;
+ i += 4;
+ }
+ else if ((bytes[i] & 0xe0) == 0xe0)
+ {
+ ch = (char)(((bytes[i] & 0x0f) << 12)
+ | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f));
+ i += 3;
+ }
+ else if ((bytes[i] & 0xd0) == 0xd0)
+ {
+ ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
+ i += 2;
+ }
+ else if ((bytes[i] & 0xc0) == 0xc0)
+ {
+ ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
+ i += 2;
+ }
+ else
+ {
+ ch = (char)(bytes[i] & 0xff);
+ i += 1;
+ }
+
+ cs[length++] = ch;
+ }
+
+ return new String(cs);
+ }
+
+ public static byte[] toUTF8ByteArray(String string)
+ {
+ return toUTF8ByteArray(string.toCharArray());
+ }
+
+ public static byte[] toUTF8ByteArray(char[] string)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ toUTF8ByteArray(string, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new IllegalStateException("cannot encode string to byte array!");
+ }
+
+ return bOut.toByteArray();
+ }
+
+ public static void toUTF8ByteArray(char[] string, OutputStream sOut)
+ throws IOException
+ {
+ char[] c = string;
+ int i = 0;
+
+ while (i < c.length)
+ {
+ char ch = c[i];
+
+ if (ch < 0x0080)
+ {
+ sOut.write(ch);
+ }
+ else if (ch < 0x0800)
+ {
+ sOut.write(0xc0 | (ch >> 6));
+ sOut.write(0x80 | (ch & 0x3f));
+ }
+ // surrogate pair
+ else if (ch >= 0xD800 && ch <= 0xDFFF)
+ {
+ // in error - can only happen, if the Java String class has a
+ // bug.
+ if (i + 1 >= c.length)
+ {
+ throw new IllegalStateException("invalid UTF-16 codepoint");
+ }
+ char W1 = ch;
+ ch = c[++i];
+ char W2 = ch;
+ // in error - can only happen, if the Java String class has a
+ // bug.
+ if (W1 > 0xDBFF)
+ {
+ throw new IllegalStateException("invalid UTF-16 codepoint");
+ }
+ int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000;
+ sOut.write(0xf0 | (codePoint >> 18));
+ sOut.write(0x80 | ((codePoint >> 12) & 0x3F));
+ sOut.write(0x80 | ((codePoint >> 6) & 0x3F));
+ sOut.write(0x80 | (codePoint & 0x3F));
+ }
+ else
+ {
+ sOut.write(0xe0 | (ch >> 12));
+ sOut.write(0x80 | ((ch >> 6) & 0x3F));
+ sOut.write(0x80 | (ch & 0x3F));
+ }
+
+ i++;
+ }
+ }
+
+ /**
+ * A locale independent version of toUpperCase.
+ *
+ * @param string input to be converted
+ * @return a US Ascii uppercase version
+ */
+ public static String toUpperCase(String string)
+ {
+ boolean changed = false;
+ char[] chars = string.toCharArray();
+
+ for (int i = 0; i != chars.length; i++)
+ {
+ char ch = chars[i];
+ if ('a' <= ch && 'z' >= ch)
+ {
+ changed = true;
+ 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
+ */
+ public static String toLowerCase(String string)
+ {
+ boolean changed = false;
+ char[] chars = string.toCharArray();
+
+ for (int i = 0; i != chars.length; i++)
+ {
+ char ch = chars[i];
+ if ('A' <= ch && 'Z' >= ch)
+ {
+ changed = true;
+ chars[i] = (char)(ch - 'A' + 'a');
+ }
+ }
+
+ if (changed)
+ {
+ return new String(chars);
+ }
+
+ return string;
+ }
+
+ public static byte[] toByteArray(char[] chars)
+ {
+ byte[] bytes = new byte[chars.length];
+
+ for (int i = 0; i != bytes.length; i++)
+ {
+ bytes[i] = (byte)chars[i];
+ }
+
+ return bytes;
+ }
+
+ public static byte[] toByteArray(String string)
+ {
+ byte[] bytes = new byte[string.length()];
+
+ for (int i = 0; i != bytes.length; i++)
+ {
+ char ch = string.charAt(i);
+
+ bytes[i] = (byte)ch;
+ }
+
+ return bytes;
+ }
+
+ /**
+ * Convert an array of 8 bit characters into a string.
+ *
+ * @param bytes 8 bit characters.
+ * @return resulting String.
+ */
+ public static String fromByteArray(byte[] bytes)
+ {
+ return new String(asCharArray(bytes));
+ }
+
+ /**
+ * Do a simple conversion of an array of 8 bit characters into a string.
+ *
+ * @param bytes 8 bit characters.
+ * @return resulting String.
+ */
+ public static char[] asCharArray(byte[] bytes)
+ {
+ char[] chars = new char[bytes.length];
+
+ for (int i = 0; i != chars.length; i++)
+ {
+ chars[i] = (char)(bytes[i] & 0xff);
+ }
+
+ return chars;
+ }
+
+ public static String[] split(String input, char delimiter)
+ {
+ Vector v = new Vector();
+ boolean moreTokens = true;
+ String subString;
+
+ while (moreTokens)
+ {
+ int tokenLocation = input.indexOf(delimiter);
+ if (tokenLocation > 0)
+ {
+ subString = input.substring(0, tokenLocation);
+ v.addElement(subString);
+ input = input.substring(tokenLocation + 1);
+ }
+ else
+ {
+ moreTokens = false;
+ v.addElement(input);
+ }
+ }
+
+ String[] res = new String[v.size()];
+
+ for (int i = 0; i != res.length; i++)
+ {
+ res[i] = (String)v.elementAt(i);
+ }
+ return res;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64.java b/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64.java
new file mode 100644
index 0000000..93fed64
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64.java
@@ -0,0 +1,121 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Base64
+{
+ private static final Encoder encoder = new Base64Encoder();
+
+ /**
+ * encode the input data producing a base 64 encoded byte array.
+ *
+ * @return a byte array containing the base 64 encoded data.
+ */
+ public static byte[] encode(
+ byte[] data)
+ {
+ int len = (data.length + 2) / 3 * 4;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+ try
+ {
+ encoder.encode(data, 0, data.length, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("exception encoding base64 string: " + e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, 0, data.length, out);
+ }
+
+ /**
+ * Encode the byte data to base 64 writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, off, length, out);
+ }
+
+ /**
+ * decode the base 64 encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ byte[] data)
+ {
+ int len = data.length / 4 * 3;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+ try
+ {
+ encoder.decode(data, 0, data.length, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("exception decoding base64 string: " + e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the base 64 encoded String data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ String data)
+ {
+ int len = data.length() / 4 * 3;
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream(len);
+
+ try
+ {
+ encoder.decode(data, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("exception decoding base64 string: " + e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the base 64 encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.decode(data, out);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java b/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java
new file mode 100644
index 0000000..3edc068
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java
@@ -0,0 +1,298 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+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)'/'
+ };
+
+ protected byte padding = (byte)'=';
+
+ /*
+ * set up the decoding table.
+ */
+ protected final byte[] decodingTable = new byte[128];
+
+ protected void initialiseDecodingTable()
+ {
+ for (int i = 0; i < encodingTable.length; i++)
+ {
+ decodingTable[encodingTable[i]] = (byte)i;
+ }
+ }
+
+ public Base64Encoder()
+ {
+ initialiseDecodingTable();
+ }
+
+ /**
+ * encode the input data producing a base 64 output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ int modulus = length % 3;
+ int dataLength = (length - modulus);
+ int a1, a2, a3;
+
+ for (int i = off; i < off + dataLength; i += 3)
+ {
+ a1 = data[i] & 0xff;
+ a2 = data[i + 1] & 0xff;
+ a3 = data[i + 2] & 0xff;
+
+ out.write(encodingTable[(a1 >>> 2) & 0x3f]);
+ out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
+ out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
+ out.write(encodingTable[a3 & 0x3f]);
+ }
+
+ /*
+ * process the tail end.
+ */
+ int b1, b2, b3;
+ int d1, d2;
+
+ switch (modulus)
+ {
+ case 0: /* nothing left to do */
+ break;
+ case 1:
+ d1 = data[off + dataLength] & 0xff;
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = (d1 << 4) & 0x3f;
+
+ out.write(encodingTable[b1]);
+ out.write(encodingTable[b2]);
+ out.write(padding);
+ out.write(padding);
+ break;
+ case 2:
+ d1 = data[off + dataLength] & 0xff;
+ d2 = data[off + dataLength + 1] & 0xff;
+
+ b1 = (d1 >>> 2) & 0x3f;
+ b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
+ b3 = (d2 << 2) & 0x3f;
+
+ out.write(encodingTable[b1]);
+ out.write(encodingTable[b2]);
+ out.write(encodingTable[b3]);
+ out.write(padding);
+ break;
+ }
+
+ return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
+ }
+
+ private boolean ignore(
+ char c)
+ {
+ return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
+ }
+
+ /**
+ * decode the base 64 encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int decode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ byte b1, b2, b3, b4;
+ int outLen = 0;
+
+ int end = off + length;
+
+ while (end > off)
+ {
+ if (!ignore((char)data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = off;
+ int finish = end - 4;
+
+ i = nextI(data, i, finish);
+
+ while (i < finish)
+ {
+ b1 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b2 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b3 = decodingTable[data[i++]];
+
+ i = nextI(data, i, finish);
+
+ b4 = decodingTable[data[i++]];
+
+ out.write((b1 << 2) | (b2 >> 4));
+ out.write((b2 << 4) | (b3 >> 2));
+ out.write((b3 << 6) | b4);
+
+ outLen += 3;
+
+ i = nextI(data, i, finish);
+ }
+
+ outLen += decodeLastBlock(out, (char)data[end - 4], (char)data[end - 3], (char)data[end - 2], (char)data[end - 1]);
+
+ return outLen;
+ }
+
+ private int nextI(byte[] data, int i, int finish)
+ {
+ while ((i < finish) && ignore((char)data[i]))
+ {
+ i++;
+ }
+ return i;
+ }
+
+ /**
+ * decode the base 64 encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ byte b1, b2, b3, b4;
+ int length = 0;
+
+ int end = data.length();
+
+ while (end > 0)
+ {
+ if (!ignore(data.charAt(end - 1)))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = 0;
+ int finish = end - 4;
+
+ i = nextI(data, i, finish);
+
+ while (i < finish)
+ {
+ b1 = decodingTable[data.charAt(i++)];
+
+ i = nextI(data, i, finish);
+
+ b2 = decodingTable[data.charAt(i++)];
+
+ i = nextI(data, i, finish);
+
+ b3 = decodingTable[data.charAt(i++)];
+
+ i = nextI(data, i, finish);
+
+ b4 = decodingTable[data.charAt(i++)];
+
+ out.write((b1 << 2) | (b2 >> 4));
+ out.write((b2 << 4) | (b3 >> 2));
+ out.write((b3 << 6) | b4);
+
+ length += 3;
+
+ i = nextI(data, i, finish);
+ }
+
+ length += decodeLastBlock(out, data.charAt(end - 4), data.charAt(end - 3), data.charAt(end - 2), data.charAt(end - 1));
+
+ return length;
+ }
+
+ private int decodeLastBlock(OutputStream out, char c1, char c2, char c3, char c4)
+ throws IOException
+ {
+ byte b1, b2, b3, b4;
+
+ if (c3 == padding)
+ {
+ b1 = decodingTable[c1];
+ b2 = decodingTable[c2];
+
+ out.write((b1 << 2) | (b2 >> 4));
+
+ return 1;
+ }
+ else if (c4 == padding)
+ {
+ b1 = decodingTable[c1];
+ b2 = decodingTable[c2];
+ b3 = decodingTable[c3];
+
+ out.write((b1 << 2) | (b2 >> 4));
+ out.write((b2 << 4) | (b3 >> 2));
+
+ return 2;
+ }
+ else
+ {
+ b1 = decodingTable[c1];
+ b2 = decodingTable[c2];
+ b3 = decodingTable[c3];
+ b4 = decodingTable[c4];
+
+ out.write((b1 << 2) | (b2 >> 4));
+ out.write((b2 << 4) | (b3 >> 2));
+ out.write((b3 << 6) | b4);
+
+ return 3;
+ }
+ }
+
+ private int nextI(String data, int i, int finish)
+ {
+ while ((i < finish) && ignore(data.charAt(i)))
+ {
+ i++;
+ }
+ return i;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/encoders/Encoder.java b/bcprov/src/main/java/org/bouncycastle/util/encoders/Encoder.java
new file mode 100644
index 0000000..b066121
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/encoders/Encoder.java
@@ -0,0 +1,17 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Encode and decode byte arrays (typically from binary to 7-bit ASCII
+ * encodings).
+ */
+public interface Encoder
+{
+ int encode(byte[] data, int off, int length, OutputStream out) throws IOException;
+
+ int decode(byte[] data, int off, int length, OutputStream out) throws IOException;
+
+ int decode(String data, OutputStream out) throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/encoders/Hex.java b/bcprov/src/main/java/org/bouncycastle/util/encoders/Hex.java
new file mode 100644
index 0000000..d69f773
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/encoders/Hex.java
@@ -0,0 +1,131 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class Hex
+{
+ private static final Encoder encoder = new HexEncoder();
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] encode(
+ byte[] data)
+ {
+ return encode(data, 0, data.length);
+ }
+
+ /**
+ * encode the input data producing a Hex encoded byte array.
+ *
+ * @return a byte array containing the Hex encoded data.
+ */
+ public static byte[] encode(
+ byte[] data,
+ int off,
+ int length)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.encode(data, off, length, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("exception encoding Hex string: " + e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, 0, data.length, out);
+ }
+
+ /**
+ * Hex encode the byte data writing it to the given output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.encode(data, off, length, out);
+ }
+
+ /**
+ * decode the Hex encoded input data. It is assumed the input data is valid.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ byte[] data)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.decode(data, 0, data.length, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("exception decoding Hex string: " + e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the Hex encoded String data - whitespace will be ignored.
+ *
+ * @return a byte array representing the decoded data.
+ */
+ public static byte[] decode(
+ String data)
+ {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ try
+ {
+ encoder.decode(data, bOut);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("exception decoding Hex string: " + e);
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * decode the Hex encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public static int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ return encoder.decode(data, out);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java b/bcprov/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java
new file mode 100644
index 0000000..0dcae29
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java
@@ -0,0 +1,172 @@
+package org.bouncycastle.util.encoders;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+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'
+ };
+
+ /*
+ * set up the decoding table.
+ */
+ protected final byte[] decodingTable = new byte[128];
+
+ protected void initialiseDecodingTable()
+ {
+ for (int i = 0; i < encodingTable.length; i++)
+ {
+ decodingTable[encodingTable[i]] = (byte)i;
+ }
+
+ decodingTable['A'] = decodingTable['a'];
+ decodingTable['B'] = decodingTable['b'];
+ decodingTable['C'] = decodingTable['c'];
+ decodingTable['D'] = decodingTable['d'];
+ decodingTable['E'] = decodingTable['e'];
+ decodingTable['F'] = decodingTable['f'];
+ }
+
+ public HexEncoder()
+ {
+ initialiseDecodingTable();
+ }
+
+ /**
+ * encode the input data producing a Hex output stream.
+ *
+ * @return the number of bytes produced.
+ */
+ public int encode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ for (int i = off; i < (off + length); i++)
+ {
+ int v = data[i] & 0xff;
+
+ out.write(encodingTable[(v >>> 4)]);
+ out.write(encodingTable[v & 0xf]);
+ }
+
+ return length * 2;
+ }
+
+ private boolean ignore(
+ char c)
+ {
+ return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
+ }
+
+ /**
+ * decode the Hex encoded byte data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int decode(
+ byte[] data,
+ int off,
+ int length,
+ OutputStream out)
+ throws IOException
+ {
+ byte b1, b2;
+ int outLen = 0;
+
+ int end = off + length;
+
+ while (end > off)
+ {
+ if (!ignore((char)data[end - 1]))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = off;
+ while (i < end)
+ {
+ while (i < end && ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b1 = decodingTable[data[i++]];
+
+ while (i < end && ignore((char)data[i]))
+ {
+ i++;
+ }
+
+ b2 = decodingTable[data[i++]];
+
+ out.write((b1 << 4) | b2);
+
+ outLen++;
+ }
+
+ return outLen;
+ }
+
+ /**
+ * decode the Hex encoded String data writing it to the given output stream,
+ * whitespace characters will be ignored.
+ *
+ * @return the number of bytes produced.
+ */
+ public int decode(
+ String data,
+ OutputStream out)
+ throws IOException
+ {
+ byte b1, b2;
+ int length = 0;
+
+ int end = data.length();
+
+ while (end > 0)
+ {
+ if (!ignore(data.charAt(end - 1)))
+ {
+ break;
+ }
+
+ end--;
+ }
+
+ int i = 0;
+ while (i < end)
+ {
+ while (i < end && ignore(data.charAt(i)))
+ {
+ i++;
+ }
+
+ b1 = decodingTable[data.charAt(i++)];
+
+ while (i < end && ignore(data.charAt(i)))
+ {
+ i++;
+ }
+
+ b2 = decodingTable[data.charAt(i++)];
+
+ out.write((b1 << 4) | b2);
+
+ length++;
+ }
+
+ return length;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/StreamOverflowException.java b/bcprov/src/main/java/org/bouncycastle/util/io/StreamOverflowException.java
new file mode 100644
index 0000000..01af8da
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/StreamOverflowException.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.util.io;
+
+import java.io.IOException;
+
+public class StreamOverflowException
+ extends IOException
+{
+ public StreamOverflowException(String msg)
+ {
+ super(msg);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java b/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java
new file mode 100644
index 0000000..41560b5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/Streams.java
@@ -0,0 +1,87 @@
+package org.bouncycastle.util.io;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public final class Streams
+{
+ private static int BUFFER_SIZE = 512;
+
+ public static void drain(InputStream inStr)
+ throws IOException
+ {
+ byte[] bs = new byte[BUFFER_SIZE];
+ while (inStr.read(bs, 0, bs.length) >= 0)
+ {
+ }
+ }
+
+ public static byte[] readAll(InputStream inStr)
+ throws IOException
+ {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ pipeAll(inStr, buf);
+ return buf.toByteArray();
+ }
+
+ public static byte[] readAllLimited(InputStream inStr, int limit)
+ throws IOException
+ {
+ ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ pipeAllLimited(inStr, limit, buf);
+ return buf.toByteArray();
+ }
+
+ public static int readFully(InputStream inStr, byte[] buf)
+ throws IOException
+ {
+ return readFully(inStr, buf, 0, buf.length);
+ }
+
+ public static int readFully(InputStream inStr, byte[] buf, int off, int len)
+ throws IOException
+ {
+ int totalRead = 0;
+ while (totalRead < len)
+ {
+ int numRead = inStr.read(buf, off + totalRead, len - totalRead);
+ if (numRead < 0)
+ {
+ break;
+ }
+ totalRead += numRead;
+ }
+ return totalRead;
+ }
+
+ public static void pipeAll(InputStream inStr, OutputStream outStr)
+ throws IOException
+ {
+ byte[] bs = new byte[BUFFER_SIZE];
+ int numRead;
+ while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)
+ {
+ outStr.write(bs, 0, numRead);
+ }
+ }
+
+ public static long pipeAllLimited(InputStream inStr, long limit, OutputStream outStr)
+ throws IOException
+ {
+ long total = 0;
+ byte[] bs = new byte[BUFFER_SIZE];
+ int numRead;
+ while ((numRead = inStr.read(bs, 0, bs.length)) >= 0)
+ {
+ total += numRead;
+ if (total > limit)
+ {
+ throw new StreamOverflowException("Data Overflow");
+ }
+ outStr.write(bs, 0, numRead);
+ }
+ return total;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/TeeInputStream.java b/bcprov/src/main/java/org/bouncycastle/util/io/TeeInputStream.java
new file mode 100644
index 0000000..9154246
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/TeeInputStream.java
@@ -0,0 +1,62 @@
+package org.bouncycastle.util.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class TeeInputStream
+ extends InputStream
+{
+ private final InputStream input;
+ private final OutputStream output;
+
+ public TeeInputStream(InputStream input, OutputStream output)
+ {
+ this.input = input;
+ this.output = output;
+ }
+
+ public int read(byte[] buf)
+ throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException
+ {
+ int i = input.read(buf, off, len);
+
+ if (i > 0)
+ {
+ output.write(buf, off, i);
+ }
+
+ return i;
+ }
+
+ public int read()
+ throws IOException
+ {
+ int i = input.read();
+
+ if (i >= 0)
+ {
+ output.write(i);
+ }
+
+ return i;
+ }
+
+ public void close()
+ throws IOException
+ {
+ this.input.close();
+ this.output.close();
+ }
+
+ public OutputStream getOutputStream()
+ {
+ return output;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java b/bcprov/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java
new file mode 100644
index 0000000..a4919cd
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/TeeOutputStream.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.util.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class TeeOutputStream
+ extends OutputStream
+{
+ private OutputStream output1;
+ private OutputStream output2;
+
+ public TeeOutputStream(OutputStream output1, OutputStream output2)
+ {
+ this.output1 = output1;
+ this.output2 = output2;
+ }
+
+ public void write(byte[] buf)
+ throws IOException
+ {
+ this.output1.write(buf);
+ this.output2.write(buf);
+ }
+
+ public void write(byte[] buf, int off, int len)
+ throws IOException
+ {
+ this.output1.write(buf, off, len);
+ this.output2.write(buf, off, len);
+ }
+
+ public void write(int b)
+ throws IOException
+ {
+ this.output1.write(b);
+ this.output2.write(b);
+ }
+
+ public void flush()
+ throws IOException
+ {
+ this.output1.flush();
+ this.output2.flush();
+ }
+
+ public void close()
+ throws IOException
+ {
+ this.output1.close();
+ this.output2.close();
+ }
+} \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java
new file mode 100644
index 0000000..69a773e
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemGenerationException.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.util.io.pem;
+
+import java.io.IOException;
+
+public class PemGenerationException
+ extends IOException
+{
+ private Throwable cause;
+
+ public PemGenerationException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public PemGenerationException(String message)
+ {
+ super(message);
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java
new file mode 100644
index 0000000..b201c13
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemHeader.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.util.io.pem;
+
+public class PemHeader
+{
+ private String name;
+ private String value;
+
+ public PemHeader(String name, String value)
+ {
+ this.name = name;
+ this.value = value;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+
+ public int hashCode()
+ {
+ return getHashCode(this.name) + 31 * getHashCode(this.value);
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof PemHeader))
+ {
+ return false;
+ }
+
+ PemHeader other = (PemHeader)o;
+
+ return other == this || (isEqual(this.name, other.name) && isEqual(this.value, other.value));
+ }
+
+ private int getHashCode(String s)
+ {
+ if (s == null)
+ {
+ return 1;
+ }
+
+ return s.hashCode();
+ }
+
+ private boolean isEqual(String s1, String s2)
+ {
+ if (s1 == s2)
+ {
+ return true;
+ }
+
+ if (s1 == null || s2 == null)
+ {
+ return false;
+ }
+
+ return s1.equals(s2);
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObject.java b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObject.java
new file mode 100644
index 0000000..2199520
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObject.java
@@ -0,0 +1,61 @@
+package org.bouncycastle.util.io.pem;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class PemObject
+ implements PemObjectGenerator
+{
+ private static final List EMPTY_LIST = Collections.unmodifiableList(new ArrayList());
+
+ private String type;
+ private List headers;
+ private byte[] content;
+
+ /**
+ * Generic constructor for object without headers.
+ *
+ * @param type pem object type.
+ * @param content the binary content of the object.
+ */
+ public PemObject(String type, byte[] content)
+ {
+ this(type, EMPTY_LIST, content);
+ }
+
+ /**
+ * Generic constructor for object with headers.
+ *
+ * @param type pem object type.
+ * @param headers a list of PemHeader objects.
+ * @param content the binary content of the object.
+ */
+ public PemObject(String type, List headers, byte[] content)
+ {
+ this.type = type;
+ this.headers = Collections.unmodifiableList(headers);
+ this.content = content;
+ }
+
+ public String getType()
+ {
+ return type;
+ }
+
+ public List getHeaders()
+ {
+ return headers;
+ }
+
+ public byte[] getContent()
+ {
+ return content;
+ }
+
+ public PemObject generate()
+ throws PemGenerationException
+ {
+ return this;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java
new file mode 100644
index 0000000..6fffdc5
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectGenerator.java
@@ -0,0 +1,7 @@
+package org.bouncycastle.util.io.pem;
+
+public interface PemObjectGenerator
+{
+ PemObject generate()
+ throws PemGenerationException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java
new file mode 100644
index 0000000..b18b550
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemObjectParser.java
@@ -0,0 +1,9 @@
+package org.bouncycastle.util.io.pem;
+
+import java.io.IOException;
+
+public interface PemObjectParser
+{
+ Object parseObject(PemObject obj)
+ throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java
new file mode 100644
index 0000000..7664725
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemReader.java
@@ -0,0 +1,84 @@
+package org.bouncycastle.util.io.pem;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bouncycastle.util.encoders.Base64;
+
+public class PemReader
+ extends BufferedReader
+{
+ private static final String BEGIN = "-----BEGIN ";
+ private static final String END = "-----END ";
+
+ public PemReader(Reader reader)
+ {
+ super(reader);
+ }
+
+ public PemObject readPemObject()
+ throws IOException
+ {
+ String line = readLine();
+
+ while (line != null && !line.startsWith(BEGIN))
+ {
+ line = readLine();
+ }
+
+ if (line != null)
+ {
+ line = line.substring(BEGIN.length());
+ int index = line.indexOf('-');
+ String type = line.substring(0, index);
+
+ if (index > 0)
+ {
+ return loadObject(type);
+ }
+ }
+
+ return null;
+ }
+
+ private PemObject loadObject(String type)
+ throws IOException
+ {
+ String line;
+ String endMarker = END + type;
+ StringBuffer buf = new StringBuffer();
+ List headers = new ArrayList();
+
+ while ((line = readLine()) != null)
+ {
+ if (line.indexOf(":") >= 0)
+ {
+ int index = line.indexOf(':');
+ String hdr = line.substring(0, index);
+ String value = line.substring(index + 1).trim();
+
+ headers.add(new PemHeader(hdr, value));
+
+ continue;
+ }
+
+ if (line.indexOf(endMarker) != -1)
+ {
+ break;
+ }
+
+ buf.append(line.trim());
+ }
+
+ if (line == null)
+ {
+ throw new IOException(endMarker + " not found");
+ }
+
+ return new PemObject(type, headers, Base64.decode(buf.toString()));
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java
new file mode 100644
index 0000000..ccefa36
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/util/io/pem/PemWriter.java
@@ -0,0 +1,137 @@
+package org.bouncycastle.util.io.pem;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Iterator;
+
+import org.bouncycastle.util.encoders.Base64;
+
+/**
+ * A generic PEM writer, based on RFC 1421
+ */
+public class PemWriter
+ extends BufferedWriter
+{
+ private static final int LINE_LENGTH = 64;
+
+ private final int nlLength;
+ private char[] buf = new char[LINE_LENGTH];
+
+ /**
+ * Base constructor.
+ *
+ * @param out output stream to use.
+ */
+ public PemWriter(Writer out)
+ {
+ super(out);
+
+ String nl = System.getProperty("line.separator");
+ if (nl != null)
+ {
+ nlLength = nl.length();
+ }
+ else
+ {
+ nlLength = 2;
+ }
+ }
+
+ /**
+ * Return the number of bytes or characters required to contain the
+ * passed in object if it is PEM encoded.
+ *
+ * @param obj pem object to be output
+ * @return an estimate of the number of bytes
+ */
+ public int getOutputSize(PemObject obj)
+ {
+ // BEGIN and END boundaries.
+ int size = (2 * (obj.getType().length() + 10 + nlLength)) + 6 + 4;
+
+ if (!obj.getHeaders().isEmpty())
+ {
+ for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
+ {
+ PemHeader hdr = (PemHeader)it.next();
+
+ size += hdr.getName().length() + ": ".length() + hdr.getValue().length() + nlLength;
+ }
+
+ size += nlLength;
+ }
+
+ // base64 encoding
+ int dataLen = ((obj.getContent().length + 2) / 3) * 4;
+
+ size += dataLen + (((dataLen + LINE_LENGTH - 1) / LINE_LENGTH) * nlLength);
+
+ return size;
+ }
+
+ public void writeObject(PemObjectGenerator objGen)
+ throws IOException
+ {
+ PemObject obj = objGen.generate();
+
+ writePreEncapsulationBoundary(obj.getType());
+
+ if (!obj.getHeaders().isEmpty())
+ {
+ for (Iterator it = obj.getHeaders().iterator(); it.hasNext();)
+ {
+ PemHeader hdr = (PemHeader)it.next();
+
+ this.write(hdr.getName());
+ this.write(": ");
+ this.write(hdr.getValue());
+ this.newLine();
+ }
+
+ this.newLine();
+ }
+
+ writeEncoded(obj.getContent());
+ writePostEncapsulationBoundary(obj.getType());
+ }
+
+ private void writeEncoded(byte[] bytes)
+ throws IOException
+ {
+ bytes = Base64.encode(bytes);
+
+ for (int i = 0; i < bytes.length; i += buf.length)
+ {
+ int index = 0;
+
+ while (index != buf.length)
+ {
+ if ((i + index) >= bytes.length)
+ {
+ break;
+ }
+ buf[index] = (char)bytes[i + index];
+ index++;
+ }
+ this.write(buf, 0, index);
+ this.newLine();
+ }
+ }
+
+ private void writePreEncapsulationBoundary(
+ String type)
+ throws IOException
+ {
+ this.write("-----BEGIN " + type + "-----");
+ this.newLine();
+ }
+
+ private void writePostEncapsulationBoundary(
+ String type)
+ throws IOException
+ {
+ this.write("-----END " + type + "-----");
+ this.newLine();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java b/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
new file mode 100644
index 0000000..b00cd1d
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateHolder.java
@@ -0,0 +1,420 @@
+package org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.Holder;
+import org.bouncycastle.asn1.x509.IssuerSerial;
+import org.bouncycastle.asn1.x509.ObjectDigestInfo;
+import org.bouncycastle.jce.PrincipalUtil;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Selector;
+
+/**
+ * The Holder object.
+ *
+ * <pre>
+ * Holder ::= SEQUENCE {
+ * baseCertificateID [0] IssuerSerial OPTIONAL,
+ * -- the issuer and serial number of
+ * -- the holder's Public Key Certificate
+ * entityName [1] GeneralNames OPTIONAL,
+ * -- the name of the claimant or role
+ * objectDigestInfo [2] ObjectDigestInfo OPTIONAL
+ * -- used to directly authenticate the holder,
+ * -- for example, an executable
+ * }
+ * </pre>
+ * @deprecated use org.bouncycastle.cert.AttributeCertificateHolder
+ */
+public class AttributeCertificateHolder
+ implements CertSelector, Selector
+{
+ final Holder holder;
+
+ AttributeCertificateHolder(ASN1Sequence seq)
+ {
+ holder = Holder.getInstance(seq);
+ }
+
+ public AttributeCertificateHolder(X509Principal issuerName,
+ BigInteger serialNumber)
+ {
+ holder = new org.bouncycastle.asn1.x509.Holder(new IssuerSerial(
+ GeneralNames.getInstance(new DERSequence(new GeneralName(issuerName))),
+ new ASN1Integer(serialNumber)));
+ }
+
+ public AttributeCertificateHolder(X500Principal issuerName,
+ BigInteger serialNumber)
+ {
+ this(X509Util.convertPrincipal(issuerName), serialNumber);
+ }
+
+ public AttributeCertificateHolder(X509Certificate cert)
+ throws CertificateParsingException
+ {
+ X509Principal name;
+
+ try
+ {
+ name = PrincipalUtil.getIssuerX509Principal(cert);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+
+ holder = new Holder(new IssuerSerial(generateGeneralNames(name),
+ new ASN1Integer(cert.getSerialNumber())));
+ }
+
+ public AttributeCertificateHolder(X509Principal principal)
+ {
+ holder = new Holder(generateGeneralNames(principal));
+ }
+
+ public AttributeCertificateHolder(X500Principal principal)
+ {
+ this(X509Util.convertPrincipal(principal));
+ }
+
+ /**
+ * Constructs a holder for v2 attribute certificates with a hash value for
+ * some type of object.
+ * <p>
+ * <code>digestedObjectType</code> can be one of the following:
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ * <p>
+ * This cannot be used if a v1 attribute certificate is used.
+ *
+ * @param digestedObjectType The digest object type.
+ * @param digestAlgorithm The algorithm identifier for the hash.
+ * @param otherObjectTypeID The object type ID if
+ * <code>digestedObjectType</code> is
+ * <code>otherObjectDigest</code>.
+ * @param objectDigest The hash value.
+ */
+ public AttributeCertificateHolder(int digestedObjectType,
+ String digestAlgorithm, String otherObjectTypeID, byte[] objectDigest)
+ {
+ holder = new Holder(new ObjectDigestInfo(digestedObjectType,
+ new ASN1ObjectIdentifier(otherObjectTypeID), new AlgorithmIdentifier(digestAlgorithm), Arrays
+ .clone(objectDigest)));
+ }
+
+ /**
+ * Returns the digest object type if an object digest info is used.
+ * <p>
+ * <ul>
+ * <li>0 - publicKey - A hash of the public key of the holder must be
+ * passed.
+ * <li>1 - publicKeyCert - A hash of the public key certificate of the
+ * holder must be passed.
+ * <li>2 - otherObjectDigest - A hash of some other object type must be
+ * passed. <code>otherObjectTypeID</code> must not be empty.
+ * </ul>
+ *
+ * @return The digest object type or -1 if no object digest info is set.
+ */
+ public int getDigestedObjectType()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestedObjectType()
+ .getValue().intValue();
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the other object type ID if an object digest info is used.
+ *
+ * @return The other object type ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getDigestAlgorithm()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getDigestAlgorithm().getObjectId()
+ .getId();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the hash if an object digest info is used.
+ *
+ * @return The hash or <code>null</code> if no object digest info is set.
+ */
+ public byte[] getObjectDigest()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ return holder.getObjectDigestInfo().getObjectDigest().getBytes();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the digest algorithm ID if an object digest info is used.
+ *
+ * @return The digest algorithm ID or <code>null</code> if no object
+ * digest info is set.
+ */
+ public String getOtherObjectTypeID()
+ {
+ if (holder.getObjectDigestInfo() != null)
+ {
+ holder.getObjectDigestInfo().getOtherObjectTypeID().getId();
+ }
+ return null;
+ }
+
+ private GeneralNames generateGeneralNames(X509Principal principal)
+ {
+ return GeneralNames.getInstance(new DERSequence(new GeneralName(principal)));
+ }
+
+ private boolean matchesDN(X509Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X509Principal(((ASN1Encodable)gn.getName()).toASN1Primitive()
+ .getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private Object[] getNames(GeneralName[] names)
+ {
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X500Principal(
+ ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ private Principal[] getPrincipals(GeneralNames names)
+ {
+ Object[] p = this.getNames(names.getNames());
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate holder
+ * entity names field.
+ *
+ * @return an array of Principal objects (usually X500Principal), null if no
+ * entity names field is set.
+ */
+ public Principal[] getEntityNames()
+ {
+ if (holder.getEntityName() != null)
+ {
+ return getPrincipals(holder.getEntityName());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the principals associated with the issuer attached to this holder
+ *
+ * @return an array of principals, null if no BaseCertificateID is set.
+ */
+ public Principal[] getIssuer()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return getPrincipals(holder.getBaseCertificateID().getIssuer());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the serial number associated with the issuer attached to this
+ * holder.
+ *
+ * @return the certificate serial number, null if no BaseCertificateID is
+ * set.
+ */
+ public BigInteger getSerialNumber()
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue();
+ }
+
+ return null;
+ }
+
+ public Object clone()
+ {
+ return new AttributeCertificateHolder((ASN1Sequence)holder
+ .toASN1Object());
+ }
+
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ try
+ {
+ if (holder.getBaseCertificateID() != null)
+ {
+ return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer());
+ }
+
+ if (holder.getEntityName() != null)
+ {
+ if (matchesDN(PrincipalUtil.getSubjectX509Principal(x509Cert),
+ holder.getEntityName()))
+ {
+ return true;
+ }
+ }
+ if (holder.getObjectDigestInfo() != null)
+ {
+ MessageDigest md = null;
+ try
+ {
+ md = MessageDigest.getInstance(getDigestAlgorithm(), "BC");
+
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+ switch (getDigestedObjectType())
+ {
+ case ObjectDigestInfo.publicKey:
+ // TODO: DSA Dss-parms
+ md.update(cert.getPublicKey().getEncoded());
+ break;
+ case ObjectDigestInfo.publicKeyCert:
+ md.update(cert.getEncoded());
+ break;
+ }
+ if (!Arrays.areEqual(md.digest(), getObjectDigest()))
+ {
+ return false;
+ }
+ }
+ }
+ catch (CertificateEncodingException e)
+ {
+ return false;
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateHolder))
+ {
+ return false;
+ }
+
+ AttributeCertificateHolder other = (AttributeCertificateHolder)obj;
+
+ return this.holder.equals(other.holder);
+ }
+
+ public int hashCode()
+ {
+ return this.holder.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java b/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
new file mode 100644
index 0000000..3a34208
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/AttributeCertificateIssuer.java
@@ -0,0 +1,208 @@
+package org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.CertSelector;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AttCertIssuer;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.V2Form;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.util.Selector;
+
+/**
+ * Carrying class for an attribute certificate issuer.
+ * @deprecated use org.bouncycastle.cert.AttributeCertificateIssuer
+ */
+public class AttributeCertificateIssuer
+ implements CertSelector, Selector
+{
+ final ASN1Encodable form;
+
+ /**
+ * Set the issuer directly with the ASN.1 structure.
+ *
+ * @param issuer The issuer
+ */
+ public AttributeCertificateIssuer(AttCertIssuer issuer)
+ {
+ form = issuer.getIssuer();
+ }
+
+ public AttributeCertificateIssuer(X500Principal principal)
+ throws IOException
+ {
+ this(new X509Principal(principal.getEncoded()));
+ }
+
+ public AttributeCertificateIssuer(X509Principal principal)
+ {
+ form = new V2Form(GeneralNames.getInstance(new DERSequence(new GeneralName(principal))));
+ }
+
+ private Object[] getNames()
+ {
+ GeneralNames name;
+
+ if (form instanceof V2Form)
+ {
+ name = ((V2Form)form).getIssuerName();
+ }
+ else
+ {
+ name = (GeneralNames)form;
+ }
+
+ GeneralName[] names = name.getNames();
+
+ List l = new ArrayList(names.length);
+
+ for (int i = 0; i != names.length; i++)
+ {
+ if (names[i].getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ l.add(new X500Principal(
+ ((ASN1Encodable)names[i].getName()).toASN1Primitive().getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("badly formed Name object");
+ }
+ }
+ }
+
+ return l.toArray(new Object[l.size()]);
+ }
+
+ /**
+ * Return any principal objects inside the attribute certificate issuer
+ * object.
+ *
+ * @return an array of Principal objects (usually X500Principal)
+ */
+ public Principal[] getPrincipals()
+ {
+ Object[] p = this.getNames();
+ List l = new ArrayList();
+
+ for (int i = 0; i != p.length; i++)
+ {
+ if (p[i] instanceof Principal)
+ {
+ l.add(p[i]);
+ }
+ }
+
+ return (Principal[])l.toArray(new Principal[l.size()]);
+ }
+
+ private boolean matchesDN(X500Principal subject, GeneralNames targets)
+ {
+ GeneralName[] names = targets.getNames();
+
+ for (int i = 0; i != names.length; i++)
+ {
+ GeneralName gn = names[i];
+
+ if (gn.getTagNo() == GeneralName.directoryName)
+ {
+ try
+ {
+ if (new X500Principal(((ASN1Encodable)gn.getName()).toASN1Primitive().getEncoded()).equals(subject))
+ {
+ return true;
+ }
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public Object clone()
+ {
+ return new AttributeCertificateIssuer(AttCertIssuer.getInstance(form));
+ }
+
+ public boolean match(Certificate cert)
+ {
+ if (!(cert instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate x509Cert = (X509Certificate)cert;
+
+ if (form instanceof V2Form)
+ {
+ V2Form issuer = (V2Form)form;
+ if (issuer.getBaseCertificateID() != null)
+ {
+ return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber())
+ && matchesDN(x509Cert.getIssuerX500Principal(), issuer.getBaseCertificateID().getIssuer());
+ }
+
+ GeneralNames name = issuer.getIssuerName();
+ if (matchesDN(x509Cert.getSubjectX500Principal(), name))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ GeneralNames name = (GeneralNames)form;
+ if (matchesDN(x509Cert.getSubjectX500Principal(), name))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AttributeCertificateIssuer))
+ {
+ return false;
+ }
+
+ AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
+
+ return this.form.equals(other.form);
+ }
+
+ public int hashCode()
+ {
+ return this.form.hashCode();
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ return match((Certificate)obj);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages.properties b/bcprov/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages.properties
new file mode 100644
index 0000000..6843d2c
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/CertPathReviewerMessages.properties
@@ -0,0 +1,616 @@
+
+## constructor exceptions
+
+# cert path is empty
+CertPathReviewer.emptyCertPath.title = CertPath is empty
+CertPathReviewer.emptyCertPath.text = PKIXCertPathReviewer: the CertPath is empty.
+CertPathReviewer.emptyCertPath.summary = PKIXCertPathReviewer: the CertPath is empty.
+CertPathReviewer.emptyCertPath.details = PKIXCertPathReviewer: the CertPath is empty.
+
+## name constraints processing errors
+
+# cert DN is not in the permitted tree
+# {0} DN as String
+CertPathReviewer.notPermittedDN.title = Name constraint error: certificate DN is not permitted
+CertPathReviewer.notPermittedDN.text = Name constraint error: the certificate DN {0} is not permitted.
+CertPathReviewer.notPermittedDN.summary = Name constraint error: certificate DN is not permitted.
+CertPathReviewer.notPermittedDN.details = Name constraint checking error. The certificate DN {0} is not in the permitted set of DNs.
+
+# cert DN is in the excluded tree
+# {0} DN as String
+CertPathReviewer.excludedDN.title = Name constraint error: certificate DN is excluded
+CertPathReviewer.excludedDN.text = Name constraint error: The certificate DN {0} is excluded.
+CertPathReviewer.excludedDN.summary = Name constraint error: certificate DN is excluded.
+CertPathReviewer.excludedDN.details = Name constraint checking error. The certificate DN {0} is inside of the excluded set of DNs.
+
+# cert email is not in the permitted tree
+# {0} email address as String
+CertPathReviewer.notPermittedEmail.title = Name constraint error: not permitted email address
+CertPathReviewer.notPermittedEmail.text = Name constraint error: certificate contains the not permitted email address {0}.
+CertPathReviewer.notPermittedEmail.summary = Name constraint error: not permitted email address.
+CertPathReviewer.notPermittedEmail.details = Name constraint checking error. The certificate contains the email address {0} which is not in the permitted set of email addresses.
+
+# cert email is in the excluded tree
+# {0} email as String
+CertPathReviewer.excludedEmail.title = Name constraint error: excluded email address
+CertPathReviewer.excludedEmail.text = Name constraint error: certificate contains the excluded email address {0}.
+CertPathReviewer.excludedEmail.summary = Name constraint error: excluded email address.
+CertPathReviewer.excludedEmail.details = Name constraint checking error. The certificate contains the email address {0} which is in the excluded set of email addresses.
+
+# cert IP is not in the permitted tree
+# {0} ip address as String
+CertPathReviewer.notPermittedIP.title = Name constraint error: not permitted IP address
+CertPathReviewer.notPermittedIP.text = Name constraint error: certificate contains the not permitted IP address {0}.
+CertPathReviewer.notPermittedIP.summary = Name constraint error: not permitted IP address.
+CertPathReviewer.notPermittedIP.details = Name constraint checking error. The certificate contains the IP address {0} which is not in the permitted set of IP addresses.
+
+# cert ip is in the excluded tree
+# {0} ip address as String
+CertPathReviewer.excludedIP.title = Name constraint error: excluded IP address
+CertPathReviewer.excludedIP.text = Name constraint error: certificate contains the excluded IP address {0}.
+CertPathReviewer.excludedIP.summary = Name constraint error: excluded IP address.
+CertPathReviewer.excludedIP.details = Name constraint checking error. The certificate contains the IP address {0} which is in the excluded set of IP addresses.
+
+# error processing the name constraints extension
+CertPathReviewer.ncExtError.title = Name constraint checking failed
+CertPathReviewer.ncExtError.text = Name constraint checking failed: there was an error processing the name constraints extension of the certificate.
+CertPathReviewer.ncExtError.summary = Error processing the name constraints extension.
+CertPathReviewer.ncExtError.details = Name constraint checking failed: there was an error processing the name constraints extension of the certificate.
+
+# error processing the subject alternative name extension
+CertPathReviewer.subjAltNameExtError.title = Name constraint checking failed
+CertPathReviewer.subjAltNameExtError.text = Name constraint checking failed: there was an error processing the subject alternative name extension of the certificate.
+CertPathReviewer.subjAltNameExtError.summary = Error processing the subject alternative name extension.
+CertPathReviewer.subjAltNameExtError.details = Name constraint checking failed: there was an error processing the subject alternative name extension of the certificate.
+
+# exception extracting subject name when checking subtrees
+# {0} subject Principal
+CertPathReviewer.ncSubjectNameError.title = Name constraint checking failed
+CertPathReviewer.ncSubjectNameError.text = Name constraint checking failed: there was an exception extracting the DN from the certificate.
+CertPathReviewer.ncSubjectNameError.summary = Name constraint checking failed: exception extracting the DN.
+CertPathReviewer.ncSubjectNameError.details = Name constraint checking failed: there was an exception extracting the DN from the certificate.
+
+
+## path length errors
+
+# max path length extended
+CertPathReviewer.pathLenghtExtended.title = Maximum path length extended
+CertPathReviewer.pathLenghtExtended.text = Certificate path invalid: Maximum path length extended.
+CertPathReviewer.pathLenghtExtended.summary = Certificate path invalid: Maximum path length extended.
+CertPathReviewer.pathLenghtExtended.details = Certificate path invalid: Maximum path length extended.
+
+# error reading length constraint from basic constraint extension
+CertPathReviewer.processLengthConstError.title = Path length checking failed
+CertPathReviewer.processLengthConstError.text = Path length checking failed: there was an error processing the basic constraint extension of the certificate.
+CertPathReviewer.processLengthConstError.summary = Error processing the subject alternative name extension.
+CertPathReviewer.processLengthConstError.details = Path length checking failed: there was an error processing the basic constraint extension of the certificate.
+
+
+## path length notifications
+
+# total path length as defined in rfc 3280
+# {0} the path length as Integer
+CertPathReviewer.totalPathLength.title = Total path length
+CertPathReviewer.totalPathLength.text = The total path length without self-signed certificates is {0}.
+CertPathReviewer.totalPathLength.summary = The total path length without self-signed certificates is {0}.
+CertPathReviewer.totalPathLength.details = The total path length without self-signed certificates, as defined in RFC 3280, is {0}.
+
+
+## critical extensions errors
+
+# one unknown critical extension
+# {0} extension as String
+CertPathReviewer.unknownCriticalExt.title = Unknown critical extension
+CertPathReviewer.unknownCriticalExt.text = The certificate contains the unknown critical extension {0}.
+CertPathReviewer.unknownCriticalExt.summary = Unknown critical extension: {0}.
+CertPathReviewer.unknownCriticalExt.details = The certificate contains the unknown critical extension with the OID {0}.
+
+# more unknown critical extensions
+# {0} extensions as Set of Strings
+CertPathReviewer.unknownCriticalExts.title = Unknown critical extensions
+CertPathReviewer.unknownCriticalExts.text = The certificate contains two or more unknown critical extensions: {0}.
+CertPathReviewer.unknownCriticalExts.summary = Unknown critical extensions: {0}.
+CertPathReviewer.unknownCriticalExts.details = The certificate contains two or more unknown critical extensions with the OIDs: {0}.
+
+# error processing critical extension
+# {0} the message of the underlying exception
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.criticalExtensionError.title = Error processing a critical extension
+CertPathReviewer.criticalExtensionError.text = Error processing a critical extension. A {0} occurred.
+CertPathReviewer.criticalExtensionError.summary = Error processing a critical extension. A {0} occurred.
+CertPathReviewer.criticalExtensionError.details = Error processing a critical extension. A {0} occurred. Cause: {0}.
+
+# error initializing the certpath checkers
+# {0} the message of the underlying exception
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.certPathCheckerError.title = Checking critical extensions failed
+CertPathReviewer.certPathCheckerError.text = Checking critical extensions failed: there was a {2} initializing a CertPathChecker.
+CertPathReviewer.certPathCheckerError.summary = Checking critical extensions failed: {2} initializing a CertPathChecker
+CertPathReviewer.certPathCheckerError.details = Checking critical extensions failed: there was an {2} initializing a CertPathChecker. Cause: {0}
+
+
+## check signature errors
+
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.title = Root key with valid signature but no trust anchor
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.text = The certificate has a valid signature, but is no trust anchor
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.summary = The certificate has a valid signature, but is no trust anchor
+CertPathReviewer.rootKeyIsValidButNotATrustAnchor.details = The certificate has a valid signature, but is no trust anchor
+
+# trustanchor found, but certificate validation failed
+CertPathReviewer.trustButInvalidCert.title = Trust anchor found, but different public key
+CertPathReviewer.trustButInvalidCert.text = A trust anchor was found. But it has a different public key, than was used to issue the first certificate of the cert path.
+CertPathReviewer.trustButInvalidCert.summary = A trust anchor was found. But it has a different public key, than was used to issue the first certificate of the cert path.
+CertPathReviewer.trustButInvalidCert.details = A trust anchor was found. But it has a different public key, than was used to issue the first certificate of the cert path.
+
+# trustanchor - cannot extract issuer
+CertPathReviewer.trustAnchorIssuerError.title = Finding trust anchor failed
+CertPathReviewer.trustAnchorIssuerError.text = Finding trust anchor failed: cannot extract issuer from certificate.
+CertPathReviewer.trustAnchorIssuerError.summary = Finding trust anchor failed: cannot extract issuer from certificate.
+CertPathReviewer.trustAnchorIssuerError.details = Finding trust anchor failed: cannot extract issuer from certificate.
+
+# no trustanchor was found for the certificate path
+# {0} issuer of the root certificate of the path
+# {1} number of trusted root certificates (trustanchors) provided
+CertPathReviewer.noTrustAnchorFound.title = No trusted root certificate found
+CertPathReviewer.noTrustAnchorFound.text = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation. The name of the CA is "{0}".
+CertPathReviewer.noTrustAnchorFound.summary = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation.
+CertPathReviewer.noTrustAnchorFound.details = The root certificate of the certificate path was issued by a CA that is not in the the trusted-root-certificate-store used for the path validation. The name of the CA is "{0}". The trusted-root-certificate store contains {1} CA(s).
+
+# conflicting trust anchors
+# {0} number of trustanchors found (Integer)
+# {1} the ca name
+CertPathReviewer.conflictingTrustAnchors.title = Corrupt trust root store
+CertPathReviewer.conflictingTrustAnchors.text = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+CertPathReviewer.conflictingTrustAnchors.summary = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+CertPathReviewer.conflictingTrustAnchors.details = Warning: corrupt trust root store: There are {0} trusted public keys for the CA "{1}" - please ensure with CA which is the correct key.
+
+# trustanchor DN is invalid
+# {0} DN of the Trustanchor
+CertPathReviewer.trustDNInvalid.title = DN of TrustAnchor is improperly specified
+CertPathReviewer.trustDNInvalid.text = The DN of the TrustAnchor is improperly specified: {0}.
+CertPathReviewer.trustDNInvalid.summary = The DN of the TrustAnchor is improperly specified.
+CertPathReviewer.trustDNInvalid.details = The DN of the TrustAnchor is improperly specified: {0}. It's not a valid X.500 name. See RFC 1779 or RFC 2253.
+
+# trustanchor public key algorithm error
+CertPathReviewer.trustPubKeyError.title = Error processing public key of the trust anchor
+CertPathReviewer.trustPubKeyError.text = Error processing public key of the trust anchor.
+CertPathReviewer.trustPubKeyError.summary = Error processing public key of the trust anchor.
+CertPathReviewer.trustPubKeyError.details = Error processing public key of the trust anchor. Could not extract the AlorithmIdentifier for the key.
+
+# can not verifiy signature: issuer public key unknown
+CertPathReviewer.NoIssuerPublicKey.title = Can not verify the certificate signature
+CertPathReviewer.NoIssuerPublicKey.text = Can not verify the certificate signature: Issuer public key is unknown.
+CertPathReviewer.NoIssuerPublicKey.summary = Can not verify the certificate signature: Issuer public key is unknown.
+CertPathReviewer.NoIssuerPublicKey.details = Can not verify the certificate signature: Issuer public key is unknown.
+
+# signature can not be verified
+# {0} message of the underlying exception (english)
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.signatureNotVerified.title = Certificate signature invalid
+CertPathReviewer.signatureNotVerified.text = The certificate signature is invalid. A {2} occurred.
+CertPathReviewer.signatureNotVerified.summary = The certificate signature is invalid.
+CertPathReviewer.signatureNotVerified.details = The certificate signature is invalid. A {2} occurred. Cause: {0}
+
+# certificate expired
+# {0} the date the certificate expired
+CertPathReviewer.certificateExpired.title = Certificate is expired
+CertPathReviewer.certificateExpired.text = Could not validate the certificate. Certificate expired on {0,date} {0,time,full}.
+CertPathReviewer.certificateExpired.summary = Certificate expired on {0,date} {0,time,full}.
+CertPathReviewer.certificateExpired.details = Could not validate the certificate. Certificate expired on {0,date} {0,time,full}.
+
+# certificate not yet valid
+# {0} the date from which on the certificate is valid
+CertPathReviewer.certificateNotYetValid.title = Certificate is not yet valid
+CertPathReviewer.certificateNotYetValid.text = Could not validate the certificate. Certificate is not valid until {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.summary = Certificate is not valid until {0,date} {0,time,full}.
+CertPathReviewer.certificateNotYetValid.details = Could not validate the certificate. Certificate is not valid until {0,date} {0,time,full}.
+
+# certificate invalid issuer DN
+# {0} expected issuer DN as String
+# {1} found issuer DN as String
+CertPathReviewer.certWrongIssuer.title = Issuer of certificate not valid
+CertPathReviewer.certWrongIssuer.text = Issuer of certificate is not valid. Expected {0}, but found {1}.
+CertPathReviewer.certWrongIssuer.summary = Issuer of certificate is not valid.
+CertPathReviewer.certWrongIssuer.details = Issuer of certificate is not valid. Expected {0}, but found {1}.
+
+# intermediate certificate is no ca cert
+CertPathReviewer.noCACert.title = Certificate is no CA certificate
+CertPathReviewer.noCACert.text = Intermediate certificate is no CA certificate.
+CertPathReviewer.noCACert.summary = The certificate is no CA certificate.
+CertPathReviewer.noCACert.details = The certificate is no CA certificate but used as one.
+
+# cert laks basic constraints
+CertPathReviewer.noBasicConstraints.title = Certificate has no basic constraints
+CertPathReviewer.noBasicConstraints.text = Intermediate certificate has no basic constraints.
+CertPathReviewer.noBasicConstraints.summary = Intermediate certificate has no basic constraints.
+CertPathReviewer.noBasicConstraints.details = Intermediate certificate has no basic constraints.
+
+# error processing basic constraints
+CertPathReviewer.errorProcesingBC.title = Error processing the basic constraints extension
+CertPathReviewer.errorProcesingBC.text = There was an error while processing the basic constraints extension of this certificate.
+CertPathReviewer.errorProcesingBC.summary = Error processing the basic constraints extension.
+CertPathReviewer.errorProcesingBC.details = There was an error while processing the basic constraints extension of this certificate.
+
+# certificate not usable for signing certs
+CertPathReviewer.noCertSign.title = Key not usable for signing certificates
+CertPathReviewer.noCertSign.text = The key usage constraint does not allow the use of this certificate key for signing certificates.
+CertPathReviewer.noCertSign.summary = The certificate key can not be used for signing certificates.
+CertPathReviewer.noCertSign.details = The key usage constraint does not allow the use of this certificate key for signing certificates.
+
+# error processing public key
+CertPathReviewer.pubKeyError.title = Error processing public key
+CertPathReviewer.pubKeyError.text = Error processing public key of the certificate.
+CertPathReviewer.pubKeyError.summary = Error processing public key of the certificate.
+CertPathReviewer.pubKeyError.details = Error processing public key of the certificate. Could not extract the AlorithmIdentifier for the key.
+
+
+## check signatures notifications
+
+#
+# trust anchor has no keyusage certSign
+CertPathReviewer.trustKeyUsage.title = Trust anchor key usage
+CertPathReviewer.trustKeyUsage.text = The trust anchor is not alloed to sign certificates.
+CertPathReviewer.trustKeyUsage.summary = The trust anchor is not alloed to sign certificates.
+CertPathReviewer.trustKeyUsage.details = The trust anchor is not alloed to sign certificates.
+
+# certificate path validation date
+# {0} date for which the cert path is validated
+# {1} current date
+CertPathReviewer.certPathValidDate.title = Certificate path validation date
+CertPathReviewer.certPathValidDate.text = The certificate path was applied on {0,date} {0,time,full}. It was checked at {1,date} {1,time,full}.
+CertPathReviewer.certPathValidDate.summary = The certificate path was validated for {0,date} {0,time,full}. It was checked at {1,date} {1,time,full}.
+CertPathReviewer.certPathValidDate.details = The certificate path was validated for {0,date} {0,time,full}. It was checked at {1,date} {1,time,full}.
+
+
+## check policy errors
+
+# error processing certificate policy extension
+CertPathReviewer.policyExtError.title = Policy checking failed
+CertPathReviewer.policyExtError.text = Policy checking failed: there was an error processing the certificate policy extension.
+CertPathReviewer.policyExtError.summary = Error processing the certificate policy extension.
+CertPathReviewer.policyExtError.details = Policy checking failed: there was an error processing the certificate policy extension.
+
+# error processing policy constraints extension
+CertPathReviewer.policyConstExtError.title = Policy checking failed
+CertPathReviewer.policyConstExtError.text = Policy checking failed: there was an error processing the policy constraints extension.
+CertPathReviewer.policyConstExtError.summary = Error processing the policy constraints extension.
+CertPathReviewer.policyConstExtError.details = Policy checking failed: there was an error processing the policy constraints extension.
+
+# error processing policy mapping extension
+CertPathReviewer.policyMapExtError.title = Policy checking failed
+CertPathReviewer.policyMapExtError.text = Policy checking failed: there was an error processing the policy mapping extension.
+CertPathReviewer.policyMapExtError.summary = Error processing the policy mapping extension.
+CertPathReviewer.policyMapExtError.details = Policy checking failed: there was an error processing the policy mapping extension.
+
+# error processing inhibit any policy extension
+CertPathReviewer.policyInhibitExtError.title = Policy checking failed
+CertPathReviewer.policyInhibitExtError.text = Policy checking failed: there was an error processing the inhibit any policy extension.
+CertPathReviewer.policyInhibitExtError.summary = Error processing the inhibit any policy extension.
+CertPathReviewer.policyInhibitExtError.details = Policy checking failed: there was an error processing the inhibit any policy extension.
+
+# error building qualifier set
+CertPathReviewer.policyQualifierError.title = Policy checking failed
+CertPathReviewer.policyQualifierError.text = Policy checking failed: error building the policy qualifier set.
+CertPathReviewer.policyQualifierError.summary = Policy checking failed: error building the policy qualifier set.
+CertPathReviewer.policyQualifierError.details = Policy checking failed: error building the policy qualifier set.
+
+# no valid policy tree - explicit policy required
+CertPathReviewer.noValidPolicyTree.title = Policy checking failed
+CertPathReviewer.noValidPolicyTree.text = Policy checking failed: no valid policy tree found when one expected.
+CertPathReviewer.noValidPolicyTree.summary = Policy checking failed: no valid policy tree found when one expected.
+CertPathReviewer.noValidPolicyTree.details = Policy checking failed: no valid policy tree found when one expected.
+
+# expicit policy requested, but no policy available
+CertPathReviewer.explicitPolicy.title = Policy checking failed
+CertPathReviewer.explicitPolicy.text = Policy checking failed: explicit policy requested but no policy available.
+CertPathReviewer.explicitPolicy.summary = Policy checking failed: explicit policy requested but no policy available.
+CertPathReviewer.explicitPolicy.details = Policy checking failed: explicit policy requested but no policy available.
+
+# path processing failed on policy
+CertPathReviewer.invalidPolicy.title = Path processing failed on policy
+CertPathReviewer.invalidPolicy.text = Path processing failed on policy.
+CertPathReviewer.invalidPolicy.summary = Path processing failed on policy.
+CertPathReviewer.invalidPolicy.details = Path processing failed on policy.
+
+# invalid policy mapping
+CertPathReviewer.invalidPolicyMapping.title = Invalid policy mapping
+CertPathReviewer.invalidPolicyMapping.text = Certificate contains an invalid policy mapping.
+CertPathReviewer.invalidPolicyMapping.summary = Certificate contains an invalid policy mapping.
+CertPathReviewer.invalidPolicyMapping.details = Certificate contains a policy mapping including the value any policy which is invalid.
+
+## check CRL notifications
+
+# found local valid CRL
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localValidCRL.title = Found valid local CRL
+CertPathReviewer.localValidCRL.text = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localValidCRL.summary = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localValidCRL.details = Found a valid CRL in local certstore. Issued on {0,date}, next update {1,date}.
+
+
+# found matching CRL, but not valid
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+CertPathReviewer.localInvalidCRL.title = Local CRL outdated
+CertPathReviewer.localInvalidCRL.text = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localInvalidCRL.summary = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+CertPathReviewer.localInvalidCRL.details = Did not use a matching CRL in a local certstore, because it is outdated. Issued on {0,date}, next update {1,date}.
+
+# found a valid crl at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineValidCRL.title = Found valid CRL at CRL distribution point
+CertPathReviewer.onlineValidCRL.text = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineValidCRL.summary = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineValidCRL.details = Found a valid CRL at: {2}. Issued on {0,date}, next update on {1,date}.
+
+# found an invalid CRL at crl distribution point
+# {0} thisUpdate of the CRL
+# {1} nextUpdate of the CRL
+# {2} the url of the distribution point
+CertPathReviewer.onlineInvalidCRL.title = Outdated CRL at CRL distribution point
+CertPathReviewer.onlineInvalidCRL.text = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineInvalidCRL.summary = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+CertPathReviewer.onlineInvalidCRL.details = The CRL loaded from {2} was outdated. Issued on {0,date}, next update on {1,date}.
+
+#found a CRL at a crl distribution point, but issued by another CA
+# {0} issuer of the CRL
+# {1} expected issuer
+# {2} the url of the distribution point
+CertPathReviewer.onlineCRLWrongCA.title = CRL from wrong issuer at CRL distribution point
+CertPathReviewer.onlineCRLWrongCA.text = The CRL loaded from {2} has was issued by {0}, excpected {1}.
+CertPathReviewer.onlineCRLWrongCA.summary = The CRL loaded from {2} has a wrong issuer.
+CertPathReviewer.onlineCRLWrongCA.details = The CRL loaded from {2} has was issued by {0}, excpected {1}.
+
+# Certificate not revoked
+CertPathReviewer.notRevoked.title = Certificate not revoked
+CertPathReviewer.notRevoked.text = The certificate was not revoked.
+CertPathReviewer.notRevoked.summary = The certificate was not revoked.
+CertPathReviewer.notRevoked.details = The certificate was not revoked.
+
+# CRL found: certificate was revoked, but after the validationDate
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.revokedAfterValidation.title = Certificate was revoked after the validation date
+CertPathReviewer.revokedAfterValidation.text = The certificate was revoked after the validation date at {0,date} {0,time,full}. Reason: {1}.
+CertPathReviewer.revokedAfterValidation.summary = The certificate was revoked after the validation date at {0,date} {0,time,full}.
+CertPathReviewer.revokedAfterValidation.details = The certificate was revoked after the validation date at {0,date} {0,time,full}. Reason: {1}.
+
+# updated crl available
+# {0} date since when the update is available
+CertPathReviewer.crlUpdateAvailable.title = CRL update available
+CertPathReviewer.crlUpdateAvailable.text = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.summary = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+CertPathReviewer.crlUpdateAvailable.details = An update for the CRL of this certificate is available since {0,date} {0,time,full}.
+
+# crl distribution point url
+# {0} the crl distribution point url as String
+CertPathReviewer.crlDistPoint.title = CRL distribution point
+CertPathReviewer.crlDistPoint.text = A CRL can be obtained from: {0}.
+CertPathReviewer.crlDistPoint.summary = A CRL can be obtained from: {0}.
+CertPathReviewer.crlDistPoint.details = A CRL can be obtained from: {0}.
+
+# ocsp location
+# {0} the url on which the ocsp service can be found
+CertPathReviewer.ocspLocation.title = OCSP responder location
+CertPathReviewer.ocspLocation.text = OCSP responder location: {0}.
+CertPathReviewer.ocspLocation.summary = OCSP responder location: {0}.
+CertPathReviewer.ocspLocation.details = OCSP responder location: {0}.
+
+# unable to get crl from crl distribution point
+# {0} the url of the distribution point
+# {1} the message of the occurred exception
+# {2} the occurred exception
+# {3} the name of the exception
+CertPathReviewer.loadCrlDistPointError.title = Cannot load CRL from CRL distribution point
+CertPathReviewer.loadCrlDistPointError.text = Unable to load a CRL from: {0}. A {3} occurred.
+CertPathReviewer.loadCrlDistPointError.summary = Unable to load a CRL from: {0}. A {3} occurred.
+CertPathReviewer.loadCrlDistPointError.details = Unable to load a CRL from: {0}. A {3} occurred. Cause: {1}.
+
+# no crl found in certstores
+# {0} the issuers which we searched for
+# {1} list of crl issuer names that are found in the certstores
+# {2} number of crls in the certstores
+CertPathReviewer.noCrlInCertstore.title = No matching CRL found in local CRL store
+CertPathReviewer.noCrlInCertstore.text = No matching CRL was found in the provided local CRL store.
+CertPathReviewer.noCrlInCertstore.summary = No matching CRL was found in the provided local CRL store.
+CertPathReviewer.noCrlInCertstore.details = No matching CRL was found in the provided local CRL store. \
+No CRL was found for the selector "{0}". The {2} CRL(s) in the certstores are from "{1}".
+
+
+## check CRL exceptions
+
+# cannot extract issuer from certificate
+CertPathReviewer.crlIssuerException.title = CRL checking failed
+CertPathReviewer.crlIssuerException.text = CRL checking failed: cannot extract issuer from certificate.
+CertPathReviewer.crlIssuerException.summary = CRL checking failed: cannot extract issuer from certificate.
+CertPathReviewer.crlIssuerException.details = CRL checking failed: cannot extract issuer from certificate.
+
+# cannot extract crls
+# {0} message from the underlying exception
+# {1} the underlying exception
+# {2} the name of the exception
+CertPathReviewer.crlExtractionError.title = CRL checking failed
+CertPathReviewer.crlExtractionError.text = CRL checking failed: Cannot extract CRL from CertStore. There was a {2}.
+CertPathReviewer.crlExtractionError.summary = CRL checking failed: Cannot extract CRL from CertStore. There was a {2}.
+CertPathReviewer.crlExtractionError.details = CRL checking failed: Cannot extract CRL from CertStore. There was a {2}. Cause: {0}.
+
+# Issuer certificate key usage extension does not permit crl signing
+CertPathReviewer.noCrlSigningPermited.title = CRL checking failed
+CertPathReviewer.noCrlSigningPermited.text = CRL checking failed: issuer certificate does not permit CRL signing.
+CertPathReviewer.noCrlSigningPermited.summary = CRL checking failed: issuer certificate does not permit CRL signing.
+CertPathReviewer.noCrlSigningPermited.details = CRL checking failed: issuer certificate does not permit CRL signing.
+
+# can not verify crl: issuer public key unknown
+CertPathReviewer.crlNoIssuerPublicKey.title = CRL checking failed
+CertPathReviewer.crlNoIssuerPublicKey.text = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+CertPathReviewer.crlNoIssuerPublicKey.summary = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+CertPathReviewer.crlNoIssuerPublicKey.details = CRL checking failed: Can not verify the CRL: Issuer public key is unknown.
+
+# crl verification failed
+CertPathReviewer.crlVerifyFailed.title = CRL checking failed
+CertPathReviewer.crlVerifyFailed.text = CRL checking failed: CRL signature is invalid.
+CertPathReviewer.crlVerifyFailed.summary = CRL checking failed: CRL signature is invalid.
+CertPathReviewer.crlVerifyFailed.details = CRL checking failed: CRL signature is invalid.
+
+# no valid CRL found
+CertPathReviewer.noValidCrlFound.title = CRL checking failed
+CertPathReviewer.noValidCrlFound.text = CRL checking failed: no valid CRL found.
+CertPathReviewer.noValidCrlFound.summary = CRL checking failed: no valid CRL found.
+CertPathReviewer.noValidCrlFound.details = CRL checking failed: no valid CRL found.
+
+# No base CRL for delta CRL
+CertPathReviewer.noBaseCRL.title = CRL checking failed
+CertPathReviewer.noBaseCRL.text = CRL checking failed: no base CRL found for delta CRL.
+CertPathReviewer.noBaseCRL.summary = CRL checking failed: no base CRL found for delta CRL.
+CertPathReviewer.noBaseCRL.details = CRL checking failed: no base CRL found for delta CRL.
+
+# certificate revoked
+# {0} the date the certificate was revoked
+# {1} the reason for revoking the certificate
+CertPathReviewer.certRevoked.title = Certificate was revoked
+CertPathReviewer.certRevoked.text = The certificate was revoked at {0,date} {0,time,full}. Reason: {1}.
+CertPathReviewer.certRevoked.summary = The certificate was revoked at {0,date} {0,time,full}.
+CertPathReviewer.certRevoked.details = The certificate was revoked at {0,date} {0,time,full}. Reason: {1}.
+
+# error processing issuing distribution point extension
+CertPathReviewer.distrPtExtError.title = CRL checking failed
+CertPathReviewer.distrPtExtError.text = CRL checking failed: there was an error processing the issuing distribution point extension.
+CertPathReviewer.distrPtExtError.summary = Error processing the issuing distribution point extension.
+CertPathReviewer.distrPtExtError.details = CRL checking failed: there was an error processing the issuing distribution point extension.
+
+# error processing crl distribution points extension
+CertPathReviewer.crlDistPtExtError.title = CRL checking failed
+CertPathReviewer.crlDistPtExtError.text = CRL checking failed: there was an error processing the crl distribution points extension.
+CertPathReviewer.crlDistPtExtError.summary = Error processing the crl distribution points extension.
+CertPathReviewer.crlDistPtExtError.details = CRL checking failed: there was an error processing the crl distribution points extension.
+
+# error processing the authority info access extension
+CertPathReviewer.crlAuthInfoAccError.title = CRL checking failed
+CertPathReviewer.crlAuthInfoAccError.text = CRL checking failed: there was an error processing the authority info access extension.
+CertPathReviewer.crlAuthInfoAccError.summary = Error processing the authority info access extension.
+CertPathReviewer.crlAuthInfoAccError.details = CRL checking failed: there was an error processing the authority info access extension.
+
+# error processing delta crl indicator extension
+CertPathReviewer.deltaCrlExtError.title = CRL checking failed
+CertPathReviewer.deltaCrlExtError.text = CRL checking failed: there was an error processing the delta CRL indicator extension.
+CertPathReviewer.deltaCrlExtError.summary = Error processing the delta CRL indicator extension.
+CertPathReviewer.deltaCrlExtError.details = CRL checking failed: there was an error processing the delta CRL indicator extension.
+
+# error porcessing crl number extension
+CertPathReviewer.crlNbrExtError.title = CRL checking failed
+CertPathReviewer.crlNbrExtError.text = CRL checking failed: there was an error processing the CRL number extension.
+CertPathReviewer.crlNbrExtError.summary = Error processing the CRL number extension.
+CertPathReviewer.crlNbrExtError.details = CRL checking failed: there was an error processing the CRL number extension.
+
+# error processing crl reason code extension
+CertPathReviewer.crlReasonExtError.title = CRL checking failed
+CertPathReviewer.crlReasonExtError.text = CRL checking failed: there was an error processing the CRL reason code extension.
+CertPathReviewer.crlReasonExtError.summary = Error processing the CRL reason code extension.
+CertPathReviewer.crlReasonExtError.details = CRL checking failed: there was an error processing the CRL reason code extension.
+
+# error processing basic constraints extension
+CertPathReviewer.crlBCExtError.title = CRL checking failed
+CertPathReviewer.crlBCExtError.text = CRL checking failed: there was an error processing the basic constraints extension.
+CertPathReviewer.crlBCExtError.summary = Error processing the basic constraints extension.
+CertPathReviewer.crlBCExtError.details = CRL checking failed: there was an error processing the basic constraints extension.
+
+# CA Cert CRL only contains user certificates
+CertPathReviewer.crlOnlyUserCert.title = CRL checking failed
+CertPathReviewer.crlOnlyUserCert.text = CRL checking failed: CRL only contains user certificates.
+CertPathReviewer.crlOnlyUserCert.summary = CRL checking failed: CRL only contains user certificates.
+CertPathReviewer.crlOnlyUserCert.details = CRL checking failed: CRL for CA certificate only contains user certificates.
+
+# End CRL only contains CA certificates
+CertPathReviewer.crlOnlyCaCert.title = CRL checking failed
+CertPathReviewer.crlOnlyCaCert.text = CRL checking failed: CRL only contains CA certificates.
+CertPathReviewer.crlOnlyCaCert.summary = CRL checking failed: CRL only contains CA certificates.
+CertPathReviewer.crlOnlyCaCert.details = CRL checking failed: CRL for end certificate only contains CA certificates.
+
+# onlyContainsAttributeCerts boolean is asserted
+CertPathReviewer.crlOnlyAttrCert.title = CRL checking failed
+CertPathReviewer.crlOnlyAttrCert.text = CRL checking failed: CRL only contains attribute certificates.
+CertPathReviewer.crlOnlyAttrCert.summary = CRL checking failed: CRL only contains attribute certificates.
+CertPathReviewer.crlOnlyAttrCert.details = CRL checking failed: CRL only contains attribute certificates.
+
+
+## QcStatement notifications
+
+# unkown statement
+# {0} statement OID
+# {1} statement as ANS1Sequence
+CertPathReviewer.QcUnknownStatement.title = Unknown statement in QcStatement extension
+CertPathReviewer.QcUnknownStatement.text = Unknown statement in QcStatement extension: OID = {0}
+CertPathReviewer.QcUnknownStatement.summary = Unknown statement in QcStatement extension: OID = {0}
+CertPathReviewer.QcUnknownStatement.details = Unknown statement in QcStatement extension: OID = {0}, statement = {1}
+
+# QcLimitValue Alpha currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueAlpha.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueAlpha.text = This certificate has a limit for the transaction value: {1,number, ###,###,###,##0.00#} {0}.
+CertPathReviewer.QcLimitValueAlpha.summary = Transaction value limit: {1,number, ###,###,###,##0.00#} {0}.
+CertPathReviewer.QcLimitValueAlpha.details = This certificate has a limitation on the value of transaction for which this certificate can be used to the specified amount, according to the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. The limit for this certificate is {1,number, ###,###,###,##0.00#} {0}.
+
+# QcLimitValue Numeric currency code
+# {0} currency code
+# {1} limit value
+# {2} monetary value as MonetaryValue
+CertPathReviewer.QcLimitValueNum.title = Transaction Value Limit
+CertPathReviewer.QcLimitValueNum.text = This certificate has a limit for the transaction value: {1,number, ###,###,###,##0.00#} of currency {0} (See RFC 4217 for currency codes).
+CertPathReviewer.QcLimitValueNum.summary = Transaction value limit: {1,number, ###,###,###,##0.00#} of currency {0} (See RFC 4217 for currency codes).
+CertPathReviewer.QcLimitValueNum.details = This certificate has a limitation on the value of transaction for which this certificate can be used to the specified amount, according to the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate. The limit for this certificate is {1,number, ###,###,###,##0.00#} of currency {0} (See RFC 4217 for currency codes).
+
+# QcSSCD
+CertPathReviewer.QcSSCD.title = QcSSCD Statement
+CertPathReviewer.QcSSCD.text = (SSCD) The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+CertPathReviewer.QcSSCD.summary = (SSCD) The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+CertPathReviewer.QcSSCD.details = (SSCD) The issuer claims that for the certificate where this statement appears that the private key associated with the public key in the certificate is protected according to Annex III of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures.
+
+# QcEuCompliance
+CertPathReviewer.QcEuCompliance.title = Qualified Certificate
+CertPathReviewer.QcEuCompliance.text = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+CertPathReviewer.QcEuCompliance.summary = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+CertPathReviewer.QcEuCompliance.details = This certificate is issued as a Qualified Certificate according Annex I and II of the Directive 1999/93/EC of the European Parliament and of the Council of 13 December 1999 on a Community framework for electronic signatures, as implemented in the law of the country specified in the issuer field of this certificate.
+
+## QcStatement errors
+
+# error processing the QcStatement extension
+CertPathReviewer.QcStatementExtError.title = Error processing the qc statements extension
+CertPathReviewer.QcStatementExtError.text = Error processing the qc statements extension.
+CertPathReviewer.QcStatementExtError.summary = Error processing the qc statements extension.
+CertPathReviewer.QcStatementExtError.details = Error processing the qc statements extension.
+
+## unknown/generic errors
+CertPathReviewer.unknown.title = Unexpected Error
+CertPathReviewer.unknown.text = Unexpected Error {0}
+CertPathReviewer.unknown.summary = Unexpected Error
+CertPathReviewer.unknown.details = Unexpected Error {0}
+
+#
+# crl reasons
+#
+unspecified = Unspecified
+keyCompromise = Key Compromise
+cACompromise = CA Compromise
+affiliationChanged = Affiliation Changed
+superseded = Superseded
+cessationOfOperation = Cessation of Operation
+certificateHold = Certificate Hold
+unknown = Unknown
+removeFromCRL = Remove from CRL
+privilegeWithdrawn = Privilege Withdrawn
+aACompromise = AA Compromise
+
+#
+#
+#
+missingIssuer = The missing certificate was issued by
+missingSerial = with the serial number
+ \ No newline at end of file
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/ExtCertificateEncodingException.java b/bcprov/src/main/java/org/bouncycastle/x509/ExtCertificateEncodingException.java
new file mode 100644
index 0000000..a26c310
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/ExtCertificateEncodingException.java
@@ -0,0 +1,20 @@
+package org.bouncycastle.x509;
+
+import java.security.cert.CertificateEncodingException;
+
+class ExtCertificateEncodingException
+ extends CertificateEncodingException
+{
+ Throwable cause;
+
+ ExtCertificateEncodingException(String message, Throwable cause)
+ {
+ super(message);
+ this.cause = cause;
+ }
+
+ public Throwable getCause()
+ {
+ return cause;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java b/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java
new file mode 100644
index 0000000..51831d0
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXBuilderParameters.java
@@ -0,0 +1,210 @@
+package org.bouncycastle.x509;
+
+import org.bouncycastle.util.Selector;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidParameterException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class contains extended parameters for PKIX certification path builders.
+ *
+ * @see java.security.cert.PKIXBuilderParameters
+ * @see org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi
+ */
+public class ExtendedPKIXBuilderParameters extends ExtendedPKIXParameters
+{
+
+ private int maxPathLength = 5;
+
+ private Set excludedCerts = Collections.EMPTY_SET;
+
+ /**
+ * Excluded certificates are not used for building a certification path.
+ * <p>
+ * The returned set is immutable.
+ *
+ * @return Returns the excluded certificates.
+ */
+ public Set getExcludedCerts()
+ {
+ return Collections.unmodifiableSet(excludedCerts);
+ }
+
+ /**
+ * Sets the excluded certificates which are not used for building a
+ * certification path. If the <code>Set</code> is <code>null</code> an
+ * empty set is assumed.
+ * <p>
+ * The given set is cloned to protect it against subsequent modifications.
+ *
+ * @param excludedCerts The excluded certificates to set.
+ */
+ public void setExcludedCerts(Set excludedCerts)
+ {
+ if (excludedCerts == null)
+ {
+ excludedCerts = Collections.EMPTY_SET;
+ }
+ else
+ {
+ this.excludedCerts = new HashSet(excludedCerts);
+ }
+ }
+
+ /**
+ * Creates an instance of <code>PKIXBuilderParameters</code> with the
+ * specified <code>Set</code> of most-trusted CAs. Each element of the set
+ * is a {@link TrustAnchor TrustAnchor}.
+ *
+ * <p>
+ * Note that the <code>Set</code> is copied to protect against subsequent
+ * modifications.
+ *
+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+ * @param targetConstraints a <code>Selector</code> specifying the
+ * constraints on the target certificate or attribute
+ * certificate.
+ * @throws InvalidAlgorithmParameterException if <code>trustAnchors</code>
+ * is empty.
+ * @throws NullPointerException if <code>trustAnchors</code> is
+ * <code>null</code>
+ * @throws ClassCastException if any of the elements of
+ * <code>trustAnchors</code> is not of type
+ * <code>java.security.cert.TrustAnchor</code>
+ */
+ public ExtendedPKIXBuilderParameters(Set trustAnchors,
+ Selector targetConstraints)
+ throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors);
+ setTargetConstraints(targetConstraints);
+ }
+
+ /**
+ * Sets the maximum number of intermediate non-self-issued certificates in a
+ * certification path. The PKIX <code>CertPathBuilder</code> must not
+ * build paths longer then this length.
+ * <p>
+ * 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.
+ *
+ * <p>
+ *
+ * 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 <code>maxPathLength</code> is set
+ * to a value less than -1
+ *
+ * @see org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi
+ * @see #getMaxPathLength
+ */
+ public void setMaxPathLength(int maxPathLength)
+ {
+ if (maxPathLength < -1)
+ {
+ throw new InvalidParameterException("The maximum path "
+ + "length parameter can not be less than -1.");
+ }
+ this.maxPathLength = maxPathLength;
+ }
+
+ /**
+ * 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.
+ *
+ * @see #setMaxPathLength(int)
+ */
+ public int getMaxPathLength()
+ {
+ return maxPathLength;
+ }
+
+ /**
+ * Can alse handle <code>ExtendedPKIXBuilderParameters</code> and
+ * <code>PKIXBuilderParameters</code>.
+ *
+ * @param params Parameters to set.
+ * @see org.bouncycastle.x509.ExtendedPKIXParameters#setParams(java.security.cert.PKIXParameters)
+ */
+ protected void setParams(PKIXParameters params)
+ {
+ super.setParams(params);
+ if (params instanceof ExtendedPKIXBuilderParameters)
+ {
+ ExtendedPKIXBuilderParameters _params = (ExtendedPKIXBuilderParameters) params;
+ maxPathLength = _params.maxPathLength;
+ excludedCerts = new HashSet(_params.excludedCerts);
+ }
+ if (params instanceof PKIXBuilderParameters)
+ {
+ PKIXBuilderParameters _params = (PKIXBuilderParameters) params;
+ maxPathLength = _params.getMaxPathLength();
+ }
+ }
+
+ /**
+ * Makes a copy of this <code>PKIXParameters</code> object. Changes to the
+ * copy will not affect the original and vice versa.
+ *
+ * @return a copy of this <code>PKIXParameters</code> object
+ */
+ public Object clone()
+ {
+ ExtendedPKIXBuilderParameters params = null;
+ try
+ {
+ params = new ExtendedPKIXBuilderParameters(getTrustAnchors(),
+ getTargetConstraints());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(this);
+ return params;
+ }
+
+ /**
+ * Returns an instance of <code>ExtendedPKIXParameters</code> which can be
+ * safely casted to <code>ExtendedPKIXBuilderParameters</code>.
+ * <p>
+ * This method can be used to get a copy from other
+ * <code>PKIXBuilderParameters</code>, <code>PKIXParameters</code>,
+ * and <code>ExtendedPKIXParameters</code> instances.
+ *
+ * @param pkixParams The PKIX parameters to create a copy of.
+ * @return An <code>ExtendedPKIXBuilderParameters</code> instance.
+ */
+ public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+ {
+ ExtendedPKIXBuilderParameters params;
+ try
+ {
+ params = new ExtendedPKIXBuilderParameters(pkixParams
+ .getTrustAnchors(), X509CertStoreSelector
+ .getInstance((X509CertSelector) pkixParams
+ .getTargetCertConstraints()));
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(pkixParams);
+ return params;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java b/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java
new file mode 100644
index 0000000..6386618
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/ExtendedPKIXParameters.java
@@ -0,0 +1,651 @@
+package org.bouncycastle.x509;
+
+import org.bouncycastle.util.Selector;
+import org.bouncycastle.util.Store;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class extends the PKIXParameters with a validity model parameter.
+ */
+public class ExtendedPKIXParameters
+ extends PKIXParameters
+{
+
+ private List stores;
+
+ private Selector selector;
+
+ private boolean additionalLocationsEnabled;
+
+ private List additionalStores;
+
+ private Set trustedACIssuers;
+
+ private Set necessaryACAttributes;
+
+ private Set prohibitedACAttributes;
+
+ private Set attrCertCheckers;
+
+ /**
+ * Creates an instance of <code>PKIXParameters</code> with the specified
+ * <code>Set</code> of most-trusted CAs. Each element of the set is a
+ * {@link TrustAnchor TrustAnchor}. <p/> Note that the <code>Set</code>
+ * is copied to protect against subsequent modifications.
+ *
+ * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
+ * @throws InvalidAlgorithmParameterException if the specified
+ * <code>Set</code> is empty.
+ * @throws NullPointerException if the specified <code>Set</code> is
+ * <code>null</code>
+ * @throws ClassCastException if any of the elements in the <code>Set</code>
+ * is not of type <code>java.security.cert.TrustAnchor</code>
+ */
+ public ExtendedPKIXParameters(Set trustAnchors)
+ throws InvalidAlgorithmParameterException
+ {
+ super(trustAnchors);
+ stores = new ArrayList();
+ additionalStores = new ArrayList();
+ trustedACIssuers = new HashSet();
+ necessaryACAttributes = new HashSet();
+ prohibitedACAttributes = new HashSet();
+ attrCertCheckers = new HashSet();
+ }
+
+ /**
+ * Returns an instance with the parameters of a given
+ * <code>PKIXParameters</code> object.
+ *
+ * @param pkixParams The given <code>PKIXParameters</code>
+ * @return an extended PKIX params object
+ */
+ public static ExtendedPKIXParameters getInstance(PKIXParameters pkixParams)
+ {
+ ExtendedPKIXParameters params;
+ try
+ {
+ params = new ExtendedPKIXParameters(pkixParams.getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(pkixParams);
+ return params;
+ }
+
+ /**
+ * Method to support <code>clone()</code> under J2ME.
+ * <code>super.clone()</code> does not exist and fields are not copied.
+ *
+ * @param params Parameters to set. If this are
+ * <code>ExtendedPKIXParameters</code> they are copied to.
+ */
+ protected void setParams(PKIXParameters params)
+ {
+ setDate(params.getDate());
+ setCertPathCheckers(params.getCertPathCheckers());
+ setCertStores(params.getCertStores());
+ setAnyPolicyInhibited(params.isAnyPolicyInhibited());
+ setExplicitPolicyRequired(params.isExplicitPolicyRequired());
+ setPolicyMappingInhibited(params.isPolicyMappingInhibited());
+ setRevocationEnabled(params.isRevocationEnabled());
+ setInitialPolicies(params.getInitialPolicies());
+ setPolicyQualifiersRejected(params.getPolicyQualifiersRejected());
+ setSigProvider(params.getSigProvider());
+ setTargetCertConstraints(params.getTargetCertConstraints());
+ try
+ {
+ setTrustAnchors(params.getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ if (params instanceof ExtendedPKIXParameters)
+ {
+ ExtendedPKIXParameters _params = (ExtendedPKIXParameters) params;
+ validityModel = _params.validityModel;
+ useDeltas = _params.useDeltas;
+ additionalLocationsEnabled = _params.additionalLocationsEnabled;
+ selector = _params.selector == null ? null
+ : (Selector) _params.selector.clone();
+ stores = new ArrayList(_params.stores);
+ additionalStores = new ArrayList(_params.additionalStores);
+ trustedACIssuers = new HashSet(_params.trustedACIssuers);
+ prohibitedACAttributes = new HashSet(_params.prohibitedACAttributes);
+ necessaryACAttributes = new HashSet(_params.necessaryACAttributes);
+ attrCertCheckers = new HashSet(_params.attrCertCheckers);
+ }
+ }
+
+ /**
+ * 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(java.util.Date)} method, so this
+ * methods sets the Date when <em>all</em> 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(java.util.Date)} method sets the time, when
+ * the <em>end certificate</em> must have been valid. <p/> It is used e.g.
+ * in the German signature law.
+ */
+ public static final int CHAIN_VALIDITY_MODEL = 1;
+
+ private int validityModel = PKIX_VALIDITY_MODEL;
+
+ private boolean useDeltas = false;
+
+ /**
+ * Defaults to <code>false</code>.
+ *
+ * @return Returns if delta CRLs should be used.
+ */
+ public boolean isUseDeltasEnabled()
+ {
+ return useDeltas;
+ }
+
+ /**
+ * Sets if delta CRLs should be used for checking the revocation status.
+ *
+ * @param useDeltas <code>true</code> if delta CRLs should be used.
+ */
+ public void setUseDeltasEnabled(boolean useDeltas)
+ {
+ this.useDeltas = useDeltas;
+ }
+
+ /**
+ * @return Returns the validity model.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public int getValidityModel()
+ {
+ return validityModel;
+ }
+
+ /**
+ * Sets the Java CertStore to this extended PKIX parameters.
+ *
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a <code>CertStore</code>.
+ */
+ public void setCertStores(List stores)
+ {
+ if (stores != null)
+ {
+ Iterator it = stores.iterator();
+ while (it.hasNext())
+ {
+ addCertStore((CertStore)it.next());
+ }
+ }
+ }
+
+ /**
+ * Sets the Bouncy Castle Stores for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * The <code>List</code> is cloned.
+ *
+ * @param stores A list of stores to use.
+ * @see #getStores
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a {@link Store}.
+ */
+ public void setStores(List stores)
+ {
+ if (stores == null)
+ {
+ this.stores = new ArrayList();
+ }
+ else
+ {
+ for (Iterator i = stores.iterator(); i.hasNext();)
+ {
+ if (!(i.next() instanceof Store))
+ {
+ throw new ClassCastException(
+ "All elements of list must be "
+ + "of type org.bouncycastle.util.Store.");
+ }
+ }
+ this.stores = new ArrayList(stores);
+ }
+ }
+
+ /**
+ * Adds a Bouncy Castle {@link Store} to find CRLs, certificates, attribute
+ * certificates or cross certificates.
+ * <p>
+ * This method should be used to add local stores, like collection based
+ * X.509 stores, if available. Local stores should be considered first,
+ * before trying to use additional (remote) locations, because they do not
+ * need possible additional network traffic.
+ * <p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ *
+ * @param store The store to add.
+ * @see #getStores
+ */
+ public void addStore(Store store)
+ {
+ if (store != null)
+ {
+ stores.add(store);
+ }
+ }
+
+ /**
+ * Adds an additional Bouncy Castle {@link Store} to find CRLs, certificates,
+ * attribute certificates or cross certificates.
+ * <p>
+ * You should not use this method. This method is used for adding additional
+ * X.509 stores, which are used to add (remote) locations, e.g. LDAP, found
+ * during X.509 object processing, e.g. in certificates or CRLs. This method
+ * is used in PKIX certification path processing.
+ * <p>
+ * If <code>store</code> is <code>null</code> it is ignored.
+ *
+ * @param store The store to add.
+ * @see #getStores()
+ */
+ public void addAdditionalStore(Store store)
+ {
+ if (store != null)
+ {
+ additionalStores.add(store);
+ }
+ }
+
+ /**
+ * @deprecated
+ */
+ public void addAddionalStore(Store store)
+ {
+ addAdditionalStore(store);
+ }
+
+ /**
+ * Returns an immutable <code>List</code> of additional Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>List</code> of additional Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #addAdditionalStore(Store)
+ */
+ public List getAdditionalStores()
+ {
+ return Collections.unmodifiableList(additionalStores);
+ }
+
+ /**
+ * Returns an immutable <code>List</code> of Bouncy Castle
+ * <code>Store</code>s used for finding CRLs, certificates, attribute
+ * certificates or cross certificates.
+ *
+ * @return an immutable <code>List</code> of Bouncy Castle
+ * <code>Store</code>s. Never <code>null</code>.
+ *
+ * @see #setStores(List)
+ */
+ public List getStores()
+ {
+ return Collections.unmodifiableList(new ArrayList(stores));
+ }
+
+ /**
+ * @param validityModel The validity model to set.
+ * @see #CHAIN_VALIDITY_MODEL
+ * @see #PKIX_VALIDITY_MODEL
+ */
+ public void setValidityModel(int validityModel)
+ {
+ this.validityModel = validityModel;
+ }
+
+ public Object clone()
+ {
+ ExtendedPKIXParameters params;
+ try
+ {
+ params = new ExtendedPKIXParameters(getTrustAnchors());
+ }
+ catch (Exception e)
+ {
+ // cannot happen
+ throw new RuntimeException(e.getMessage());
+ }
+ params.setParams(this);
+ return params;
+ }
+
+ /**
+ * Returns if additional {@link X509Store}s for locations like LDAP found
+ * in certificates or CRLs should be used.
+ *
+ * @return Returns <code>true</code> if additional stores are used.
+ */
+ public boolean isAdditionalLocationsEnabled()
+ {
+ return additionalLocationsEnabled;
+ }
+
+ /**
+ * Sets if additional {@link X509Store}s for locations like LDAP found in
+ * certificates or CRLs should be used.
+ *
+ * @param enabled <code>true</code> if additional stores are used.
+ */
+ public void setAdditionalLocationsEnabled(boolean enabled)
+ {
+ additionalLocationsEnabled = enabled;
+ }
+
+ /**
+ * Returns the required constraints on the target certificate or attribute
+ * certificate. The constraints are returned as an instance of
+ * <code>Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ *
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * <p>
+ * Note that the <code>Selector</code> returned is cloned to protect
+ * against subsequent modifications.
+ *
+ * @return a <code>Selector</code> specifying the constraints on the
+ * target certificate or attribute certificate (or <code>null</code>)
+ * @see #setTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public Selector getTargetConstraints()
+ {
+ if (selector != null)
+ {
+ return (Selector) selector.clone();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate or attribute
+ * certificate. The constraints are specified as an instance of
+ * <code>Selector</code>. If <code>null</code>, no constraints are
+ * defined.
+ * <p>
+ * The target certificate in a PKIX path may be a certificate or an
+ * attribute certificate.
+ * <p>
+ * Note that the <code>Selector</code> specified is cloned to protect
+ * against subsequent modifications.
+ *
+ * @param selector a <code>Selector</code> specifying the constraints on
+ * the target certificate or attribute certificate (or
+ * <code>null</code>)
+ * @see #getTargetConstraints
+ * @see X509CertStoreSelector
+ * @see X509AttributeCertStoreSelector
+ */
+ public void setTargetConstraints(Selector selector)
+ {
+ if (selector != null)
+ {
+ this.selector = (Selector) selector.clone();
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Sets the required constraints on the target certificate. The constraints
+ * are specified as an instance of <code>X509CertSelector</code>. If
+ * <code>null</code>, no constraints are defined.
+ *
+ * <p>
+ * This method wraps the given <code>X509CertSelector</code> into a
+ * <code>X509CertStoreSelector</code>.
+ * <p>
+ * Note that the <code>X509CertSelector</code> specified is cloned to
+ * protect against subsequent modifications.
+ *
+ * @param selector a <code>X509CertSelector</code> specifying the
+ * constraints on the target certificate (or <code>null</code>)
+ * @see #getTargetCertConstraints
+ * @see X509CertStoreSelector
+ */
+ public void setTargetCertConstraints(CertSelector selector)
+ {
+ super.setTargetCertConstraints(selector);
+ if (selector != null)
+ {
+ this.selector = X509CertStoreSelector
+ .getInstance((X509CertSelector) selector);
+ }
+ else
+ {
+ this.selector = null;
+ }
+ }
+
+ /**
+ * Returns the trusted attribute certificate issuers. If attribute
+ * certificates is verified the trusted AC issuers must be set.
+ * <p>
+ * The returned <code>Set</code> consists of <code>TrustAnchor</code>s.
+ * <p>
+ * The returned <code>Set</code> is immutable. Never <code>null</code>
+ *
+ * @return Returns an immutable set of the trusted AC issuers.
+ */
+ public Set getTrustedACIssuers()
+ {
+ return Collections.unmodifiableSet(trustedACIssuers);
+ }
+
+ /**
+ * Sets the trusted attribute certificate issuers. If attribute certificates
+ * is verified the trusted AC issuers must be set.
+ * <p>
+ * The <code>trustedACIssuers</code> must be a <code>Set</code> of
+ * <code>TrustAnchor</code>
+ * <p>
+ * The given set is cloned.
+ *
+ * @param trustedACIssuers The trusted AC issuers to set. Is never
+ * <code>null</code>.
+ * @throws ClassCastException if an element of <code>stores</code> is not
+ * a <code>TrustAnchor</code>.
+ */
+ public void setTrustedACIssuers(Set trustedACIssuers)
+ {
+ if (trustedACIssuers == null)
+ {
+ this.trustedACIssuers.clear();
+ return;
+ }
+ for (Iterator it = trustedACIssuers.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof TrustAnchor))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type " + TrustAnchor.class.getName() + ".");
+ }
+ }
+ this.trustedACIssuers.clear();
+ this.trustedACIssuers.addAll(trustedACIssuers);
+ }
+
+ /**
+ * Returns the neccessary attributes which must be contained in an attribute
+ * certificate.
+ * <p>
+ * The returned <code>Set</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ *
+ * @return Returns the necessary AC attributes.
+ */
+ public Set getNecessaryACAttributes()
+ {
+ return Collections.unmodifiableSet(necessaryACAttributes);
+ }
+
+ /**
+ * Sets the neccessary which must be contained in an attribute certificate.
+ * <p>
+ * The <code>Set</code> must contain <code>String</code>s with the
+ * OIDs.
+ * <p>
+ * The set is cloned.
+ *
+ * @param necessaryACAttributes The necessary AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>necessaryACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public void setNecessaryACAttributes(Set necessaryACAttributes)
+ {
+ if (necessaryACAttributes == null)
+ {
+ this.necessaryACAttributes.clear();
+ return;
+ }
+ for (Iterator it = necessaryACAttributes.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof String))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type String.");
+ }
+ }
+ this.necessaryACAttributes.clear();
+ this.necessaryACAttributes.addAll(necessaryACAttributes);
+ }
+
+ /**
+ * Returns the attribute certificates which are not allowed.
+ * <p>
+ * The returned <code>Set</code> is immutable and contains
+ * <code>String</code>s with the OIDs.
+ *
+ * @return Returns the prohibited AC attributes. Is never <code>null</code>.
+ */
+ public Set getProhibitedACAttributes()
+ {
+ return Collections.unmodifiableSet(prohibitedACAttributes);
+ }
+
+ /**
+ * Sets the attribute certificates which are not allowed.
+ * <p>
+ * The <code>Set</code> must contain <code>String</code>s with the
+ * OIDs.
+ * <p>
+ * The set is cloned.
+ *
+ * @param prohibitedACAttributes The prohibited AC attributes to set.
+ * @throws ClassCastException if an element of
+ * <code>prohibitedACAttributes</code> is not a
+ * <code>String</code>.
+ */
+ public void setProhibitedACAttributes(Set prohibitedACAttributes)
+ {
+ if (prohibitedACAttributes == null)
+ {
+ this.prohibitedACAttributes.clear();
+ return;
+ }
+ for (Iterator it = prohibitedACAttributes.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof String))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type String.");
+ }
+ }
+ this.prohibitedACAttributes.clear();
+ this.prohibitedACAttributes.addAll(prohibitedACAttributes);
+ }
+
+ /**
+ * Returns the attribute certificate checker. The returned set contains
+ * {@link PKIXAttrCertChecker}s and is immutable.
+ *
+ * @return Returns the attribute certificate checker. Is never
+ * <code>null</code>.
+ */
+ public Set getAttrCertCheckers()
+ {
+ return Collections.unmodifiableSet(attrCertCheckers);
+ }
+
+ /**
+ * Sets the attribute certificate checkers.
+ * <p>
+ * All elements in the <code>Set</code> must a {@link PKIXAttrCertChecker}.
+ * <p>
+ * The given set is cloned.
+ *
+ * @param attrCertCheckers The attribute certificate checkers to set. Is
+ * never <code>null</code>.
+ * @throws ClassCastException if an element of <code>attrCertCheckers</code>
+ * is not a <code>PKIXAttrCertChecker</code>.
+ */
+ public void setAttrCertCheckers(Set attrCertCheckers)
+ {
+ if (attrCertCheckers == null)
+ {
+ this.attrCertCheckers.clear();
+ return;
+ }
+ for (Iterator it = attrCertCheckers.iterator(); it.hasNext();)
+ {
+ if (!(it.next() instanceof PKIXAttrCertChecker))
+ {
+ throw new ClassCastException("All elements of set must be "
+ + "of type " + PKIXAttrCertChecker.class.getName() + ".");
+ }
+ }
+ this.attrCertCheckers.clear();
+ this.attrCertCheckers.addAll(attrCertCheckers);
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/NoSuchStoreException.java b/bcprov/src/main/java/org/bouncycastle/x509/NoSuchStoreException.java
new file mode 100644
index 0000000..255c030
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/NoSuchStoreException.java
@@ -0,0 +1,10 @@
+package org.bouncycastle.x509;
+
+public class NoSuchStoreException
+ extends Exception
+{
+ public NoSuchStoreException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/PKIXAttrCertChecker.java b/bcprov/src/main/java/org/bouncycastle/x509/PKIXAttrCertChecker.java
new file mode 100644
index 0000000..816cdab
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/PKIXAttrCertChecker.java
@@ -0,0 +1,56 @@
+package org.bouncycastle.x509;
+
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.util.Collection;
+import java.util.Set;
+
+public abstract class PKIXAttrCertChecker
+ implements Cloneable
+{
+
+ /**
+ * Returns an immutable <code>Set</code> of X.509 attribute certificate
+ * extensions that this <code>PKIXAttrCertChecker</code> supports or
+ * <code>null</code> if no extensions are supported.
+ * <p>
+ * Each element of the set is a <code>String</code> representing the
+ * Object Identifier (OID) of the X.509 extension that is supported.
+ * <p>
+ * All X.509 attribute certificate extensions that a
+ * <code>PKIXAttrCertChecker</code> might possibly be able to process
+ * should be included in the set.
+ *
+ * @return an immutable <code>Set</code> of X.509 extension OIDs (in
+ * <code>String</code> format) supported by this
+ * <code>PKIXAttrCertChecker</code>, or <code>null</code> if no
+ * extensions are supported
+ */
+ public abstract Set getSupportedExtensions();
+
+ /**
+ * Performs checks on the specified attribute certificate. Every handled
+ * extension is rmeoved from the <code>unresolvedCritExts</code>
+ * collection.
+ *
+ * @param attrCert The attribute certificate to be checked.
+ * @param certPath The certificate path which belongs to the attribute
+ * certificate issuer public key certificate.
+ * @param holderCertPath The certificate path which belongs to the holder
+ * certificate.
+ * @param unresolvedCritExts a <code>Collection</code> of OID strings
+ * representing the current set of unresolved critical extensions
+ * @throws CertPathValidatorException if the specified attribute certificate
+ * does not pass the check.
+ */
+ public abstract void check(X509AttributeCertificate attrCert, CertPath certPath,
+ CertPath holderCertPath, Collection unresolvedCritExts)
+ throws CertPathValidatorException;
+
+ /**
+ * Returns a clone of this object.
+ *
+ * @return a copy of this <code>PKIXAttrCertChecker</code>
+ */
+ public abstract Object clone();
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509Attribute.java b/bcprov/src/main/java/org/bouncycastle/x509/X509Attribute.java
new file mode 100644
index 0000000..95da292
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509Attribute.java
@@ -0,0 +1,79 @@
+package org.bouncycastle.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.ASN1Set;
+import org.bouncycastle.asn1.DERSet;
+import org.bouncycastle.asn1.x509.Attribute;
+
+/**
+ * Class for carrying the values in an X.509 Attribute.
+ */
+public class X509Attribute
+ extends ASN1Object
+{
+ Attribute attr;
+
+ /**
+ * @param at an object representing an attribute.
+ */
+ X509Attribute(
+ ASN1Encodable at)
+ {
+ this.attr = Attribute.getInstance(at);
+ }
+
+ /**
+ * Create an X.509 Attribute with the type given by the passed in oid and
+ * the value represented by an ASN.1 Set containing value.
+ *
+ * @param oid type of the attribute
+ * @param value value object to go into the atribute's value set.
+ */
+ public X509Attribute(
+ String oid,
+ ASN1Encodable value)
+ {
+ this.attr = new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value));
+ }
+
+ /**
+ * Create an X.59 Attribute with the type given by the passed in oid and the
+ * value represented by an ASN.1 Set containing the objects in value.
+ *
+ * @param oid type of the attribute
+ * @param value vector of values to go in the attribute's value set.
+ */
+ public X509Attribute(
+ String oid,
+ ASN1EncodableVector value)
+ {
+ this.attr = new Attribute(new ASN1ObjectIdentifier(oid), new DERSet(value));
+ }
+
+ public String getOID()
+ {
+ return attr.getAttrType().getId();
+ }
+
+ public ASN1Encodable[] getValues()
+ {
+ ASN1Set s = attr.getAttrValues();
+ ASN1Encodable[] values = new ASN1Encodable[s.size()];
+
+ for (int i = 0; i != s.size(); i++)
+ {
+ values[i] = (ASN1Encodable)s.getObjectAt(i);
+ }
+
+ return values;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ return attr.toASN1Primitive();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java b/bcprov/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java
new file mode 100644
index 0000000..48a825f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509AttributeCertificate.java
@@ -0,0 +1,101 @@
+package org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Extension;
+import java.util.Date;
+
+/**
+ * Interface for an X.509 Attribute Certificate.
+ */
+public interface X509AttributeCertificate
+ extends X509Extension
+{
+ /**
+ * Return the version number for the certificate.
+ *
+ * @return the version number.
+ */
+ public int getVersion();
+
+ /**
+ * Return the serial number for the certificate.
+ *
+ * @return the serial number.
+ */
+ public BigInteger getSerialNumber();
+
+ /**
+ * Return the date before which the certificate is not valid.
+ *
+ * @return the "not valid before" date.
+ */
+ public Date getNotBefore();
+
+ /**
+ * Return the date after which the certificate is not valid.
+ *
+ * @return the "not valid afer" date.
+ */
+ public Date getNotAfter();
+
+ /**
+ * Return the holder of the certificate.
+ *
+ * @return the holder.
+ */
+ public AttributeCertificateHolder getHolder();
+
+ /**
+ * Return the issuer details for the certificate.
+ *
+ * @return the issuer details.
+ */
+ public AttributeCertificateIssuer getIssuer();
+
+ /**
+ * Return the attributes contained in the attribute block in the certificate.
+ *
+ * @return an array of attributes.
+ */
+ public X509Attribute[] getAttributes();
+
+ /**
+ * Return the attributes with the same type as the passed in oid.
+ *
+ * @param oid the object identifier we wish to match.
+ * @return an array of matched attributes, null if there is no match.
+ */
+ public X509Attribute[] getAttributes(String oid);
+
+ public boolean[] getIssuerUniqueID();
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException;
+
+ public void checkValidity(Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException;
+
+ public byte[] getSignature();
+
+ public void verify(PublicKey key, String provider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException;
+
+ /**
+ * Return an ASN.1 encoded byte array representing the attribute certificate.
+ *
+ * @return an ASN.1 encoded byte array.
+ * @throws IOException if the certificate cannot be encoded.
+ */
+ public byte[] getEncoded()
+ throws IOException;
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java b/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java
new file mode 100644
index 0000000..cc50b8f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509CRLStoreSelector.java
@@ -0,0 +1,330 @@
+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;
+
+/**
+ * This class is a Selector implementation for X.509 certificate revocation
+ * lists.
+ *
+ * @see org.bouncycastle.util.Selector
+ * @see org.bouncycastle.x509.X509Store
+ * @see org.bouncycastle.jce.provider.X509StoreCRLCollection
+ */
+public class X509CRLStoreSelector
+ extends X509CRLSelector
+ implements Selector
+{
+ private boolean deltaCRLIndicator = false;
+
+ private boolean completeCRLEnabled = false;
+
+ private BigInteger maxBaseCRLNumber = null;
+
+ private byte[] issuingDistributionPoint = null;
+
+ private boolean issuingDistributionPointEnabled = false;
+
+ private X509AttributeCertificate attrCertChecking;
+
+ /**
+ * Returns if the issuing distribution point criteria should be applied.
+ * Defaults to <code>false</code>.
+ * <p>
+ * 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;
+ }
+
+ /**
+ * Enables or disables the issuing distribution point check.
+ *
+ * @param issuingDistributionPointEnabled <code>true</code> to enable the
+ * issuing distribution point check.
+ */
+ public void setIssuingDistributionPointEnabled(
+ boolean issuingDistributionPointEnabled)
+ {
+ this.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ }
+
+ /**
+ * Sets the attribute certificate being checked. This is not a criterion.
+ * Rather, it is optional information that may help a {@link X509Store} find
+ * CRLs that would be relevant when checking revocation for the specified
+ * attribute certificate. If <code>null</code> is specified, then no such
+ * optional information is provided.
+ *
+ * @param attrCert the <code>X509AttributeCertificate</code> being checked (or
+ * <code>null</code>)
+ * @see #getAttrCertificateChecking()
+ */
+ public void setAttrCertificateChecking(X509AttributeCertificate attrCert)
+ {
+ attrCertChecking = attrCert;
+ }
+
+ /**
+ * Returns the attribute certificate being checked.
+ *
+ * @return Returns the attribute certificate being checked.
+ * @see #setAttrCertificateChecking(X509AttributeCertificate)
+ */
+ public X509AttributeCertificate getAttrCertificateChecking()
+ {
+ return attrCertChecking;
+ }
+
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509CRL))
+ {
+ return false;
+ }
+ X509CRL crl = (X509CRL)obj;
+ DERInteger dci = null;
+ try
+ {
+ byte[] bytes = crl
+ .getExtensionValue(X509Extensions.DeltaCRLIndicator.getId());
+ if (bytes != null)
+ {
+ dci = DERInteger.getInstance(X509ExtensionUtil
+ .fromExtensionValue(bytes));
+ }
+ }
+ 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(X509Extensions.IssuingDistributionPoint
+ .getId());
+ if (issuingDistributionPoint == null)
+ {
+ if (idp != null)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (!Arrays.areEqual(idp, issuingDistributionPoint))
+ {
+ return false;
+ }
+ }
+
+ }
+ return super.match((X509CRL)obj);
+ }
+
+ public boolean match(CRL crl)
+ {
+ return match((Object)crl);
+ }
+
+ /**
+ * Returns if this selector must match CRLs with the delta CRL indicator
+ * extension set. Defaults to <code>false</code>.
+ *
+ * @return Returns <code>true</code> if only CRLs with the delta CRL
+ * indicator extension are selected.
+ */
+ public boolean isDeltaCRLIndicatorEnabled()
+ {
+ return deltaCRLIndicator;
+ }
+
+ /**
+ * If this is set to <code>true</code> the CRL reported contains the delta
+ * CRL indicator CRL extension.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param deltaCRLIndicator <code>true</code> if the delta CRL indicator
+ * extension must be in the CRL.
+ */
+ public void setDeltaCRLIndicatorEnabled(boolean deltaCRLIndicator)
+ {
+ this.deltaCRLIndicator = deltaCRLIndicator;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CRLSelector</code>.
+ *
+ * @param selector A <code>X509CRLSelector</code> instance.
+ * @return An instance of an <code>X509CRLStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation
+ * fails.
+ */
+ public static X509CRLStoreSelector getInstance(X509CRLSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException(
+ "cannot create from null selector");
+ }
+ X509CRLStoreSelector cs = new X509CRLStoreSelector();
+ cs.setCertificateChecking(selector.getCertificateChecking());
+ cs.setDateAndTime(selector.getDateAndTime());
+ try
+ {
+ cs.setIssuerNames(selector.getIssuerNames());
+ }
+ catch (IOException e)
+ {
+ // cannot happen
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ cs.setIssuers(selector.getIssuers());
+ cs.setMaxCRLNumber(selector.getMaxCRL());
+ cs.setMinCRLNumber(selector.getMinCRL());
+ return cs;
+ }
+
+ public Object clone()
+ {
+ X509CRLStoreSelector sel = X509CRLStoreSelector.getInstance(this);
+ sel.deltaCRLIndicator = deltaCRLIndicator;
+ sel.completeCRLEnabled = completeCRLEnabled;
+ sel.maxBaseCRLNumber = maxBaseCRLNumber;
+ sel.attrCertChecking = attrCertChecking;
+ sel.issuingDistributionPointEnabled = issuingDistributionPointEnabled;
+ sel.issuingDistributionPoint = Arrays.clone(issuingDistributionPoint);
+ return sel;
+ }
+
+ /**
+ * If <code>true</code> only complete CRLs are returned. Defaults to
+ * <code>false</code>.
+ *
+ * @return <code>true</code> if only complete CRLs are returned.
+ */
+ public boolean isCompleteCRLEnabled()
+ {
+ return completeCRLEnabled;
+ }
+
+ /**
+ * If set to <code>true</code> only complete CRLs are returned.
+ * <p>
+ * {@link #setCompleteCRLEnabled(boolean)} and
+ * {@link #setDeltaCRLIndicatorEnabled(boolean)} excluded each other.
+ *
+ * @param completeCRLEnabled <code>true</code> if only complete CRLs
+ * should be returned.
+ */
+ public void setCompleteCRLEnabled(boolean completeCRLEnabled)
+ {
+ this.completeCRLEnabled = completeCRLEnabled;
+ }
+
+ /**
+ * Get the maximum base CRL number. Defaults to <code>null</code>.
+ *
+ * @return Returns the maximum base CRL number.
+ * @see #setMaxBaseCRLNumber(BigInteger)
+ */
+ public BigInteger getMaxBaseCRLNumber()
+ {
+ return maxBaseCRLNumber;
+ }
+
+ /**
+ * Sets the maximum base CRL number. Setting to <code>null</code> disables
+ * this cheack.
+ * <p>
+ * 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;
+ }
+
+ /**
+ * Returns the issuing distribution point. Defaults to <code>null</code>,
+ * which is a missing issuing distribution point extension.
+ * <p>
+ * The internal byte array is cloned before it is returned.
+ * <p>
+ * The criteria must be enable with
+ * {@link #setIssuingDistributionPointEnabled(boolean)}.
+ *
+ * @return Returns the issuing distribution point.
+ * @see #setIssuingDistributionPoint(byte[])
+ */
+ public byte[] getIssuingDistributionPoint()
+ {
+ return Arrays.clone(issuingDistributionPoint);
+ }
+
+ /**
+ * Sets the issuing distribution point.
+ * <p>
+ * 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.
+ * <p>
+ * The byte array is cloned to protect against subsequent modifications.
+ * <p>
+ * 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);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509CertStoreSelector.java b/bcprov/src/main/java/org/bouncycastle/x509/X509CertStoreSelector.java
new file mode 100644
index 0000000..b272649
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509CertStoreSelector.java
@@ -0,0 +1,87 @@
+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;
+
+/**
+ * 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
+ */
+public class X509CertStoreSelector
+ extends X509CertSelector
+ implements Selector
+{
+ public boolean match(Object obj)
+ {
+ if (!(obj instanceof X509Certificate))
+ {
+ return false;
+ }
+
+ X509Certificate other = (X509Certificate)obj;
+
+ return super.match(other);
+ }
+
+ public boolean match(Certificate cert)
+ {
+ return match((Object)cert);
+ }
+
+ public Object clone()
+ {
+ X509CertStoreSelector selector = (X509CertStoreSelector)super.clone();
+
+ return selector;
+ }
+
+ /**
+ * Returns an instance of this from a <code>X509CertSelector</code>.
+ *
+ * @param selector A <code>X509CertSelector</code> instance.
+ * @return An instance of an <code>X509CertStoreSelector</code>.
+ * @exception IllegalArgumentException if selector is null or creation fails.
+ */
+ public static X509CertStoreSelector getInstance(X509CertSelector selector)
+ {
+ if (selector == null)
+ {
+ throw new IllegalArgumentException("cannot create from null selector");
+ }
+ X509CertStoreSelector cs = new X509CertStoreSelector();
+ cs.setAuthorityKeyIdentifier(selector.getAuthorityKeyIdentifier());
+ cs.setBasicConstraints(selector.getBasicConstraints());
+ cs.setCertificate(selector.getCertificate());
+ cs.setCertificateValid(selector.getCertificateValid());
+ cs.setMatchAllSubjectAltNames(selector.getMatchAllSubjectAltNames());
+ try
+ {
+ cs.setPathToNames(selector.getPathToNames());
+ cs.setExtendedKeyUsage(selector.getExtendedKeyUsage());
+ cs.setNameConstraints(selector.getNameConstraints());
+ cs.setPolicy(selector.getPolicy());
+ cs.setSubjectPublicKeyAlgID(selector.getSubjectPublicKeyAlgID());
+ cs.setSubjectAlternativeNames(selector.getSubjectAlternativeNames());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("error in passed in selector: " + e);
+ }
+ cs.setIssuer(selector.getIssuer());
+ cs.setKeyUsage(selector.getKeyUsage());
+ cs.setPrivateKeyValid(selector.getPrivateKeyValid());
+ cs.setSerialNumber(selector.getSerialNumber());
+ cs.setSubject(selector.getSubject());
+ cs.setSubjectKeyIdentifier(selector.getSubjectKeyIdentifier());
+ cs.setSubjectPublicKey(selector.getSubjectPublicKey());
+ return cs;
+ }
+
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509CollectionStoreParameters.java b/bcprov/src/main/java/org/bouncycastle/x509/X509CollectionStoreParameters.java
new file mode 100644
index 0000000..16420fe
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509CollectionStoreParameters.java
@@ -0,0 +1,70 @@
+package org.bouncycastle.x509;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * This class contains a collection for collection based <code>X509Store</code>s.
+ *
+ * @see org.bouncycastle.x509.X509Store
+ *
+ */
+public class X509CollectionStoreParameters
+ implements X509StoreParameters
+{
+ private Collection collection;
+
+ /**
+ * Constructor.
+ * <p>
+ * The collection is copied.
+ * </p>
+ *
+ * @param collection
+ * The collection containing X.509 object types.
+ * @throws NullPointerException if <code>collection</code> is <code>null</code>.
+ */
+ public X509CollectionStoreParameters(Collection collection)
+ {
+ if (collection == null)
+ {
+ throw new NullPointerException("collection cannot be null");
+ }
+ this.collection = collection;
+ }
+
+ /**
+ * Returns a shallow clone. The returned contents are not copied, so adding
+ * or removing objects will effect this.
+ *
+ * @return a shallow clone.
+ */
+ public Object clone()
+ {
+ return new X509CollectionStoreParameters(collection);
+ }
+
+ /**
+ * Returns a copy of the <code>Collection</code>.
+ *
+ * @return The <code>Collection</code>. Is never <code>null</code>.
+ */
+ public Collection getCollection()
+ {
+ return new ArrayList(collection);
+ }
+
+ /**
+ * Returns a formatted string describing the parameters.
+ *
+ * @return a formatted string describing the parameters
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("X509CollectionStoreParameters: [\n");
+ sb.append(" collection: " + collection + "\n");
+ sb.append("]");
+ return sb.toString();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509Store.java b/bcprov/src/main/java/org/bouncycastle/x509/X509Store.java
new file mode 100644
index 0000000..1bfc00f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509Store.java
@@ -0,0 +1,79 @@
+package org.bouncycastle.x509;
+
+import org.bouncycastle.util.Selector;
+import org.bouncycastle.util.Store;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.util.Collection;
+
+public class X509Store
+ implements Store
+{
+ public static X509Store getInstance(String type, X509StoreParameters parameters)
+ throws NoSuchStoreException
+ {
+ try
+ {
+ X509Util.Implementation impl = X509Util.getImplementation("X509Store", type);
+
+ return createStore(impl, parameters);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new NoSuchStoreException(e.getMessage());
+ }
+ }
+
+ public static X509Store getInstance(String type, X509StoreParameters parameters, String provider)
+ throws NoSuchStoreException, NoSuchProviderException
+ {
+ return getInstance(type, parameters, X509Util.getProvider(provider));
+ }
+
+ public static X509Store getInstance(String type, X509StoreParameters parameters, Provider provider)
+ throws NoSuchStoreException
+ {
+ try
+ {
+ X509Util.Implementation impl = X509Util.getImplementation("X509Store", type, provider);
+
+ return createStore(impl, parameters);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new NoSuchStoreException(e.getMessage());
+ }
+ }
+
+ private static X509Store createStore(X509Util.Implementation impl, X509StoreParameters parameters)
+ {
+ X509StoreSpi spi = (X509StoreSpi)impl.getEngine();
+
+ spi.engineInit(parameters);
+
+ return new X509Store(impl.getProvider(), spi);
+ }
+
+ private Provider _provider;
+ private X509StoreSpi _spi;
+
+ private X509Store(
+ Provider provider,
+ X509StoreSpi spi)
+ {
+ _provider = provider;
+ _spi = spi;
+ }
+
+ public Provider getProvider()
+ {
+ return _provider;
+ }
+
+ public Collection getMatches(Selector selector)
+ {
+ return _spi.engineGetMatches(selector);
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509StoreParameters.java b/bcprov/src/main/java/org/bouncycastle/x509/X509StoreParameters.java
new file mode 100644
index 0000000..22548da
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509StoreParameters.java
@@ -0,0 +1,5 @@
+package org.bouncycastle.x509;
+
+public interface X509StoreParameters
+{
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509StoreSpi.java b/bcprov/src/main/java/org/bouncycastle/x509/X509StoreSpi.java
new file mode 100644
index 0000000..3455add
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509StoreSpi.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.x509;
+
+import org.bouncycastle.util.Selector;
+
+import java.util.Collection;
+
+public abstract class X509StoreSpi
+{
+ public abstract void engineInit(X509StoreParameters parameters);
+
+ public abstract Collection engineGetMatches(Selector selector);
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java b/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java
new file mode 100644
index 0000000..13426c1
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509Util.java
@@ -0,0 +1,450 @@
+package org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+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.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+// 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;
+import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
+// BEGIN android-removed
+// import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+// END android-removed
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.util.Strings;
+
+class X509Util
+{
+ private static Hashtable algorithms = new Hashtable();
+ private static Hashtable params = new Hashtable();
+ private static Set noParams = new HashSet();
+
+ static
+ {
+ // BEGIN android-removed
+ // algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ // algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
+ // END android-removed
+ algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
+ // BEGIN android-removed
+ // algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ // algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
+ // END android-removed
+ algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
+ algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
+ algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
+ algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ // BEGIN android-removed
+ // algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ // END android-removed
+ algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
+ // BEGIN android-removed
+ // algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ // algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
+ // algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ // algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
+ // algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ // algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
+ // END android-removed
+ algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
+ algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
+ // BEGIN android-removed
+ // algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
+ // END android-removed
+ algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
+ algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
+ algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
+ algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
+ // BEGIN android-removed
+ // algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
+ // END android-removed
+ algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
+ algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
+ algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
+ // BEGIN android-removed
+ // algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ // algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ // 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);
+ // 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.
+ //
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1);
+ // BEGIN android-removed
+ // noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA224);
+ // END android-removed
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA256);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA384);
+ noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA512);
+ noParams.add(X9ObjectIdentifiers.id_dsa_with_sha1);
+ // BEGIN android-removed
+ // noParams.add(NISTObjectIdentifiers.dsa_with_sha224);
+ // END android-removed
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha256);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha384);
+ noParams.add(NISTObjectIdentifiers.dsa_with_sha512);
+
+ //
+ // RFC 4491
+ //
+ // BEGIN android-removed
+ // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
+ // noParams.add(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
+ // END android-removed
+
+ //
+ // explicit params
+ //
+ // BEGIN android-changed
+ AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
+ // END android-changed
+ params.put("SHA1WITHRSAANDMGF1", creatPSSParams(sha1AlgId, 20));
+
+ // BEGIN android-removed
+ // // BEGIN android-changed
+ // AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE);
+ // // END android-changed
+ // params.put("SHA224WITHRSAANDMGF1", creatPSSParams(sha224AlgId, 28));
+ // END android-removed
+
+ // BEGIN android-changed
+ AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);
+ // END android-changed
+ params.put("SHA256WITHRSAANDMGF1", creatPSSParams(sha256AlgId, 32));
+
+ // BEGIN android-changed
+ AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE);
+ // END android-changed
+ params.put("SHA384WITHRSAANDMGF1", creatPSSParams(sha384AlgId, 48));
+
+ // BEGIN android-changed
+ AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512, DERNull.INSTANCE);
+ // END android-changed
+ params.put("SHA512WITHRSAANDMGF1", creatPSSParams(sha512AlgId, 64));
+ }
+
+ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int saltSize)
+ {
+ return new RSASSAPSSparams(
+ hashAlgId,
+ new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId),
+ new ASN1Integer(saltSize),
+ new ASN1Integer(1));
+ }
+
+ static DERObjectIdentifier getAlgorithmOID(
+ String algorithmName)
+ {
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (algorithms.containsKey(algorithmName))
+ {
+ return (DERObjectIdentifier)algorithms.get(algorithmName);
+ }
+
+ return new DERObjectIdentifier(algorithmName);
+ }
+
+ static AlgorithmIdentifier getSigAlgID(
+ DERObjectIdentifier sigOid,
+ String algorithmName)
+ {
+ if (noParams.contains(sigOid))
+ {
+ return new AlgorithmIdentifier(sigOid);
+ }
+
+ algorithmName = Strings.toUpperCase(algorithmName);
+
+ if (params.containsKey(algorithmName))
+ {
+ return new AlgorithmIdentifier(sigOid, (ASN1Encodable)params.get(algorithmName));
+ }
+ else
+ {
+ // BEGIN android-changed
+ return new AlgorithmIdentifier(sigOid, DERNull.INSTANCE);
+ // END android-changed
+ }
+ }
+
+ static Iterator getAlgNames()
+ {
+ Enumeration e = algorithms.keys();
+ List l = new ArrayList();
+
+ while (e.hasMoreElements())
+ {
+ l.add(e.nextElement());
+ }
+
+ return l.iterator();
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ return Signature.getInstance(algorithm);
+ }
+
+ static Signature getSignatureInstance(
+ String algorithm,
+ String provider)
+ throws NoSuchProviderException, NoSuchAlgorithmException
+ {
+ if (provider != null)
+ {
+ return Signature.getInstance(algorithm, provider);
+ }
+ else
+ {
+ return Signature.getInstance(algorithm);
+ }
+ }
+
+ static byte[] calculateSignature(
+ DERObjectIdentifier sigOid,
+ String sigName,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName);
+
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ static byte[] calculateSignature(
+ DERObjectIdentifier sigOid,
+ String sigName,
+ String provider,
+ PrivateKey key,
+ SecureRandom random,
+ ASN1Encodable object)
+ throws IOException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ Signature sig;
+
+ if (sigOid == null)
+ {
+ throw new IllegalStateException("no signature algorithm specified");
+ }
+
+ sig = X509Util.getSignatureInstance(sigName, provider);
+
+ if (random != null)
+ {
+ sig.initSign(key, random);
+ }
+ else
+ {
+ sig.initSign(key);
+ }
+
+ sig.update(object.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+
+ return sig.sign();
+ }
+
+ static X509Principal convertPrincipal(
+ X500Principal principal)
+ {
+ try
+ {
+ return new X509Principal(principal.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("cannot convert principal");
+ }
+ }
+
+ static class Implementation
+ {
+ Object engine;
+ Provider provider;
+
+ Implementation(
+ Object engine,
+ Provider provider)
+ {
+ this.engine = engine;
+ this.provider = provider;
+ }
+
+ Object getEngine()
+ {
+ return engine;
+ }
+
+ Provider getProvider()
+ {
+ return provider;
+ }
+ }
+
+ /**
+ * see if we can find an algorithm (or its alias and what it represents) in
+ * the property table for the given provider.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm,
+ Provider prov)
+ throws NoSuchAlgorithmException
+ {
+ algorithm = Strings.toUpperCase(algorithm);
+
+ String alias;
+
+ while ((alias = prov.getProperty("Alg.Alias." + baseName + "." + algorithm)) != null)
+ {
+ algorithm = alias;
+ }
+
+ String className = prov.getProperty(baseName + "." + algorithm);
+
+ if (className != null)
+ {
+ try
+ {
+ Class cls;
+ ClassLoader clsLoader = prov.getClass().getClassLoader();
+
+ if (clsLoader != null)
+ {
+ cls = clsLoader.loadClass(className);
+ }
+ else
+ {
+ cls = Class.forName(className);
+ }
+
+ return new Implementation(cls.newInstance(), prov);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but no class \"" + className + "\" found!");
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(
+ "algorithm " + algorithm + " in provider " + prov.getName() + " but class \"" + className + "\" inaccessible!");
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm + " for provider " + prov.getName());
+ }
+
+ /**
+ * return an implementation for a given algorithm/provider.
+ * If the provider is null, we grab the first avalaible who has the required algorithm.
+ */
+ static Implementation getImplementation(
+ String baseName,
+ String algorithm)
+ throws NoSuchAlgorithmException
+ {
+ Provider[] prov = Security.getProviders();
+
+ //
+ // search every provider looking for the algorithm we want.
+ //
+ for (int i = 0; i != prov.length; i++)
+ {
+ //
+ // try case insensitive
+ //
+ Implementation imp = getImplementation(baseName, Strings.toUpperCase(algorithm), prov[i]);
+ if (imp != null)
+ {
+ return imp;
+ }
+
+ try
+ {
+ imp = getImplementation(baseName, algorithm, prov[i]);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ // continue
+ }
+ }
+
+ throw new NoSuchAlgorithmException("cannot find implementation " + algorithm);
+ }
+
+ static Provider getProvider(String provider)
+ throws NoSuchProviderException
+ {
+ Provider prov = Security.getProvider(provider);
+
+ if (prov == null)
+ {
+ throw new NoSuchProviderException("Provider " + provider + " not found");
+ }
+
+ return prov;
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java b/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
new file mode 100644
index 0000000..5703dc8
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509V1CertificateGenerator.java
@@ -0,0 +1,377 @@
+package org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+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.DERBitString;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.TBSCertificate;
+import org.bouncycastle.asn1.x509.Time;
+import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+
+/**
+ * class to produce an X.509 Version 1 certificate.
+ * @deprecated use org.bouncycastle.cert.X509v1CertificateBuilder.
+ */
+public class X509V1CertificateGenerator
+{
+ private V1TBSCertificateGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+
+ public X509V1CertificateGenerator()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V1TBSCertificateGenerator();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X500Principal issuer)
+ {
+ try
+ {
+ tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't process principal: " + e);
+ }
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X500Principal subject)
+ {
+ try
+ {
+ tbsGen.setSubject(new X509Principal(subject.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't process principal: " + e);
+ }
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(new SubjectPublicKeyInfo((ASN1Sequence)new ASN1InputStream(
+ new ByteArrayInputStream(key.getEncoded())).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested");
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "BC".
+ * @deprecated use generate(key, "BC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "BC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "BC" and the passed in source of randomness
+ * @deprecated use generate(key, random, "BC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "BC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "BC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider and the passed in source of randomness
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "BC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing, and the passed in source
+ * of randomness (if required).
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ return generateJcaObject(tbsCert, signature);
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateEncodingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ try
+ {
+ return new X509CertificateObject(new X509CertificateStructure(new DERSequence(v)));
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java b/bcprov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
new file mode 100644
index 0000000..14db8ea
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java
@@ -0,0 +1,350 @@
+package org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERBitString;
+import org.bouncycastle.asn1.x509.AttributeCertificate;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * An implementation of a version 2 X.509 Attribute Certificate.
+ * @deprecated use org.bouncycastle.cert.X509AttributeCertificateHolder
+ */
+public class X509V2AttributeCertificate
+ implements X509AttributeCertificate
+{
+ private AttributeCertificate cert;
+ private Date notBefore;
+ private Date notAfter;
+
+ private static AttributeCertificate getObject(InputStream in)
+ throws IOException
+ {
+ try
+ {
+ return AttributeCertificate.getInstance(new ASN1InputStream(in).readObject());
+ }
+ catch (IOException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception decoding certificate structure: " + e.toString());
+ }
+ }
+
+ public X509V2AttributeCertificate(
+ InputStream encIn)
+ throws IOException
+ {
+ this(getObject(encIn));
+ }
+
+ public X509V2AttributeCertificate(
+ byte[] encoded)
+ throws IOException
+ {
+ this(new ByteArrayInputStream(encoded));
+ }
+
+ X509V2AttributeCertificate(
+ AttributeCertificate cert)
+ throws IOException
+ {
+ this.cert = cert;
+
+ try
+ {
+ this.notAfter = cert.getAcinfo().getAttrCertValidityPeriod().getNotAfterTime().getDate();
+ this.notBefore = cert.getAcinfo().getAttrCertValidityPeriod().getNotBeforeTime().getDate();
+ }
+ catch (ParseException e)
+ {
+ throw new IOException("invalid data structure in certificate!");
+ }
+ }
+
+ public int getVersion()
+ {
+ return cert.getAcinfo().getVersion().getValue().intValue() + 1;
+ }
+
+ public BigInteger getSerialNumber()
+ {
+ return cert.getAcinfo().getSerialNumber().getValue();
+ }
+
+ public AttributeCertificateHolder getHolder()
+ {
+ return new AttributeCertificateHolder((ASN1Sequence)cert.getAcinfo().getHolder().toASN1Object());
+ }
+
+ public AttributeCertificateIssuer getIssuer()
+ {
+ return new AttributeCertificateIssuer(cert.getAcinfo().getIssuer());
+ }
+
+ public Date getNotBefore()
+ {
+ return notBefore;
+ }
+
+ public Date getNotAfter()
+ {
+ return notAfter;
+ }
+
+ public boolean[] getIssuerUniqueID()
+ {
+ DERBitString id = cert.getAcinfo().getIssuerUniqueID();
+
+ if (id != null)
+ {
+ byte[] bytes = id.getBytes();
+ boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()];
+
+ for (int i = 0; i != boolId.length; i++)
+ {
+ boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0;
+ }
+
+ return boolId;
+ }
+
+ return null;
+ }
+
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ this.checkValidity(new Date());
+ }
+
+ public void checkValidity(
+ Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException
+ {
+ if (date.after(this.getNotAfter()))
+ {
+ throw new CertificateExpiredException("certificate expired on " + this.getNotAfter());
+ }
+
+ if (date.before(this.getNotBefore()))
+ {
+ throw new CertificateNotYetValidException("certificate not valid till " + this.getNotBefore());
+ }
+ }
+
+ public byte[] getSignature()
+ {
+ return cert.getSignatureValue().getBytes();
+ }
+
+ public final void verify(
+ PublicKey key,
+ String provider)
+ throws CertificateException, NoSuchAlgorithmException,
+ InvalidKeyException, NoSuchProviderException, SignatureException
+ {
+ Signature signature = null;
+
+ if (!cert.getSignatureAlgorithm().equals(cert.getAcinfo().getSignature()))
+ {
+ throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
+ }
+
+ signature = Signature.getInstance(cert.getSignatureAlgorithm().getObjectId().getId(), provider);
+
+ signature.initVerify(key);
+
+ try
+ {
+ signature.update(cert.getAcinfo().getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new SignatureException("Exception encoding certificate info object");
+ }
+
+ if (!signature.verify(this.getSignature()))
+ {
+ throw new InvalidKeyException("Public key presented not for certificate signature");
+ }
+ }
+
+ public byte[] getEncoded()
+ throws IOException
+ {
+ return cert.getEncoded();
+ }
+
+ public byte[] getExtensionValue(String oid)
+ {
+ Extensions extensions = cert.getAcinfo().getExtensions();
+
+ if (extensions != null)
+ {
+ Extension ext = extensions.getExtension(new ASN1ObjectIdentifier(oid));
+
+ if (ext != null)
+ {
+ try
+ {
+ return ext.getExtnValue().getEncoded(ASN1Encoding.DER);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("error encoding " + e.toString());
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Set getExtensionOIDs(
+ boolean critical)
+ {
+ Extensions extensions = cert.getAcinfo().getExtensions();
+
+ if (extensions != null)
+ {
+ Set set = new HashSet();
+ Enumeration e = extensions.oids();
+
+ while (e.hasMoreElements())
+ {
+ ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
+ Extension ext = extensions.getExtension(oid);
+
+ if (ext.isCritical() == critical)
+ {
+ set.add(oid.getId());
+ }
+ }
+
+ return set;
+ }
+
+ return null;
+ }
+
+ public Set getNonCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(false);
+ }
+
+ public Set getCriticalExtensionOIDs()
+ {
+ return getExtensionOIDs(true);
+ }
+
+ public boolean hasUnsupportedCriticalExtension()
+ {
+ Set extensions = getCriticalExtensionOIDs();
+
+ return extensions != null && !extensions.isEmpty();
+ }
+
+ public X509Attribute[] getAttributes()
+ {
+ ASN1Sequence seq = cert.getAcinfo().getAttributes();
+ X509Attribute[] attrs = new X509Attribute[seq.size()];
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ attrs[i] = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
+ }
+
+ return attrs;
+ }
+
+ public X509Attribute[] getAttributes(String oid)
+ {
+ ASN1Sequence seq = cert.getAcinfo().getAttributes();
+ List list = new ArrayList();
+
+ for (int i = 0; i != seq.size(); i++)
+ {
+ X509Attribute attr = new X509Attribute((ASN1Encodable)seq.getObjectAt(i));
+ if (attr.getOID().equals(oid))
+ {
+ list.add(attr);
+ }
+ }
+
+ if (list.size() == 0)
+ {
+ return null;
+ }
+
+ return (X509Attribute[])list.toArray(new X509Attribute[list.size()]);
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == this)
+ {
+ return true;
+ }
+
+ if (!(o instanceof X509AttributeCertificate))
+ {
+ return false;
+ }
+
+ X509AttributeCertificate other = (X509AttributeCertificate)o;
+
+ try
+ {
+ byte[] b1 = this.getEncoded();
+ byte[] b2 = other.getEncoded();
+
+ return Arrays.areEqual(b1, b2);
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ }
+
+ public int hashCode()
+ {
+ try
+ {
+ return Arrays.hashCode(this.getEncoded());
+ }
+ catch (IOException e)
+ {
+ return 0;
+ }
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java b/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
new file mode 100644
index 0000000..870ba4f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/X509V3CertificateGenerator.java
@@ -0,0 +1,527 @@
+package org.bouncycastle.x509;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Iterator;
+
+import javax.security.auth.x500.X500Principal;
+
+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.DERBitString;
+import org.bouncycastle.asn1.DERObjectIdentifier;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x509.TBSCertificate;
+import org.bouncycastle.asn1.x509.Time;
+import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
+import org.bouncycastle.asn1.x509.X509CertificateStructure;
+import org.bouncycastle.asn1.x509.X509ExtensionsGenerator;
+import org.bouncycastle.asn1.x509.X509Name;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.provider.X509CertificateObject;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * class to produce an X.509 Version 3 certificate.
+ * @deprecated use org.bouncycastle.cert.X509v3CertificateBuilder.
+ */
+public class X509V3CertificateGenerator
+{
+ private V3TBSCertificateGenerator tbsGen;
+ private DERObjectIdentifier sigOID;
+ private AlgorithmIdentifier sigAlgId;
+ private String signatureAlgorithm;
+ private X509ExtensionsGenerator extGenerator;
+
+ public X509V3CertificateGenerator()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator = new X509ExtensionsGenerator();
+ }
+
+ /**
+ * reset the generator
+ */
+ public void reset()
+ {
+ tbsGen = new V3TBSCertificateGenerator();
+ extGenerator.reset();
+ }
+
+ /**
+ * set the serial number for the certificate.
+ */
+ public void setSerialNumber(
+ BigInteger serialNumber)
+ {
+ if (serialNumber.compareTo(BigInteger.ZERO) <= 0)
+ {
+ throw new IllegalArgumentException("serial number must be a positive integer");
+ }
+
+ tbsGen.setSerialNumber(new ASN1Integer(serialNumber));
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X500Principal issuer)
+ {
+ try
+ {
+ tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't process principal: " + e);
+ }
+ }
+
+ /**
+ * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+ * certificate.
+ */
+ public void setIssuerDN(
+ X509Name issuer)
+ {
+ tbsGen.setIssuer(issuer);
+ }
+
+ public void setNotBefore(
+ Date date)
+ {
+ tbsGen.setStartDate(new Time(date));
+ }
+
+ public void setNotAfter(
+ Date date)
+ {
+ tbsGen.setEndDate(new Time(date));
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X500Principal subject)
+ {
+ try
+ {
+ tbsGen.setSubject(new X509Principal(subject.getEncoded()));
+ }
+ catch (IOException e)
+ {
+ throw new IllegalArgumentException("can't process principal: " + e);
+ }
+ }
+
+ /**
+ * Set the subject distinguished name. The subject describes the entity associated with the public key.
+ */
+ public void setSubjectDN(
+ X509Name subject)
+ {
+ tbsGen.setSubject(subject);
+ }
+
+ public void setPublicKey(
+ PublicKey key)
+ throws IllegalArgumentException
+ {
+ try
+ {
+ tbsGen.setSubjectPublicKeyInfo(
+ SubjectPublicKeyInfo.getInstance(new ASN1InputStream(key.getEncoded()).readObject()));
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("unable to process key - " + e.toString());
+ }
+ }
+
+ /**
+ * Set the signature algorithm. This can be either a name or an OID, names
+ * are treated as case insensitive.
+ *
+ * @param signatureAlgorithm string representation of the algorithm name.
+ */
+ public void setSignatureAlgorithm(
+ String signatureAlgorithm)
+ {
+ this.signatureAlgorithm = signatureAlgorithm;
+
+ try
+ {
+ sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalArgumentException("Unknown signature type requested: " + signatureAlgorithm);
+ }
+
+ sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
+
+ tbsGen.setSignature(sigAlgId);
+ }
+
+ /**
+ * Set the subject unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setSubjectUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setSubjectUniqueID(booleanToBitString(uniqueID));
+ }
+
+ /**
+ * Set the issuer unique ID - note: it is very rare that it is correct to do this.
+ */
+ public void setIssuerUniqueID(boolean[] uniqueID)
+ {
+ tbsGen.setIssuerUniqueID(booleanToBitString(uniqueID));
+ }
+
+ private DERBitString booleanToBitString(boolean[] id)
+ {
+ byte[] bytes = new byte[(id.length + 7) / 8];
+
+ for (int i = 0; i != id.length; i++)
+ {
+ bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0;
+ }
+
+ int pad = id.length % 8;
+
+ if (pad == 0)
+ {
+ return new DERBitString(bytes);
+ }
+ else
+ {
+ return new DERBitString(bytes, 8 - pad);
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ ASN1Encodable value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * The value parameter becomes the contents of the octet string associated
+ * with the extension.
+ */
+ public void addExtension(
+ String oid,
+ boolean critical,
+ byte[] value)
+ {
+ this.addExtension(new DERObjectIdentifier(oid), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ */
+ public void addExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ byte[] value)
+ {
+ extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value);
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ String oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ byte[] extValue = cert.getExtensionValue(oid);
+
+ if (extValue == null)
+ {
+ throw new CertificateParsingException("extension " + oid + " not present");
+ }
+
+ try
+ {
+ ASN1Encodable value = X509ExtensionUtil.fromExtensionValue(extValue);
+
+ this.addExtension(oid, critical, value);
+ }
+ catch (IOException e)
+ {
+ throw new CertificateParsingException(e.toString());
+ }
+ }
+
+ /**
+ * add a given extension field for the standard extensions tag (tag 3)
+ * copying the extension value from another certificate.
+ * @throws CertificateParsingException if the extension cannot be extracted.
+ */
+ public void copyAndAddExtension(
+ DERObjectIdentifier oid,
+ boolean critical,
+ X509Certificate cert)
+ throws CertificateParsingException
+ {
+ this.copyAndAddExtension(oid.getId(), critical, cert);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "BC".
+ * @deprecated use generate(key, "BC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "BC", null);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider "BC", and the passed in source of randomness
+ * (if required).
+ * @deprecated use generate(key, random, "BC")
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ SecureRandom random)
+ throws SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generateX509Certificate(key, "BC", random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new SecurityException("BC provider not installed!");
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ return generateX509Certificate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ * @deprecated use generate()
+ */
+ public X509Certificate generateX509Certificate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
+ {
+ try
+ {
+ return generate(key, provider, random);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw e;
+ }
+ catch (SignatureException e)
+ {
+ throw e;
+ }
+ catch (InvalidKeyException e)
+ {
+ throw e;
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new SecurityException("exception: " + e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider.
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "BC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, (SecureRandom)null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject
+ * using the default provider, and the passed in source of randomness
+ * (if required).
+ * <p>
+ * <b>Note:</b> this differs from the deprecated method in that the default provider is
+ * used - not "BC".
+ * </p>
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ return generate(key, provider, null);
+ }
+
+ /**
+ * generate an X509 certificate, based on the current issuer and subject,
+ * using the passed in provider for the signing and the supplied source
+ * of randomness, if required.
+ */
+ public X509Certificate generate(
+ PrivateKey key,
+ String provider,
+ SecureRandom random)
+ throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
+ {
+ TBSCertificate tbsCert = generateTbsCert();
+ byte[] signature;
+
+ try
+ {
+ signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
+ }
+
+ try
+ {
+ return generateJcaObject(tbsCert, signature);
+ }
+ catch (CertificateParsingException e)
+ {
+ throw new ExtCertificateEncodingException("exception producing certificate object", e);
+ }
+ }
+
+ private TBSCertificate generateTbsCert()
+ {
+ if (!extGenerator.isEmpty())
+ {
+ tbsGen.setExtensions(extGenerator.generate());
+ }
+
+ return tbsGen.generateTBSCertificate();
+ }
+
+ private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
+ throws CertificateParsingException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(tbsCert);
+ v.add(sigAlgId);
+ v.add(new DERBitString(signature));
+
+ return new X509CertificateObject(new X509CertificateStructure(new DERSequence(v)));
+ }
+
+ /**
+ * Return an iterator of the signature names supported by the generator.
+ *
+ * @return an iterator containing recognised names.
+ */
+ public Iterator getSignatureAlgNames()
+ {
+ return X509Util.getAlgNames();
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java b/bcprov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java
new file mode 100644
index 0000000..2164d1f
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java
@@ -0,0 +1,152 @@
+package org.bouncycastle.x509.extension;
+
+import java.io.IOException;
+import java.security.InvalidKeyException;
+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;
+import org.bouncycastle.asn1.x509.Extension;
+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;
+
+/**
+ * A high level authority key identifier.
+ * @deprecated use JcaX509ExtensionUtils and AuthorityKeyIdentifier.getInstance()
+ */
+public class AuthorityKeyIdentifierStructure
+ extends AuthorityKeyIdentifier
+{
+ /**
+ * 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 AuthorityKeyIdentifierStructure(
+ byte[] encodedValue)
+ throws IOException
+ {
+ super((ASN1Sequence)X509ExtensionUtil.fromExtensionValue(encodedValue));
+ }
+
+ /**
+ * Constructor which will take an extension
+ *
+ * @param extension a X509Extension object containing an AuthorityKeyIdentifier.
+ * @deprecated use constructor that takes Extension
+ */
+ public AuthorityKeyIdentifierStructure(
+ X509Extension extension)
+ {
+ super((ASN1Sequence)extension.getParsedValue());
+ }
+
+ /**
+ * Constructor which will take an extension
+ *
+ * @param extension a X509Extension object containing an AuthorityKeyIdentifier.
+ */
+ public AuthorityKeyIdentifierStructure(
+ Extension extension)
+ {
+ super((ASN1Sequence)extension.getParsedValue());
+ }
+
+ private static ASN1Sequence fromCertificate(
+ X509Certificate certificate)
+ throws CertificateParsingException
+ {
+ try
+ {
+ if (certificate.getVersion() != 3)
+ {
+ GeneralName genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate));
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)new ASN1InputStream(certificate.getPublicKey().getEncoded()).readObject());
+
+ return (ASN1Sequence)new AuthorityKeyIdentifier(
+ info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object();
+ }
+ else
+ {
+ GeneralName genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate));
+
+ byte[] ext = certificate.getExtensionValue(X509Extensions.SubjectKeyIdentifier.getId());
+
+ if (ext != null)
+ {
+ ASN1OctetString str = (ASN1OctetString)X509ExtensionUtil.fromExtensionValue(ext);
+
+ return (ASN1Sequence)new AuthorityKeyIdentifier(
+ str.getOctets(), new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object();
+ }
+ else
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)new ASN1InputStream(certificate.getPublicKey().getEncoded()).readObject());
+
+ return (ASN1Sequence)new AuthorityKeyIdentifier(
+ info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Object();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException("Exception extracting certificate details: " + e.toString());
+ }
+ }
+
+ private static ASN1Sequence fromKey(
+ PublicKey pubKey)
+ throws InvalidKeyException
+ {
+ try
+ {
+ SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+ (ASN1Sequence)new ASN1InputStream(pubKey.getEncoded()).readObject());
+
+ return (ASN1Sequence)new AuthorityKeyIdentifier(info).toASN1Object();
+ }
+ catch (Exception e)
+ {
+ throw new InvalidKeyException("can't process key: " + e);
+ }
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using the passed in certificate's public
+ * key, issuer and serial number.
+ *
+ * @param certificate the certificate providing the information.
+ * @throws CertificateParsingException if there is a problem processing the certificate
+ */
+ public AuthorityKeyIdentifierStructure(
+ X509Certificate certificate)
+ throws CertificateParsingException
+ {
+ super(fromCertificate(certificate));
+ }
+
+ /**
+ * Create an AuthorityKeyIdentifier using just the hash of the
+ * public key.
+ *
+ * @param pubKey the key to generate the hash from.
+ * @throws InvalidKeyException if there is a problem using the key.
+ */
+ public AuthorityKeyIdentifierStructure(
+ PublicKey pubKey)
+ throws InvalidKeyException
+ {
+ super(fromKey(pubKey));
+ }
+}
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java b/bcprov/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java
new file mode 100644
index 0000000..2c7afd3
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/extension/SubjectKeyIdentifierStructure.java
@@ -0,0 +1,53 @@
+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/bcprov/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java b/bcprov/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
new file mode 100644
index 0000000..048f31b
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/extension/X509ExtensionUtil.java
@@ -0,0 +1,102 @@
+package org.bouncycastle.x509.extension;
+
+import java.io.IOException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1String;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.X509Extension;
+
+
+public class X509ExtensionUtil
+{
+ public static ASN1Primitive fromExtensionValue(
+ byte[] encodedValue)
+ throws IOException
+ {
+ ASN1OctetString octs = (ASN1OctetString)ASN1Primitive.fromByteArray(encodedValue);
+
+ return ASN1Primitive.fromByteArray(octs.getOctets());
+ }
+
+ public static Collection getIssuerAlternativeNames(X509Certificate cert)
+ throws CertificateParsingException
+ {
+ byte[] extVal = cert.getExtensionValue(X509Extension.issuerAlternativeName.getId());
+
+ return getAlternativeNames(extVal);
+ }
+
+ public static Collection getSubjectAlternativeNames(X509Certificate cert)
+ throws CertificateParsingException
+ {
+ byte[] extVal = cert.getExtensionValue(X509Extension.subjectAlternativeName.getId());
+
+ return getAlternativeNames(extVal);
+ }
+
+ private static Collection getAlternativeNames(byte[] extVal)
+ throws CertificateParsingException
+ {
+ if (extVal == null)
+ {
+ return Collections.EMPTY_LIST;
+ }
+ try
+ {
+ Collection temp = new ArrayList();
+ Enumeration it = DERSequence.getInstance(fromExtensionValue(extVal)).getObjects();
+ while (it.hasMoreElements())
+ {
+ GeneralName genName = GeneralName.getInstance(it.nextElement());
+ List list = new ArrayList();
+ // BEGIN android-changed
+ list.add(Integer.valueOf(genName.getTagNo()));
+ // END android-changed
+ switch (genName.getTagNo())
+ {
+ case GeneralName.ediPartyName:
+ case GeneralName.x400Address:
+ case GeneralName.otherName:
+ list.add(genName.getName().toASN1Primitive());
+ break;
+ case GeneralName.directoryName:
+ list.add(X500Name.getInstance(genName.getName()).toString());
+ break;
+ case GeneralName.dNSName:
+ case GeneralName.rfc822Name:
+ case GeneralName.uniformResourceIdentifier:
+ list.add(((ASN1String)genName.getName()).getString());
+ break;
+ case GeneralName.registeredID:
+ list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId());
+ break;
+ case GeneralName.iPAddress:
+ list.add(DEROctetString.getInstance(genName.getName()).getOctets());
+ break;
+ default:
+ throw new IOException("Bad tag number: " + genName.getTagNo());
+ }
+
+ temp.add(list);
+ }
+ return Collections.unmodifiableCollection(temp);
+ }
+ catch (Exception e)
+ {
+ throw new CertificateParsingException(e.getMessage());
+ }
+ }
+}